mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Support rotation in MeshFilter (#3176)
Co-authored-by: Jonathan Shimwell <drshimwell@gmail.com> Co-authored-by: Patrick Shriwise <pshriwise@gmail.com>
This commit is contained in:
parent
a230b86128
commit
a2fd6cc57e
12 changed files with 594 additions and 2 deletions
|
|
@ -51,6 +51,12 @@ public:
|
|||
|
||||
virtual bool translated() const { return translated_; }
|
||||
|
||||
virtual void set_rotation(const vector<double>& rotation);
|
||||
|
||||
virtual const vector<double>& rotation() const { return rotation_; }
|
||||
|
||||
virtual bool rotated() const { return rotated_; }
|
||||
|
||||
protected:
|
||||
//----------------------------------------------------------------------------
|
||||
// Data members
|
||||
|
|
@ -58,6 +64,8 @@ protected:
|
|||
int32_t mesh_; //!< Index of the mesh
|
||||
bool translated_ {false}; //!< Whether or not the filter is translated
|
||||
Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation
|
||||
bool rotated_ {false}; //!< Whether or not the filter is rotated
|
||||
vector<double> rotation_; //!< Filter rotation
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -833,6 +833,25 @@ class MeshFilter(Filter):
|
|||
translation : Iterable of float
|
||||
This array specifies a vector that is used to translate (shift) the mesh
|
||||
for this filter
|
||||
rotation : Iterable of float
|
||||
This array specifies the angles in degrees about the x, y, and z axes
|
||||
that the mesh should be rotated. The rotation applied is an intrinsic
|
||||
rotation with specified Tait-Bryan angles. That is to say, if the angles
|
||||
are :math:`(\phi, \theta, \psi)`, then the rotation matrix applied is
|
||||
:math:`R_z(\psi) R_y(\theta) R_x(\phi)` or
|
||||
|
||||
.. math::
|
||||
|
||||
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi
|
||||
+ \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi
|
||||
\sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi +
|
||||
\sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi
|
||||
\sin\theta \sin\psi \\ -\sin\theta & \sin\phi \cos\theta & \cos\phi
|
||||
\cos\theta \end{array} \right ]
|
||||
|
||||
A rotation matrix can also be specified directly by setting this
|
||||
attribute to a nested list (or 2D numpy array) that specifies each
|
||||
element of the matrix.
|
||||
bins : list of tuple
|
||||
A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1),
|
||||
...]
|
||||
|
|
@ -845,6 +864,7 @@ class MeshFilter(Filter):
|
|||
self.mesh = mesh
|
||||
self.id = filter_id
|
||||
self._translation = None
|
||||
self._rotation = None
|
||||
|
||||
def __hash__(self):
|
||||
string = type(self).__name__ + '\n'
|
||||
|
|
@ -856,6 +876,7 @@ class MeshFilter(Filter):
|
|||
string += '{: <16}=\t{}\n'.format('\tMesh ID', self.mesh.id)
|
||||
string += '{: <16}=\t{}\n'.format('\tID', self.id)
|
||||
string += '{: <16}=\t{}\n'.format('\tTranslation', self.translation)
|
||||
string += '{: <16}=\t{}\n'.format('\tRotation', self.rotation)
|
||||
return string
|
||||
|
||||
@classmethod
|
||||
|
|
@ -879,6 +900,10 @@ class MeshFilter(Filter):
|
|||
if translation:
|
||||
out.translation = translation[()]
|
||||
|
||||
rotation = group.get('rotation')
|
||||
if rotation:
|
||||
out.rotation = rotation[()]
|
||||
|
||||
return out
|
||||
|
||||
@property
|
||||
|
|
@ -911,6 +936,15 @@ class MeshFilter(Filter):
|
|||
cv.check_length('mesh filter translation', t, 3)
|
||||
self._translation = np.asarray(t)
|
||||
|
||||
@property
|
||||
def rotation(self):
|
||||
return self._rotation
|
||||
|
||||
@rotation.setter
|
||||
def rotation(self, rotation):
|
||||
cv.check_length('mesh filter rotation', rotation, 3)
|
||||
self._rotation = np.asarray(rotation)
|
||||
|
||||
def can_merge(self, other):
|
||||
# Mesh filters cannot have more than one bin
|
||||
return False
|
||||
|
|
@ -996,6 +1030,8 @@ class MeshFilter(Filter):
|
|||
subelement.text = str(self.mesh.id)
|
||||
if self.translation is not None:
|
||||
element.set('translation', ' '.join(map(str, self.translation)))
|
||||
if self.rotation is not None:
|
||||
element.set('rotation', ' '.join(map(str, self.rotation.ravel())))
|
||||
return element
|
||||
|
||||
@classmethod
|
||||
|
|
@ -1008,6 +1044,13 @@ class MeshFilter(Filter):
|
|||
translation = get_elem_list(elem, "translation", float) or []
|
||||
if translation:
|
||||
out.translation = translation
|
||||
|
||||
rotation = get_elem_list(elem, 'rotation', float) or []
|
||||
if rotation:
|
||||
if len(rotation) == 3:
|
||||
out.rotation = rotation
|
||||
elif len(rotation) == 9:
|
||||
out.rotation = np.array(rotation).reshape(3, 3)
|
||||
return out
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,14 @@ _dll.openmc_mesh_filter_get_translation.errcheck = _error_handler
|
|||
_dll.openmc_mesh_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)]
|
||||
_dll.openmc_mesh_filter_set_translation.restype = c_int
|
||||
_dll.openmc_mesh_filter_set_translation.errcheck = _error_handler
|
||||
_dll.openmc_mesh_filter_get_rotation.argtypes = [c_int32, POINTER(c_double),
|
||||
POINTER(c_size_t)]
|
||||
_dll.openmc_mesh_filter_get_rotation.restype = c_int
|
||||
_dll.openmc_mesh_filter_get_rotation.errcheck = _error_handler
|
||||
_dll.openmc_mesh_filter_set_rotation.argtypes = [
|
||||
c_int32, POINTER(c_double), c_size_t]
|
||||
_dll.openmc_mesh_filter_set_rotation.restype = c_int
|
||||
_dll.openmc_mesh_filter_set_rotation.errcheck = _error_handler
|
||||
_dll.openmc_meshborn_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_meshborn_filter_get_mesh.restype = c_int
|
||||
_dll.openmc_meshborn_filter_get_mesh.errcheck = _error_handler
|
||||
|
|
@ -393,6 +401,10 @@ class MeshFilter(Filter):
|
|||
Mesh used for the filter
|
||||
translation : Iterable of float
|
||||
3-D coordinates of the translation vector
|
||||
rotation : Iterable of float
|
||||
The rotation matrix or angles of the filter mesh. This can either be
|
||||
a fully specified 3 x 3 rotation matrix or an Iterable of length 3
|
||||
with the angles in degrees about the x, y, and z axes, respectively.
|
||||
|
||||
"""
|
||||
filter_type = 'mesh'
|
||||
|
|
@ -422,6 +434,34 @@ class MeshFilter(Filter):
|
|||
def translation(self, translation):
|
||||
_dll.openmc_mesh_filter_set_translation(self._index, (c_double*3)(*translation))
|
||||
|
||||
@property
|
||||
def rotation(self):
|
||||
rotation_data = np.zeros(12)
|
||||
rot_size = c_size_t()
|
||||
|
||||
_dll.openmc_mesh_filter_get_rotation(
|
||||
self._index, rotation_data.ctypes.data_as(POINTER(c_double)),
|
||||
rot_size)
|
||||
rot_size = rot_size.value
|
||||
|
||||
if rot_size == 9:
|
||||
return rotation_data[:rot_size].shape(3, 3)
|
||||
elif rot_size in (0, 12):
|
||||
# If size is 0, rotation_data[9:] will be zeros. This indicates no
|
||||
# rotation and is the most straightforward way to always return
|
||||
# an iterable of floats
|
||||
return rotation_data[9:]
|
||||
else:
|
||||
raise ValueError(
|
||||
f'Invalid size of rotation matrix: {rot_size}')
|
||||
|
||||
@rotation.setter
|
||||
def rotation(self, rotation_data):
|
||||
flat_rotation = np.asarray(rotation_data, dtype=float).flatten()
|
||||
|
||||
_dll.openmc_mesh_filter_set_rotation(
|
||||
self._index, flat_rotation.ctypes.data_as(POINTER(c_double)),
|
||||
c_size_t(len(flat_rotation)))
|
||||
|
||||
class MeshBornFilter(Filter):
|
||||
"""MeshBorn filter stored internally.
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ void Cell::set_rotation(const vector<double>& rot)
|
|||
fatal_error(fmt::format("Non-3D rotation vector applied to cell {}", id_));
|
||||
}
|
||||
|
||||
// Compute and store the rotation matrix.
|
||||
// Compute and store the inverse rotation matrix for the angles given.
|
||||
rotation_.clear();
|
||||
rotation_.reserve(rot.size() == 9 ? 9 : 12);
|
||||
if (rot.size() == 3) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "openmc/constants.h"
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/mesh.h"
|
||||
#include "openmc/position.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -30,6 +31,10 @@ void MeshFilter::from_xml(pugi::xml_node node)
|
|||
if (check_for_node(node, "translation")) {
|
||||
set_translation(get_node_array<double>(node, "translation"));
|
||||
}
|
||||
// Read the rotation transform.
|
||||
if (check_for_node(node, "rotation")) {
|
||||
set_rotation(get_node_array<double>(node, "rotation"));
|
||||
}
|
||||
}
|
||||
|
||||
void MeshFilter::get_all_bins(
|
||||
|
|
@ -45,6 +50,12 @@ void MeshFilter::get_all_bins(
|
|||
last_r -= translation();
|
||||
r -= translation();
|
||||
}
|
||||
// apply rotation if present
|
||||
if (!rotation_.empty()) {
|
||||
last_r = last_r.rotate(rotation_);
|
||||
r = r.rotate(rotation_);
|
||||
u = u.rotate(rotation_);
|
||||
}
|
||||
|
||||
if (estimator != TallyEstimator::TRACKLENGTH) {
|
||||
auto bin = model::meshes[mesh_]->get_bin(r);
|
||||
|
|
@ -65,6 +76,9 @@ void MeshFilter::to_statepoint(hid_t filter_group) const
|
|||
if (translated_) {
|
||||
write_dataset(filter_group, "translation", translation_);
|
||||
}
|
||||
if (rotated_) {
|
||||
write_dataset(filter_group, "rotation", rotation_);
|
||||
}
|
||||
}
|
||||
|
||||
std::string MeshFilter::text_label(int bin) const
|
||||
|
|
@ -93,6 +107,40 @@ void MeshFilter::set_translation(const double translation[3])
|
|||
this->set_translation({translation[0], translation[1], translation[2]});
|
||||
}
|
||||
|
||||
void MeshFilter::set_rotation(const vector<double>& rot)
|
||||
{
|
||||
rotated_ = true;
|
||||
|
||||
// Compute and store the inverse rotation matrix for the angles given.
|
||||
rotation_.clear();
|
||||
rotation_.reserve(rot.size() == 9 ? 9 : 12);
|
||||
if (rot.size() == 3) {
|
||||
double phi = -rot[0] * PI / 180.0;
|
||||
double theta = -rot[1] * PI / 180.0;
|
||||
double psi = -rot[2] * PI / 180.0;
|
||||
rotation_.push_back(std::cos(theta) * std::cos(psi));
|
||||
rotation_.push_back(-std::cos(phi) * std::sin(psi) +
|
||||
std::sin(phi) * std::sin(theta) * std::cos(psi));
|
||||
rotation_.push_back(std::sin(phi) * std::sin(psi) +
|
||||
std::cos(phi) * std::sin(theta) * std::cos(psi));
|
||||
rotation_.push_back(std::cos(theta) * std::sin(psi));
|
||||
rotation_.push_back(std::cos(phi) * std::cos(psi) +
|
||||
std::sin(phi) * std::sin(theta) * std::sin(psi));
|
||||
rotation_.push_back(-std::sin(phi) * std::cos(psi) +
|
||||
std::cos(phi) * std::sin(theta) * std::sin(psi));
|
||||
rotation_.push_back(-std::sin(theta));
|
||||
rotation_.push_back(std::sin(phi) * std::cos(theta));
|
||||
rotation_.push_back(std::cos(phi) * std::cos(theta));
|
||||
|
||||
// When user specifies angles, write them at end of vector
|
||||
rotation_.push_back(rot[0]);
|
||||
rotation_.push_back(rot[1]);
|
||||
rotation_.push_back(rot[2]);
|
||||
} else {
|
||||
std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// C-API functions
|
||||
//==============================================================================
|
||||
|
|
@ -201,4 +249,48 @@ extern "C" int openmc_mesh_filter_set_translation(
|
|||
return 0;
|
||||
}
|
||||
|
||||
//! Return the rotation matrix of a mesh filter
|
||||
extern "C" int openmc_mesh_filter_get_rotation(
|
||||
int32_t index, double rot[], size_t* n)
|
||||
{
|
||||
// Make sure this is a valid index to an allocated filter
|
||||
if (int err = verify_filter(index))
|
||||
return err;
|
||||
|
||||
// Check the filter type
|
||||
const auto& filter = model::tally_filters[index];
|
||||
if (filter->type() != FilterType::MESH) {
|
||||
set_errmsg("Tried to get a rotation from a non-mesh filter.");
|
||||
return OPENMC_E_INVALID_TYPE;
|
||||
}
|
||||
// Get rotation from the mesh filter and set value
|
||||
auto mesh_filter = dynamic_cast<MeshFilter*>(filter.get());
|
||||
*n = mesh_filter->rotation().size();
|
||||
std::memcpy(rot, mesh_filter->rotation().data(),
|
||||
*n * sizeof(mesh_filter->rotation()[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Set the flattened rotation matrix of a mesh filter
|
||||
extern "C" int openmc_mesh_filter_set_rotation(
|
||||
int32_t index, const double rot[], size_t rot_len)
|
||||
{
|
||||
// Make sure this is a valid index to an allocated filter
|
||||
if (int err = verify_filter(index))
|
||||
return err;
|
||||
|
||||
const auto& filter = model::tally_filters[index];
|
||||
// Check the filter type
|
||||
if (filter->type() != FilterType::MESH) {
|
||||
set_errmsg("Tried to set a rotation from a non-mesh filter.");
|
||||
return OPENMC_E_INVALID_TYPE;
|
||||
}
|
||||
|
||||
// Get a pointer to the filter and downcast
|
||||
auto mesh_filter = dynamic_cast<MeshFilter*>(filter.get());
|
||||
std::vector<double> vec_rot(rot, rot + rot_len);
|
||||
mesh_filter->set_rotation(vec_rot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -933,7 +933,8 @@ void WeightWindowsGenerator::create_tally()
|
|||
for (const auto& f : model::tally_filters) {
|
||||
if (f->type() == FilterType::MESH) {
|
||||
const auto* mesh_filter = dynamic_cast<MeshFilter*>(f.get());
|
||||
if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) {
|
||||
if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated() &&
|
||||
!mesh_filter->rotated()) {
|
||||
ww_tally->add_filter(f.get());
|
||||
found_mesh_filter = true;
|
||||
break;
|
||||
|
|
|
|||
0
tests/regression_tests/filter_rotations/__init__.py
Normal file
0
tests/regression_tests/filter_rotations/__init__.py
Normal file
59
tests/regression_tests/filter_rotations/inputs_true.dat
Normal file
59
tests/regression_tests/filter_rotations/inputs_true.dat
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<model>
|
||||
<materials>
|
||||
<material id="1" depletable="true">
|
||||
<density value="10.0" units="g/cm3"/>
|
||||
<nuclide name="U235" ao="1.0"/>
|
||||
</material>
|
||||
<material id="2">
|
||||
<density value="1.0" units="g/cm3"/>
|
||||
<nuclide name="Zr90" ao="1.0"/>
|
||||
</material>
|
||||
</materials>
|
||||
<geometry>
|
||||
<cell id="1" material="1" region="1 -2 3 -4 10 -9" universe="1"/>
|
||||
<cell id="2" material="2" region="(-1 | 2 | -3 | 4) (5 -6 7 -8) 10 -9" universe="1"/>
|
||||
<surface id="1" name="minimum x" type="x-plane" coeffs="-5.0"/>
|
||||
<surface id="2" name="maximum x" type="x-plane" coeffs="5.0"/>
|
||||
<surface id="3" name="minimum y" type="y-plane" coeffs="-5.0"/>
|
||||
<surface id="4" name="maximum y" type="y-plane" coeffs="5.0"/>
|
||||
<surface id="5" name="minimum x" type="x-plane" boundary="reflective" coeffs="-10.0"/>
|
||||
<surface id="6" name="maximum x" type="x-plane" boundary="reflective" coeffs="10.0"/>
|
||||
<surface id="7" name="minimum y" type="y-plane" boundary="reflective" coeffs="-10.0"/>
|
||||
<surface id="8" name="maximum y" type="y-plane" boundary="reflective" coeffs="10.0"/>
|
||||
<surface id="9" type="z-plane" boundary="vacuum" coeffs="10.0"/>
|
||||
<surface id="10" type="z-plane" boundary="vacuum" coeffs="-10.0"/>
|
||||
</geometry>
|
||||
<settings>
|
||||
<run_mode>eigenvalue</run_mode>
|
||||
<particles>1000</particles>
|
||||
<batches>5</batches>
|
||||
<inactive>0</inactive>
|
||||
</settings>
|
||||
<tallies>
|
||||
<mesh id="1">
|
||||
<dimension>3 4 5</dimension>
|
||||
<lower_left>-9 -9 -9</lower_left>
|
||||
<upper_right>9 9 9</upper_right>
|
||||
</mesh>
|
||||
<mesh id="2">
|
||||
<dimension>3 4 5</dimension>
|
||||
<lower_left>-9 -9 -9</lower_left>
|
||||
<upper_right>9 9 9</upper_right>
|
||||
</mesh>
|
||||
<filter id="1" type="mesh">
|
||||
<bins>1</bins>
|
||||
</filter>
|
||||
<filter id="2" type="mesh" rotation="0 0 10">
|
||||
<bins>2</bins>
|
||||
</filter>
|
||||
<tally id="1">
|
||||
<filters>1</filters>
|
||||
<scores>total</scores>
|
||||
</tally>
|
||||
<tally id="2">
|
||||
<filters>2</filters>
|
||||
<scores>total</scores>
|
||||
</tally>
|
||||
</tallies>
|
||||
</model>
|
||||
244
tests/regression_tests/filter_rotations/results_true.dat
Normal file
244
tests/regression_tests/filter_rotations/results_true.dat
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
k-combined:
|
||||
7.729082E-01 3.775399E-02
|
||||
tally 1:
|
||||
5.296804E-02
|
||||
5.661701E-04
|
||||
8.356446E-02
|
||||
1.412139E-03
|
||||
5.041335E-02
|
||||
5.143568E-04
|
||||
1.299348E-01
|
||||
3.467618E-03
|
||||
3.929702E-01
|
||||
3.147038E-02
|
||||
1.379707E-01
|
||||
3.888484E-03
|
||||
1.405034E-01
|
||||
4.473799E-03
|
||||
3.785796E-01
|
||||
2.940585E-02
|
||||
1.422010E-01
|
||||
4.113723E-03
|
||||
5.647073E-02
|
||||
6.735251E-04
|
||||
7.911154E-02
|
||||
1.329137E-03
|
||||
5.160755E-02
|
||||
5.361448E-04
|
||||
6.669424E-02
|
||||
9.090832E-04
|
||||
1.008621E-01
|
||||
2.134534E-03
|
||||
6.808932E-02
|
||||
9.355993E-04
|
||||
1.873006E-01
|
||||
7.135961E-03
|
||||
6.221575E-01
|
||||
7.819842E-02
|
||||
1.856653E-01
|
||||
6.954762E-03
|
||||
2.014929E-01
|
||||
8.327845E-03
|
||||
5.853251E-01
|
||||
6.945708E-02
|
||||
1.709645E-01
|
||||
5.917124E-03
|
||||
7.214913E-02
|
||||
1.058962E-03
|
||||
1.027720E-01
|
||||
2.138475E-03
|
||||
6.099853E-02
|
||||
7.493941E-04
|
||||
6.892071E-02
|
||||
9.630680E-04
|
||||
1.035459E-01
|
||||
2.173883E-03
|
||||
6.973870E-02
|
||||
9.904237E-04
|
||||
2.125703E-01
|
||||
9.112659E-03
|
||||
9.012205E-01
|
||||
2.163546E-01
|
||||
2.066426E-01
|
||||
8.617414E-03
|
||||
2.258950E-01
|
||||
1.039607E-02
|
||||
9.476792E-01
|
||||
2.350708E-01
|
||||
2.225585E-01
|
||||
1.017898E-02
|
||||
7.111503E-02
|
||||
1.036847E-03
|
||||
1.117012E-01
|
||||
2.530040E-03
|
||||
6.870474E-02
|
||||
9.551035E-04
|
||||
5.738897E-02
|
||||
6.699030E-04
|
||||
9.522335E-02
|
||||
1.835769E-03
|
||||
6.570917E-02
|
||||
8.656870E-04
|
||||
1.945592E-01
|
||||
7.593336E-03
|
||||
5.514753E-01
|
||||
6.122981E-02
|
||||
2.144202E-01
|
||||
9.421739E-03
|
||||
1.971631E-01
|
||||
7.944046E-03
|
||||
6.088996E-01
|
||||
7.442954E-02
|
||||
1.965447E-01
|
||||
7.765628E-03
|
||||
7.005494E-02
|
||||
1.012891E-03
|
||||
1.010633E-01
|
||||
2.084095E-03
|
||||
6.145926E-02
|
||||
7.694351E-04
|
||||
4.999479E-02
|
||||
5.129164E-04
|
||||
7.238243E-02
|
||||
1.062921E-03
|
||||
4.902309E-02
|
||||
4.852193E-04
|
||||
1.324655E-01
|
||||
3.642431E-03
|
||||
3.305312E-01
|
||||
2.265726E-02
|
||||
1.332993E-01
|
||||
3.728385E-03
|
||||
1.547469E-01
|
||||
4.894837E-03
|
||||
3.625944E-01
|
||||
2.747313E-02
|
||||
1.435761E-01
|
||||
4.334405E-03
|
||||
5.789603E-02
|
||||
7.065383E-04
|
||||
7.589559E-02
|
||||
1.205386E-03
|
||||
5.210018E-02
|
||||
5.790843E-04
|
||||
tally 2:
|
||||
4.597932E-02
|
||||
4.246849E-04
|
||||
8.494738E-02
|
||||
1.467238E-03
|
||||
5.155072E-02
|
||||
5.373129E-04
|
||||
1.479395E-01
|
||||
4.468164E-03
|
||||
3.931843E-01
|
||||
3.141943E-02
|
||||
1.264081E-01
|
||||
3.243689E-03
|
||||
1.229742E-01
|
||||
3.276501E-03
|
||||
3.768427E-01
|
||||
2.927971E-02
|
||||
1.574908E-01
|
||||
5.079304E-03
|
||||
5.621044E-02
|
||||
6.877866E-04
|
||||
8.490616E-02
|
||||
1.510673E-03
|
||||
4.709600E-02
|
||||
4.576632E-04
|
||||
5.382674E-02
|
||||
5.890600E-04
|
||||
1.116560E-01
|
||||
2.599817E-03
|
||||
6.648634E-02
|
||||
8.862677E-04
|
||||
1.996861E-01
|
||||
8.137198E-03
|
||||
6.218616E-01
|
||||
7.805532E-02
|
||||
1.672379E-01
|
||||
5.667797E-03
|
||||
1.841275E-01
|
||||
6.936896E-03
|
||||
5.887874E-01
|
||||
7.031665E-02
|
||||
1.872574E-01
|
||||
7.086584E-03
|
||||
7.574698E-02
|
||||
1.160992E-03
|
||||
1.100173E-01
|
||||
2.453972E-03
|
||||
5.427866E-02
|
||||
5.955556E-04
|
||||
5.644318E-02
|
||||
6.503634E-04
|
||||
1.058628E-01
|
||||
2.254338E-03
|
||||
8.012794E-02
|
||||
1.297032E-03
|
||||
2.292757E-01
|
||||
1.064490E-02
|
||||
9.001874E-01
|
||||
2.153097E-01
|
||||
1.921874E-01
|
||||
7.537343E-03
|
||||
2.058642E-01
|
||||
8.537136E-03
|
||||
9.442653E-01
|
||||
2.359241E-01
|
||||
2.419900E-01
|
||||
1.202201E-02
|
||||
7.563876E-02
|
||||
1.169874E-03
|
||||
1.165428E-01
|
||||
2.750405E-03
|
||||
5.646354E-02
|
||||
6.408683E-04
|
||||
4.963879E-02
|
||||
4.975915E-04
|
||||
1.005478E-01
|
||||
2.046400E-03
|
||||
7.041191E-02
|
||||
1.002590E-03
|
||||
1.959123E-01
|
||||
7.727902E-03
|
||||
5.625596E-01
|
||||
6.366248E-02
|
||||
1.987313E-01
|
||||
8.108832E-03
|
||||
1.922194E-01
|
||||
7.602752E-03
|
||||
6.062527E-01
|
||||
7.384124E-02
|
||||
2.039506E-01
|
||||
8.379010E-03
|
||||
7.019905E-02
|
||||
1.034239E-03
|
||||
1.081383E-01
|
||||
2.344040E-03
|
||||
5.125142E-02
|
||||
5.430397E-04
|
||||
4.230495E-02
|
||||
3.666730E-04
|
||||
7.722275E-02
|
||||
1.208856E-03
|
||||
4.998937E-02
|
||||
5.049355E-04
|
||||
1.461632E-01
|
||||
4.456332E-03
|
||||
3.315459E-01
|
||||
2.288314E-02
|
||||
1.238273E-01
|
||||
3.205844E-03
|
||||
1.355317E-01
|
||||
3.754923E-03
|
||||
3.646520E-01
|
||||
2.766067E-02
|
||||
1.543013E-01
|
||||
5.044487E-03
|
||||
6.082173E-02
|
||||
7.636985E-04
|
||||
8.490569E-02
|
||||
1.506309E-03
|
||||
4.046126E-02
|
||||
3.495832E-04
|
||||
72
tests/regression_tests/filter_rotations/test.py
Normal file
72
tests/regression_tests/filter_rotations/test.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import pytest
|
||||
|
||||
from tests.testing_harness import PyAPITestHarness
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def model():
|
||||
|
||||
model = openmc.model.Model()
|
||||
|
||||
fuel = openmc.Material()
|
||||
fuel.set_density('g/cm3', 10.0)
|
||||
fuel.add_nuclide('U235', 1.0)
|
||||
zr = openmc.Material()
|
||||
zr.set_density('g/cm3', 1.0)
|
||||
zr.add_nuclide('Zr90', 1.0)
|
||||
model.materials.extend([fuel, zr])
|
||||
|
||||
box1 = openmc.model.RectangularPrism(10.0, 10.0)
|
||||
box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective')
|
||||
top = openmc.ZPlane(z0=10.0, boundary_type='vacuum')
|
||||
bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum')
|
||||
cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top)
|
||||
cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top)
|
||||
model.geometry = openmc.Geometry([cell1, cell2])
|
||||
|
||||
model.settings.batches = 5
|
||||
model.settings.inactive = 0
|
||||
model.settings.particles = 1000
|
||||
|
||||
rotation = np.array((0, 0, 10))
|
||||
|
||||
llc = np.array([-9, -9, -9])
|
||||
urc = np.array([9, 9, 9])
|
||||
|
||||
mesh_dims = (3, 4, 5)
|
||||
|
||||
filters = []
|
||||
|
||||
# un-rotated meshes
|
||||
reg_mesh = openmc.RegularMesh()
|
||||
reg_mesh.dimension = mesh_dims
|
||||
reg_mesh.lower_left = llc
|
||||
reg_mesh.upper_right = urc
|
||||
|
||||
filters.append(openmc.MeshFilter(reg_mesh))
|
||||
|
||||
# rotated meshes
|
||||
rotated_reg_mesh = openmc.RegularMesh()
|
||||
rotated_reg_mesh.dimension = mesh_dims
|
||||
rotated_reg_mesh.lower_left = llc
|
||||
rotated_reg_mesh.upper_right = urc
|
||||
|
||||
filters.append(openmc.MeshFilter(rotated_reg_mesh))
|
||||
filters[-1].rotation = rotation
|
||||
|
||||
# Create tallies
|
||||
for f in filters:
|
||||
tally = openmc.Tally()
|
||||
tally.filters = [f]
|
||||
tally.scores = ['total']
|
||||
model.tallies.append(tally)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def test_filter_mesh_rotations(model):
|
||||
harness = PyAPITestHarness('statepoint.5.h5', model)
|
||||
harness.main()
|
||||
|
|
@ -259,3 +259,29 @@ def test_get_reshaped_data(run_in_tmpdir):
|
|||
|
||||
assert data1.shape == (2, 19*3*2, 1, 1)
|
||||
assert data2.shape == (2, 19, 3, 2, 1, 1)
|
||||
|
||||
def test_mesh_filter_rotation_roundtrip(run_in_tmpdir):
|
||||
"""Test that MeshFilter rotation works as expected"""
|
||||
|
||||
|
||||
mesh = openmc.RegularMesh()
|
||||
mesh.lower_left = [-10, -10, -10]
|
||||
mesh.upper_right = [10, 10, 10]
|
||||
mesh.dimension = [2, 3, 4]
|
||||
|
||||
# check that rotatoin is round-tripped correctly for a set of angles
|
||||
mesh_filter = openmc.MeshFilter(mesh)
|
||||
mesh_filter.rotation = [0, 0, 90] # Rotate around z-axis by 90 degrees
|
||||
|
||||
elem = mesh_filter.to_xml_element()
|
||||
mesh_filter_xml = openmc.MeshFilter.from_xml_element(elem, meshes={mesh.id: mesh})
|
||||
assert all(mesh_filter_xml.rotation == mesh_filter.rotation)
|
||||
|
||||
# check that rotation matrix is round-tripped correctly for a rotation matrix
|
||||
mesh_filter.rotation = np.array([[0.7071, 0, 0.7071],
|
||||
[0, 1, 0],
|
||||
[-0.7071, 0, 0.7071]])
|
||||
|
||||
elem = mesh_filter.to_xml_element()
|
||||
mesh_filter_xml = openmc.MeshFilter.from_xml_element(elem, meshes={mesh.id: mesh})
|
||||
assert np.allclose(mesh_filter_xml.rotation, mesh_filter.rotation)
|
||||
|
|
|
|||
|
|
@ -608,6 +608,13 @@ def test_regular_mesh(lib_init):
|
|||
assert isinstance(mesh, openmc.lib.RegularMesh)
|
||||
assert mesh_id == mesh.id
|
||||
|
||||
rotation = (180.0, 0.0, 0.0)
|
||||
|
||||
mf = openmc.lib.MeshFilter(mesh)
|
||||
assert mf.mesh == mesh
|
||||
mf.rotation = rotation
|
||||
assert np.allclose(mf.rotation, rotation)
|
||||
|
||||
translation = (1.0, 2.0, 3.0)
|
||||
|
||||
mf = openmc.lib.MeshFilter(mesh)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue