Repository: openmc-dev/openmc

Issue:
Ellipse and ellipsoid surfaces
It is not possible to model ellipses or ellipsoids currently. This would be a fairly simple addition. Just need to go through the derivations for distance to surface and reflective boundary conditions.



Discussion:

Resolving patch:
diff --git a/openmc/summary.py b/openmc/summary.py
--- a/openmc/summary.py
+++ b/openmc/summary.py
@@ -179,6 +179,11 @@ def _read_surfaces(self):
                 if surf_type == 'z-cone':
                     surface = openmc.ZCone(surface_id, bc, x0, y0, z0, R2, name)
 
+            elif surf_type == 'quadric':
+                a, b, c, d, e, f, g, h, j, k = coeffs
+                surface = openmc.Quadric(surface_id, bc, a, b, c, d, e, f,
+                                         g, h, j, k, name)
+
             # Add Surface to global dictionary of all Surfaces
             self.surfaces[index] = surface
 
diff --git a/openmc/surface.py b/openmc/surface.py
--- a/openmc/surface.py
+++ b/openmc/surface.py
@@ -949,6 +949,152 @@ def __init__(self, surface_id=None, boundary_type='transmission',
         self._type = 'z-cone'
 
 
+class Quadric(Surface):
+    """A sphere of the form :math:`Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy +
+    Jz + K`.
+
+    Parameters
+    ----------
+    surface_id : int
+        Unique identifier for the surface. If not specified, an identifier will
+        automatically be assigned.
+    boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
+        Boundary condition that defines the behavior for particles hitting the
+        surface. Defaults to transmissive boundary condition where particles
+        freely pass through the surface.
+    a, b, c, d, e, f, g, h, j, k : float
+        coefficients for the surface
+    name : str
+        Name of the sphere. If not specified, the name will be the empty string.
+
+    Attributes
+    ----------
+    a, b, c, d, e, f, g, h, j, k : float
+        coefficients for the surface
+
+    """
+
+    def __init__(self, surface_id=None, boundary_type='transmission',
+                 a=None, b=None, c=None, d=None, e=None, f=None, g=None,
+                 h=None, j=None, k=None, name=''):
+        # Initialize Quadric class attributes
+        super(Quadric, self).__init__(surface_id, boundary_type, name=name)
+
+        self._type = 'quadric'
+        self._coeff_keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k']
+
+        if a is not None:
+            self.a = a
+        if b is not None:
+            self.b = b
+        if c is not None:
+            self.c = c
+        if d is not None:
+            self.d = d
+        if e is not None:
+            self.e = e
+        if f is not None:
+            self.f = f
+        if g is not None:
+            self.g = g
+        if h is not None:
+            self.h = h
+        if j is not None:
+            self.j = j
+        if k is not None:
+            self.k = k
+
+    @property
+    def a(self):
+        return self.coeffs['a']
+
+    @property
+    def b(self):
+        return self.coeffs['b']
+
+    @property
+    def c(self):
+        return self.coeffs['c']
+
+    @property
+    def d(self):
+        return self.coeffs['d']
+
+    @property
+    def e(self):
+        return self.coeffs['e']
+
+    @property
+    def f(self):
+        return self.coeffs['f']
+
+    @property
+    def g(self):
+        return self.coeffs['g']
+
+    @property
+    def h(self):
+        return self.coeffs['h']
+
+    @property
+    def j(self):
+        return self.coeffs['j']
+
+    @property
+    def k(self):
+        return self.coeffs['k']
+
+    @a.setter
+    def a(self, a):
+        check_type('a coefficient', a, Real)
+        self._coeffs['a'] = a
+
+    @b.setter
+    def b(self, b):
+        check_type('b coefficient', b, Real)
+        self._coeffs['b'] = b
+
+    @c.setter
+    def c(self, c):
+        check_type('c coefficient', c, Real)
+        self._coeffs['c'] = c
+
+    @d.setter
+    def d(self, d):
+        check_type('d coefficient', d, Real)
+        self._coeffs['d'] = d
+
+    @e.setter
+    def e(self, e):
+        check_type('e coefficient', e, Real)
+        self._coeffs['e'] = e
+
+    @f.setter
+    def f(self, f):
+        check_type('f coefficient', f, Real)
+        self._coeffs['f'] = f
+
+    @g.setter
+    def g(self, g):
+        check_type('g coefficient', g, Real)
+        self._coeffs['g'] = g
+
+    @h.setter
+    def h(self, h):
+        check_type('h coefficient', h, Real)
+        self._coeffs['h'] = h
+
+    @j.setter
+    def j(self, j):
+        check_type('j coefficient', j, Real)
+        self._coeffs['j'] = j
+
+    @k.setter
+    def k(self, k):
+        check_type('k coefficient', k, Real)
+        self._coeffs['k'] = k
+
+
 class Halfspace(Region):
     """A positive or negative half-space region.
 


Test patch:
diff --git a/tests/test_quadric_surfaces/geometry.xml b/tests/test_quadric_surfaces/geometry.xml
new file mode 100644
--- /dev/null
+++ b/tests/test_quadric_surfaces/geometry.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<geometry>
+
+  <surface id="1" type="sphere" coeffs="0. 0. 5. 5." boundary="reflective" />
+  <surface id="2" type="quadric" coeffs="1. 1. 1. 0. 0. 0. 0. 0. 0. -81." boundary="reflective" />
+  <surface id="3" type="z-plane" coeffs="5." />
+  <surface id="4" type="z-cylinder" coeffs="0. 0. 5." boundary="reflective" />
+  <surface id="5" type="z-cone" coeffs="0. 0. -10. 1." boundary="reflective" />
+  <surface id="6" type="plane" coeffs="0.2 0.2 1.0 -8." boundary="reflective" />
+
+  <cell id="1" material="1" region="-1 -2 3" />
+  <cell id="2" material="1" region="-3 -4 -5 6" />
+
+</geometry>
diff --git a/tests/test_reflective_sphere/materials.xml b/tests/test_quadric_surfaces/materials.xml
similarity index 56%
rename from tests/test_reflective_sphere/materials.xml
rename to tests/test_quadric_surfaces/materials.xml
--- a/tests/test_reflective_sphere/materials.xml
+++ b/tests/test_quadric_surfaces/materials.xml
@@ -3,7 +3,8 @@
 
   <material id="1">
     <density value="4.5" units="g/cc" />
-    <nuclide name="U-235" xs="71c" ao="1.0" />
+    <nuclide name="U-238" xs="71c" ao="1.0" />
+    <nuclide name="U-235" xs="71c" ao="0.06" />
   </material>
 
 </materials>
diff --git a/tests/test_quadric_surfaces/results_true.dat b/tests/test_quadric_surfaces/results_true.dat
new file mode 100644
--- /dev/null
+++ b/tests/test_quadric_surfaces/results_true.dat
@@ -0,0 +1,2 @@
+k-combined:
+9.706301E-01 4.351374E-02
diff --git a/tests/test_reflective_cone/settings.xml b/tests/test_quadric_surfaces/settings.xml
similarity index 79%
rename from tests/test_reflective_cone/settings.xml
rename to tests/test_quadric_surfaces/settings.xml
--- a/tests/test_reflective_cone/settings.xml
+++ b/tests/test_quadric_surfaces/settings.xml
@@ -8,7 +8,7 @@
   </eigenvalue>
 
   <source>
-    <space type="point" parameters="0 0 -5" />
+    <space type="point" parameters="0. 0. 0." />
   </source>
 
 </settings>
diff --git a/tests/test_reflective_cone/test_reflective_cone.py b/tests/test_quadric_surfaces/test_quadric_surfaces.py
old mode 100644
new mode 100755
similarity index 100%
rename from tests/test_reflective_cone/test_reflective_cone.py
rename to tests/test_quadric_surfaces/test_quadric_surfaces.py
diff --git a/tests/test_reflective_cone/geometry.xml b/tests/test_reflective_cone/geometry.xml
deleted file mode 100644
--- a/tests/test_reflective_cone/geometry.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0"?>
-<geometry>
-
-  <surface id="1" type="z-cone" coeffs="0 0 0 5" boundary="reflective"/>
-  <cell id="1" material="1" region="-1" />
-    
-</geometry>
diff --git a/tests/test_reflective_cone/materials.xml b/tests/test_reflective_cone/materials.xml
deleted file mode 100644
--- a/tests/test_reflective_cone/materials.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<materials>
-
-  <material id="1">
-    <density value="4.5" units="g/cc" />
-    <nuclide name="U-235" xs="71c" ao="1.0" />
-  </material>
-
-</materials>
diff --git a/tests/test_reflective_cone/results_true.dat b/tests/test_reflective_cone/results_true.dat
deleted file mode 100644
--- a/tests/test_reflective_cone/results_true.dat
+++ /dev/null
@@ -1,2 +0,0 @@
-k-combined:
-2.269987E+00 4.469683E-03
diff --git a/tests/test_reflective_cylinder/geometry.xml b/tests/test_reflective_cylinder/geometry.xml
deleted file mode 100644
--- a/tests/test_reflective_cylinder/geometry.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0"?>
-<geometry>
-
-  <!-- cylinder with radius 10 -->
-  <surface id="1" type="z-cylinder" coeffs="0 0 10" boundary="reflective"/>
-  <cell id="1" material="1" region="-1" />
-    
-</geometry>
diff --git a/tests/test_reflective_cylinder/materials.xml b/tests/test_reflective_cylinder/materials.xml
deleted file mode 100644
--- a/tests/test_reflective_cylinder/materials.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0"?>
-<materials>
-
-  <material id="1">
-    <density value="4.5" units="g/cc" />
-    <nuclide name="U-235" xs="71c" ao="1.0" />
-  </material>
-
-</materials>
diff --git a/tests/test_reflective_cylinder/results_true.dat b/tests/test_reflective_cylinder/results_true.dat
deleted file mode 100644
--- a/tests/test_reflective_cylinder/results_true.dat
+++ /dev/null
@@ -1,2 +0,0 @@
-k-combined:
-2.272436E+00 7.831006E-04
diff --git a/tests/test_reflective_cylinder/settings.xml b/tests/test_reflective_cylinder/settings.xml
deleted file mode 100644
--- a/tests/test_reflective_cylinder/settings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<settings>
-
-  <eigenvalue>
-    <batches>10</batches>
-    <inactive>5</inactive>
-    <particles>1000</particles>
-  </eigenvalue>
-
-  <source>
-    <space type="box">
-      <parameters>-4 -4 -4  4  4  4</parameters>
-    </space>
-  </source>
-
-</settings>
diff --git a/tests/test_reflective_cylinder/test_reflective_cylinder.py b/tests/test_reflective_cylinder/test_reflective_cylinder.py
deleted file mode 100644
--- a/tests/test_reflective_cylinder/test_reflective_cylinder.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import sys
-sys.path.insert(0, os.pardir)
-from testing_harness import TestHarness
-
-
-if __name__ == '__main__':
-    harness = TestHarness('statepoint.10.*')
-    harness.main()
diff --git a/tests/test_reflective_sphere/geometry.xml b/tests/test_reflective_sphere/geometry.xml
deleted file mode 100644
--- a/tests/test_reflective_sphere/geometry.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0"?>
-<geometry>
-
-  <!-- Sphere with radius 10 -->
-  <surface id="1" type="sphere" coeffs="0 0 0 10" boundary="reflective"/>
-  <cell id="1" material="1" region="-1" />
-    
-</geometry>
diff --git a/tests/test_reflective_sphere/results_true.dat b/tests/test_reflective_sphere/results_true.dat
deleted file mode 100644
--- a/tests/test_reflective_sphere/results_true.dat
+++ /dev/null
@@ -1,2 +0,0 @@
-k-combined:
-2.271012E+00 3.466351E-03
diff --git a/tests/test_reflective_sphere/settings.xml b/tests/test_reflective_sphere/settings.xml
deleted file mode 100644
--- a/tests/test_reflective_sphere/settings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<settings>
-
-  <eigenvalue>
-    <batches>10</batches>
-    <inactive>5</inactive>
-    <particles>1000</particles>
-  </eigenvalue>
-
-  <source>
-    <space type="box">
-      <parameters>-4 -4 -4  4  4  4</parameters>
-    </space>
-  </source>
-
-</settings>
diff --git a/tests/test_reflective_sphere/test_reflective_sphere.py b/tests/test_reflective_sphere/test_reflective_sphere.py
deleted file mode 100644
--- a/tests/test_reflective_sphere/test_reflective_sphere.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import sys
-sys.path.insert(0, os.pardir)
-from testing_harness import TestHarness
-
-
-if __name__ == '__main__':
-    harness = TestHarness('statepoint.10.*')
-    harness.main()