diff --git a/openmc/surface.py b/openmc/surface.py index 97aca43b3..c2afeb613 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -38,10 +38,13 @@ class SurfaceCoefficient: value : float or str Value of the coefficient (float) or the name of the coefficient that it is equivalent to (str). + positive : bool + Does the surface coefficient must be positive. Defaults to False. """ - def __init__(self, value): + def __init__(self, value, positive=False): self.value = value + self.positive = positive def __get__(self, instance, owner=None): if instance is None: @@ -56,6 +59,8 @@ class SurfaceCoefficient: if isinstance(self.value, Real): raise AttributeError('This coefficient is read-only') check_type(f'{self.value} coefficient', value, Real) + if self.positive: + check_greater_than(f'{self.value} coefficient', value, 0.0) instance._coefficients[self.value] = value @@ -1261,7 +1266,7 @@ class Cylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r') + r = SurfaceCoefficient('r', positive=True) dx = SurfaceCoefficient('dx') dy = SurfaceCoefficient('dy') dz = SurfaceCoefficient('dz') @@ -1427,7 +1432,7 @@ class XCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient(0.) y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r') + r = SurfaceCoefficient('r', positive=True) dx = SurfaceCoefficient(1.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(0.) @@ -1525,7 +1530,7 @@ class YCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient(0.) z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r') + r = SurfaceCoefficient('r', positive=True) dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(1.) dz = SurfaceCoefficient(0.) @@ -1623,7 +1628,7 @@ class ZCylinder(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient(0.) - r = SurfaceCoefficient('r') + r = SurfaceCoefficient('r', positive=True) dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(1.) @@ -1723,7 +1728,7 @@ class Sphere(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r = SurfaceCoefficient('r') + r = SurfaceCoefficient('r', positive=True) def _get_base_coeffs(self): x0, y0, z0, r = self.x0, self.y0, self.z0, self.r @@ -1849,7 +1854,7 @@ class Cone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2') + r2 = SurfaceCoefficient('r2', positive=True) dx = SurfaceCoefficient('dx') dy = SurfaceCoefficient('dy') dz = SurfaceCoefficient('dz') @@ -1985,7 +1990,7 @@ class XCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2') + r2 = SurfaceCoefficient('r2', positive=True) dx = SurfaceCoefficient(1.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(0.) @@ -2087,7 +2092,7 @@ class YCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2') + r2 = SurfaceCoefficient('r2', positive=True) dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(1.) dz = SurfaceCoefficient(0.) @@ -2189,7 +2194,7 @@ class ZCone(QuadricMixin, Surface): x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - r2 = SurfaceCoefficient('r2') + r2 = SurfaceCoefficient('r2', positive=True) dx = SurfaceCoefficient(0.) dy = SurfaceCoefficient(0.) dz = SurfaceCoefficient(1.) @@ -2292,9 +2297,9 @@ class TorusMixin: x0 = SurfaceCoefficient('x0') y0 = SurfaceCoefficient('y0') z0 = SurfaceCoefficient('z0') - a = SurfaceCoefficient('a') - b = SurfaceCoefficient('b') - c = SurfaceCoefficient('c') + a = SurfaceCoefficient('a', positive=True) + b = SurfaceCoefficient('b', positive=True) + c = SurfaceCoefficient('c', positive=True) def translate(self, vector, inplace=False): surf = self if inplace else self.clone() diff --git a/tests/unit_tests/test_pin.py b/tests/unit_tests/test_pin.py index 5496a3b73..53665b1a6 100644 --- a/tests/unit_tests/test_pin.py +++ b/tests/unit_tests/test_pin.py @@ -46,11 +46,6 @@ def test_failure(pin_mats, good_radii): with pytest.raises(ValueError, match="length"): pin(good_surfaces[:len(pin_mats) - 2], pin_mats) - # Non-positive radii - rad = [openmc.ZCylinder(r=-0.1)] + good_surfaces[1:] - with pytest.raises(ValueError, match="index 0"): - pin(rad, pin_mats) - # Non-increasing radii surfs = tuple(reversed(good_surfaces)) with pytest.raises(ValueError, match="index 1"): diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index aaf591e05..f5c0b8f8b 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -195,6 +195,12 @@ def test_cylinder(): assert s.dy == -1 assert s.dz == 1 assert s.r == 2 + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.Cylinder(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r=0.0) + with pytest.raises(ValueError): + openmc.Cylinder(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r=-1.0) # Check bounding box assert_infinite_bb(s) @@ -244,6 +250,12 @@ def test_xcylinder(): assert s.y0 == y assert s.z0 == z assert s.r == r + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.XCylinder(y0=y, z0=z, r=0.0) + with pytest.raises(ValueError): + openmc.XCylinder(y0=y, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -290,6 +302,12 @@ def test_ycylinder(): assert s.x0 == x assert s.z0 == z assert s.r == r + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.YCylinder(x0=x, z0=z, r=0.0) + with pytest.raises(ValueError): + openmc.YCylinder(x0=x, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -327,6 +345,12 @@ def test_zcylinder(): assert s.x0 == x assert s.y0 == y assert s.r == r + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.ZCylinder(x0=x, y0=y, r=0.0) + with pytest.raises(ValueError): + openmc.ZCylinder(x0=x, y0=y, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -365,6 +389,12 @@ def test_sphere(): assert s.y0 == y assert s.z0 == z assert s.r == r + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.Sphere(x0=x, y0=y, z0=z, r=0.0) + with pytest.raises(ValueError): + openmc.Sphere(x0=x, y0=y, z0=z, r=-1.0) # Check bounding box ll, ur = (+s).bounding_box @@ -404,6 +434,12 @@ def cone_common(apex, r2, cls): assert s.y0 == y assert s.z0 == z assert s.r2 == r2 + + # Check radius must be positive + with pytest.raises(ValueError): + cls(x0=x, y0=y, z0=z, r2=0.0) + with pytest.raises(ValueError): + cls(x0=x, y0=y, z0=z, r2=-1.0) # Check bounding box assert_infinite_bb(s) @@ -442,6 +478,12 @@ def test_cone(): assert s.dy == -1 assert s.dz == 1 assert s.r2 == 4 + + # Check radius must be positive + with pytest.raises(ValueError): + openmc.Cone(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r2=0.0) + with pytest.raises(ValueError): + openmc.Cone(x0=x0, y0=y0, z0=z0, dx=dx, dy=dy, dz=dz, r2=-1.0) # Check bounding box assert_infinite_bb(s) @@ -622,6 +664,13 @@ def torus_common(center, R, r1, r2, cls): assert s.a == R assert s.b == r1 assert s.c == r2 + + # Check radius must be positive + params = [(0.0, r1, r2), (R, 0.0, r2), (R, r1, 0.0), + (-1.0, r1, r2), (R, -1.0, r2), (R, r1, -1.0)] + for a,b,c in params: + with pytest.raises(ValueError): + cls(x0=x, y0=y, z0=z, a=a, b=b, c=c) # evaluate method assert s.evaluate((x, y, z)) > 0.0