Resolving comments from @paulromano. Namely, set the openmc.lib.Cell rotation and translations to be properties that can take iterables vice ndarrays. Also removed const declaration when not needed. Finally, revised code and tests so that we do not return a None for non-initialized cases. This would yield different behavior between translation and rotation and instead of leading to confusion I now simply always return a sensical ndarray of float values.That is no rotation is no longer None, but is now array([0., 0., 0.]).

This commit is contained in:
agnelson 2021-07-30 11:42:27 -05:00
parent 6a9d43bcdb
commit ad3a14fa3d
4 changed files with 42 additions and 54 deletions

View file

@ -23,7 +23,7 @@ extern "C" {
int openmc_cell_set_id(int32_t index, int32_t id);
int openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance, bool set_contained = false);
int openmc_cell_set_translation(int32_t index, const double xyz[]);
int openmc_cell_set_rotation(int32_t index, const double rot[], const size_t rot_len);
int openmc_cell_set_rotation(int32_t index, const double rot[], size_t rot_len);
int openmc_energy_filter_get_bins(int32_t index, const double** energies, size_t* n);
int openmc_energy_filter_set_bins(int32_t index, size_t n, const double* energies);
int openmc_energyfunc_filter_get_energy(int32_t index, size_t* n, const double** energy);

View file

@ -103,6 +103,13 @@ class Cell(_FortranObjectWithID):
Number of unique cell instances
bounding_box : 2-tuple of numpy.ndarray
Lower-left and upper-right coordinates of bounding box
translation : Iterable of float
3-D coordinates of the translation vector
rotation : Iterable of float
The rotation matrix or angles of the universe filling the cell. 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.
"""
__instances = WeakValueDictionary()
@ -227,62 +234,43 @@ class Cell(_FortranObjectWithID):
_dll.openmc_cell_set_temperature(self._index, T, instance, set_contained)
def get_translation(self):
"""Get the translation vector of a cell
"""
@property
def translation(self):
translation = np.zeros(3)
_dll.openmc_cell_get_translation(
self._index, translation.ctypes.data_as(POINTER(c_double)))
return translation
def set_translation(self, translation):
"""Set the translation vector of a cell
Parameters
----------
translation : numpy.ndarray
3-D translation vector
"""
@translation.setter
def translation(self, translation_vec):
vector = np.asarray(translation_vec, dtype=float)
_dll.openmc_cell_set_translation(
self._index, translation.ctypes.data_as(POINTER(c_double)))
self._index, vector.ctypes.data_as(POINTER(c_double)))
def get_rotation(self):
"""Get the rotation matrix of a cell
"""
rotation = np.zeros(12)
@property
def rotation(self):
rotation_data = np.zeros(12)
rot_size = c_size_t()
_dll.openmc_cell_get_rotation(
self._index, rotation.ctypes.data_as(POINTER(c_double)), rot_size)
self._index, rotation_data.ctypes.data_as(POINTER(c_double)),
rot_size)
rot_size = rot_size.value
if rot_size == 0:
return None
elif rot_size == 9:
return rotation[:n]
elif rot_size == 12:
return rotation[9:]
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(
'Invalid size of rotation matrix: {}'.format(rot_size))
def set_rotation(self, rotation):
"""Set the rotation matrix of a cell
Parameters
----------
rotation : numpy.ndarray
The rotation angles (if length is 3) or the 3x3 rotation matrix
"""
flat_rotation = rotation.flatten()
@rotation.setter
def rotation(self, rotation_data):
flat_rotation = np.asarray(rotation_data, dtype=float).flatten()
_dll.openmc_cell_set_rotation(
self._index, flat_rotation.ctypes.data_as(POINTER(c_double)),

View file

@ -1309,7 +1309,7 @@ openmc_cell_set_id(int32_t index, int32_t id)
extern "C" int openmc_cell_get_translation(int32_t index, double xyz[])
{
if (index >= 0 && index < model::cells.size()) {
auto& cell = openmc::model::cells[index];
auto& cell = model::cells[index];
xyz[0] = cell->translation_.x;
xyz[1] = cell->translation_.y;
xyz[2] = cell->translation_.z;
@ -1342,7 +1342,7 @@ extern "C" int openmc_cell_set_translation(int32_t index, const double xyz[])
extern "C" int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n)
{
if (index >= 0 && index < model::cells.size()) {
auto& cell = openmc::model::cells[index];
auto& cell = model::cells[index];
*n = cell->rotation_.size();
std::memcpy(rot, cell->rotation_.data(), *n * sizeof(cell->rotation_[0]));
return 0;
@ -1354,7 +1354,7 @@ extern "C" int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n)
//! Set the flattened rotation matrix of a cell
extern "C" int openmc_cell_set_rotation(int32_t index, const double rot[],
const size_t rot_len)
size_t rot_len)
{
if (index >= 0 && index < model::cells.size()) {
if (model::cells[index]->fill_ == C_NONE) {

View file

@ -717,28 +717,28 @@ def test_cell_translation(pincell_model_w_univ, mpi_intracomm):
# Cell 1 is filled with a material so it has a translation, but we can't
# set it.
cell = openmc.lib.cells[1]
assert cell.get_translation() == pytest.approx([0., 0., 0.])
assert cell.translation == pytest.approx([0., 0., 0.])
with pytest.raises(exc.GeometryError, match='not filled with'):
cell.set_translation(np.array([1., 0., -1.]))
cell.translation = (1., 0., -1.)
# Cell 2 was given a universe, so we can assign it a translation vector
cell = openmc.lib.cells[2]
assert cell.get_translation() == pytest.approx([0., 0., 0.])
assert cell.translation == pytest.approx([0., 0., 0.])
# This time we *can* set it
cell.set_translation(np.array([1., 0., -1.]))
assert cell.get_translation() == pytest.approx([1., 0., -1.])
cell.translation = (1., 0., -1.)
assert cell.translation == pytest.approx([1., 0., -1.])
def test_cell_rotation(pincell_model_w_univ):
# Cell 1 is filled with a material so we cannot rotate it, but we can get
# its rotation matrix (which will be the identity matrix)
cell = openmc.lib.cells[1]
assert cell.get_rotation() is None
assert cell.rotation == pytest.approx([0., 0., 0.])
with pytest.raises(exc.GeometryError, match='not filled with'):
cell.set_rotation(np.array([180., 0., 0.]))
cell.rotation = (180., 0., 0.)
# Now repeat with Cell 2 and we will be allowed to do it
cell = openmc.lib.cells[2]
assert cell.get_rotation() is None
cell.set_rotation(np.array([180., 0., 0.]))
assert cell.get_rotation() == pytest.approx([180., 0., 0.])
assert cell.rotation == pytest.approx([0., 0., 0.])
cell.rotation = (180., 0., 0.)
assert cell.rotation == pytest.approx([180., 0., 0.])