mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
finished unit tests
This commit is contained in:
parent
a25882e76f
commit
c88bd49597
4 changed files with 174 additions and 139 deletions
186
openmc/region.py
186
openmc/region.py
|
|
@ -225,7 +225,6 @@ class Region(metaclass=ABCMeta):
|
|||
# at the end
|
||||
return output[0]
|
||||
|
||||
@abstractmethod
|
||||
def clone(self, memo=None):
|
||||
"""Create a copy of this region - each of the surfaces in the
|
||||
region's nodes will be cloned and will have new unique IDs.
|
||||
|
|
@ -242,9 +241,14 @@ class Region(metaclass=ABCMeta):
|
|||
The clone of this region
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
clone = deepcopy(self)
|
||||
clone[:] = [n.clone(memo) for n in self]
|
||||
return clone
|
||||
|
||||
def translate(self, vector, memo=None):
|
||||
"""Translate region in given direction
|
||||
|
||||
|
|
@ -262,7 +266,52 @@ class Region(metaclass=ABCMeta):
|
|||
Translated region
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(n.translate(vector, memo) for n in self)
|
||||
|
||||
def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False,
|
||||
memo=None):
|
||||
r"""Rotate surface by angles provided or by applying matrix directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rotation : 3-tuple of float, or 3x3 iterable
|
||||
A 3-tuple of angles :math:`(\phi, \theta, \psi)` in degrees where
|
||||
the first element is the rotation about the x-axis in the fixed
|
||||
laboratory frame, the second element is the rotation about the
|
||||
y-axis in the fixed laboratory frame, and the third element is the
|
||||
rotation about the z-axis in the fixed laboratory frame. The
|
||||
rotations are active rotations. Additionally a 3x3 rotation matrix
|
||||
can be specified directly either as a nested iterable or array.
|
||||
pivot : iterable of float, optional
|
||||
(x, y, z) coordinates for the point to rotate about. Defaults to
|
||||
(0., 0., 0.)
|
||||
order : str, optional
|
||||
A string of 'x', 'y', and 'z' in some order specifying which
|
||||
rotation to perform first, second, and third. Defaults to 'xyz'
|
||||
which means, the rotation by angle :math:`\phi` about x will be
|
||||
applied first, followed by :math:`\theta` about y and then
|
||||
:math:`\psi` about z. This corresponds to an x-y-z extrinsic
|
||||
rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan
|
||||
angles :math:`(\phi, \theta, \psi)`.
|
||||
inplace : boolean
|
||||
Whether or not to return a new instance of Surface or to modify the
|
||||
coefficients of this Surface in place. Defaults to False.
|
||||
memo : dict or None
|
||||
Dictionary used for memoization
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.Region
|
||||
Translated region
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(n.rotate(rotation, pivot=pivot, order=order,
|
||||
inplace=inplace, memo=memo) for n in self)
|
||||
|
||||
|
||||
class Intersection(Region, MutableSequence):
|
||||
|
|
@ -354,51 +403,6 @@ class Intersection(Region, MutableSequence):
|
|||
upper_right[:] = np.minimum(upper_right, upper_right_n)
|
||||
return lower_left, upper_right
|
||||
|
||||
def clone(self, memo=None):
|
||||
"""Create a copy of this region - each of the surfaces in the
|
||||
intersection's nodes will be cloned and will have new unique IDs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
memo : dict or None
|
||||
A nested dictionary of previously cloned objects. This parameter
|
||||
is used internally and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
clone : openmc.Intersection
|
||||
The clone of this intersection
|
||||
|
||||
"""
|
||||
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
clone = deepcopy(self)
|
||||
clone[:] = [n.clone(memo) for n in self]
|
||||
return clone
|
||||
|
||||
def translate(self, vector, memo=None):
|
||||
"""Translate region in given direction
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : iterable of float
|
||||
Direction in which region should be translated
|
||||
memo : dict or None
|
||||
Dictionary used for memoization. This parameter is used internally
|
||||
and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.Intersection
|
||||
Translated region
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(n.translate(vector, memo) for n in self)
|
||||
|
||||
|
||||
class Union(Region, MutableSequence):
|
||||
r"""Union of two or more regions.
|
||||
|
|
@ -487,51 +491,6 @@ class Union(Region, MutableSequence):
|
|||
upper_right[:] = np.maximum(upper_right, upper_right_n)
|
||||
return lower_left, upper_right
|
||||
|
||||
def clone(self, memo=None):
|
||||
"""Create a copy of this region - each of the surfaces in the
|
||||
union's nodes will be cloned and will have new unique IDs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
memo : dict or None
|
||||
A nested dictionary of previously cloned objects. This parameter
|
||||
is used internally and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
clone : openmc.Union
|
||||
The clone of this union
|
||||
|
||||
"""
|
||||
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
clone = deepcopy(self)
|
||||
clone[:] = [n.clone(memo) for n in self]
|
||||
return clone
|
||||
|
||||
def translate(self, vector, memo=None):
|
||||
"""Translate region in given direction
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : iterable of float
|
||||
Direction in which region should be translated
|
||||
memo : dict or None
|
||||
Dictionary used for memoization. This parameter is used internally
|
||||
and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.Union
|
||||
Translated region
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(n.translate(vector, memo) for n in self)
|
||||
|
||||
|
||||
class Complement(Region):
|
||||
"""Complement of a region.
|
||||
|
|
@ -642,22 +601,6 @@ class Complement(Region):
|
|||
region.remove_redundant_surfaces(redundant_surfaces)
|
||||
|
||||
def clone(self, memo=None):
|
||||
"""Create a copy of this region - each of the surfaces in the
|
||||
complement's node will be cloned and will have new unique IDs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
memo : dict or None
|
||||
A nested dictionary of previously cloned objects. This parameter
|
||||
is used internally and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
clone : openmc.Complement
|
||||
The clone of this complement
|
||||
|
||||
"""
|
||||
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
|
|
@ -666,22 +609,13 @@ class Complement(Region):
|
|||
return clone
|
||||
|
||||
def translate(self, vector, memo=None):
|
||||
"""Translate region in given direction
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vector : iterable of float
|
||||
Direction in which region should be translated
|
||||
memo : dict or None
|
||||
Dictionary used for memoization. This parameter is used internally
|
||||
and should not be specified by the user.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.Complement
|
||||
Translated region
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(self.node.translate(vector, memo))
|
||||
|
||||
def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False,
|
||||
memo=None):
|
||||
if memo is None:
|
||||
memo = {}
|
||||
return type(self)(self.node.rotate(rotation, pivot=pivot, order=order,
|
||||
inplace=inplace, memo=memo))
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ def get_rotation_matrix(rotation, order='xyz'):
|
|||
laboratory frame, and the third element is the rotation about the
|
||||
z-axis in the fixed laboratory frame. The rotations are active
|
||||
rotations.
|
||||
order : str, optinoal
|
||||
order : str, optional
|
||||
A string of 'x', 'y', and 'z' in some order specifying which rotation
|
||||
to perform first, second, and third. Defaults to 'xyz' which means, the
|
||||
rotation by angle phi about x will be applied first, followed by theta
|
||||
about y and then phi about z. This corresponds to an x-y-z extrinsic
|
||||
rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan
|
||||
angles :math:`(\phi, \theta, \psi)`.
|
||||
rotation by angle :math:`\phi` about x will be applied first, followed
|
||||
by :math:`\theta` about y and then :math:`\psi` about z. This
|
||||
corresponds to an x-y-z extrinsic rotation as well as a z-y'-x''
|
||||
intrinsic rotation using Tait-Bryan angles :math:`(\phi, \theta, \psi)`.
|
||||
|
||||
"""
|
||||
check_type('surface rotation', rotation, Iterable, Real)
|
||||
|
|
@ -307,22 +307,29 @@ class Surface(IDManagerMixin, metaclass=ABCMeta):
|
|||
|
||||
@abstractmethod
|
||||
def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False):
|
||||
r"""Rotate surface by given Tait-Bryan angles
|
||||
r"""Rotate surface by angles provided or by applying matrix directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rotation : iterable of float
|
||||
Intrinsic Tait-Bryan angles in degrees used to rotate the surface
|
||||
rotation : 3-tuple of float, or 3x3 iterable
|
||||
A 3-tuple of angles :math:`(\phi, \theta, \psi)` in degrees where
|
||||
the first element is the rotation about the x-axis in the fixed
|
||||
laboratory frame, the second element is the rotation about the
|
||||
y-axis in the fixed laboratory frame, and the third element is the
|
||||
rotation about the z-axis in the fixed laboratory frame. The
|
||||
rotations are active rotations. Additionally a 3x3 rotation matrix
|
||||
can be specified directly either as a nested iterable or array.
|
||||
pivot : iterable of float, optional
|
||||
(x, y, z) coordinates for the point to rotate about. Defaults to
|
||||
(0., 0., 0.)
|
||||
order : str, optional
|
||||
A string of 'x', 'y', and 'z' in some order specifying which
|
||||
rotation to perform first, second, and third. Defaults to 'xyz'
|
||||
which means, the rotation by angle phi about x will be applied
|
||||
first, followed by theta about y and then phi about z. This
|
||||
corresponds to an x-y-z extrinsic rotation as well as a z-y'-x''
|
||||
intrinsic rotation using Tait-Bryan angles :math:`(\phi, \theta, \psi)`.
|
||||
which means, the rotation by angle :math:`\phi` about x will be
|
||||
applied first, followed by :math:`\theta` about y and then
|
||||
:math:`\psi` about z. This corresponds to an x-y-z extrinsic
|
||||
rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan
|
||||
angles :math:`(\phi, \theta, \psi)`.
|
||||
inplace : boolean
|
||||
Whether or not to return a new instance of Surface or to modify the
|
||||
coefficients of this Surface in place. Defaults to False.
|
||||
|
|
@ -1291,6 +1298,19 @@ class Cylinder(QuadricMixin, Surface):
|
|||
check_type('dz coefficient', dz, Real)
|
||||
self._coefficients['dz'] = dz
|
||||
|
||||
def bounding_box(self, side):
|
||||
if side == '-':
|
||||
r = self.r
|
||||
ll = [xi - r if np.isclose(dxi, 0., rtol=0., atol=self._atol)
|
||||
else -np.inf for xi, dxi in zip(self._origin, self._axis)]
|
||||
ur = [xi + r if np.isclose(dxi, 0., rtol=0., atol=self._atol)
|
||||
else np.inf for xi, dxi in zip(self._origin, self._axis)]
|
||||
return (np.array(ll), np.array(ur))
|
||||
|
||||
elif side == '+':
|
||||
return (np.array([-np.inf, -np.inf, -np.inf]),
|
||||
np.array([np.inf, np.inf, np.inf]))
|
||||
|
||||
def _get_base_coeffs(self):
|
||||
# Get x, y, z coordinates of two points
|
||||
x1, y1, z1 = self._origin
|
||||
|
|
@ -2772,9 +2792,59 @@ class Halfspace(Region):
|
|||
if key not in memo:
|
||||
memo[key] = self.surface.translate(vector)
|
||||
|
||||
# Return translated surface
|
||||
# Return translated half-space
|
||||
return type(self)(memo[key], self.side)
|
||||
|
||||
def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False,
|
||||
memo=None):
|
||||
r"""Rotate surface by angles provided or by applying matrix directly.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rotation : 3-tuple of float, or 3x3 iterable
|
||||
A 3-tuple of angles :math:`(\phi, \theta, \psi)` in degrees where
|
||||
the first element is the rotation about the x-axis in the fixed
|
||||
laboratory frame, the second element is the rotation about the
|
||||
y-axis in the fixed laboratory frame, and the third element is the
|
||||
rotation about the z-axis in the fixed laboratory frame. The
|
||||
rotations are active rotations. Additionally a 3x3 rotation matrix
|
||||
can be specified directly either as a nested iterable or array.
|
||||
pivot : iterable of float, optional
|
||||
(x, y, z) coordinates for the point to rotate about. Defaults to
|
||||
(0., 0., 0.)
|
||||
order : str, optional
|
||||
A string of 'x', 'y', and 'z' in some order specifying which
|
||||
rotation to perform first, second, and third. Defaults to 'xyz'
|
||||
which means, the rotation by angle :math:`\phi` about x will be
|
||||
applied first, followed by :math:`\theta` about y and then
|
||||
:math:`\psi` about z. This corresponds to an x-y-z extrinsic
|
||||
rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan
|
||||
angles :math:`(\phi, \theta, \psi)`.
|
||||
inplace : boolean
|
||||
Whether or not to return a new instance of Surface or to modify the
|
||||
coefficients of this Surface in place. Defaults to False.
|
||||
memo : dict or None
|
||||
Dictionary used for memoization
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.Halfspace
|
||||
Translated half-space
|
||||
|
||||
"""
|
||||
if memo is None:
|
||||
memo = {}
|
||||
|
||||
# If rotated surface not in memo, add it
|
||||
key = (self.surface, tuple(rotation), tuple(pivot), order, inplace)
|
||||
if key not in memo:
|
||||
memo[key] = self.surface.rotate(rotation, pivot=pivot, order=order,
|
||||
inplace=inplace)
|
||||
|
||||
# Return rotated half-space
|
||||
return type(self)(memo[key], self.side)
|
||||
|
||||
|
||||
_SURFACE_CLASSES = {cls._type: cls for cls in Surface.__subclasses__()}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,13 @@ def test_union(reset):
|
|||
assert (6, 0, 0) not in regt
|
||||
assert (8, 0, 0) in regt
|
||||
|
||||
# rotate method
|
||||
regr = region.rotate((0., 90., 0.))
|
||||
assert (-4, 0, 0) not in regr
|
||||
assert (0, 0, 6) in regr
|
||||
assert (0, 0, -6) in regr
|
||||
assert (0, 0, 3) not in regr
|
||||
|
||||
|
||||
def test_intersection(reset):
|
||||
s1 = openmc.XPlane(x0=5, surface_id=1)
|
||||
|
|
@ -73,6 +80,13 @@ def test_intersection(reset):
|
|||
assert (6, 0, 0) in regt
|
||||
assert (8, 0, 0) not in regt
|
||||
|
||||
# rotate method
|
||||
regr = region.rotate((0., 90., 0.))
|
||||
assert (-4, 0, 0) in regr
|
||||
assert (0, 0, 6) not in regr
|
||||
assert (0, 0, -6) not in regr
|
||||
assert (0, 0, 3) in regr
|
||||
|
||||
|
||||
def test_complement(reset):
|
||||
zcyl = openmc.ZCylinder(r=1., surface_id=1)
|
||||
|
|
@ -106,6 +120,14 @@ def test_complement(reset):
|
|||
assert ll == pytest.approx((0., 0., -4.))
|
||||
assert ur == pytest.approx((2., 2., 6.))
|
||||
|
||||
# rotate method
|
||||
inside_r = inside.rotate((90., 0., 0.))
|
||||
ll, ur = inside_r.bounding_box
|
||||
assert (.5, 2, 0) in inside_r
|
||||
assert (0, 0, 6) not in inside_r
|
||||
assert ll == pytest.approx((-1., -5., -1.))
|
||||
assert ur == pytest.approx((1., 5., 1.))
|
||||
|
||||
|
||||
def test_get_surfaces():
|
||||
s1 = openmc.XPlane()
|
||||
|
|
|
|||
|
|
@ -533,6 +533,15 @@ def test_quadric():
|
|||
assert (st.g, st.h, st.j) == (-2, -2, -2)
|
||||
assert st.k == s.k + 3
|
||||
|
||||
# rotate method
|
||||
x0, y0, z0, r2 = 2, 3, 4, 4
|
||||
dx, dy, dz = 1, -1, 1
|
||||
s = openmc.Cone(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r2=r2)
|
||||
q = openmc.Quadric(*s._get_base_coeffs())
|
||||
qr = q.rotate((45, 60, 30))
|
||||
sr = s.rotate((45, 60, 30))
|
||||
assert qr.is_equal(sr)
|
||||
|
||||
|
||||
def test_cylinder_from_points():
|
||||
seed(1) # Make random numbers reproducible
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue