diff --git a/openmc/universe.py b/openmc/universe.py
index b65263ef9c..78f75bbfc1 100644
--- a/openmc/universe.py
+++ b/openmc/universe.py
@@ -12,9 +12,12 @@ import numpy as np
import openmc
import openmc.checkvalue as cv
+
from ._xml import get_text
+from .checkvalue import check_type, check_value
from .mixin import IDManagerMixin
from .plots import _SVG_COLORS
+from .surface import _BOUNDARY_TYPES
class UniverseBase(ABC, IDManagerMixin):
@@ -713,6 +716,78 @@ class DAGMCUniverse(UniverseBase):
dagmc_element.set('filename', self.filename)
xml_element.append(dagmc_element)
+ def bounding_region(self, bounded_type='box', boundary_type='vacuum'):
+ """Creates a either a spherical or box shaped bounding region around
+ the DAGMC geometry.
+ Parameters
+ ----------
+ bounded_type : str
+ The type of bounding surface(s) to use when constructing the region.
+ Options include a single spherical surface (sphere) or a rectangle
+ made from six planes (box).
+ boundary_type : str
+ Boundary condition that defines the behavior for particles hitting
+ the surface. Defaults to vacuum boundary condition. Passed into the
+ surface construction.
+ Returns
+ -------
+ openmc.Region
+ Region instance
+ """
+
+ check_type('boundary type', boundary_type, str)
+ check_value('boundary type', boundary_type, _BOUNDARY_TYPES)
+ check_type('bounded type', bounded_type, str)
+ check_value('bounded type', bounded_type, ('box', 'sphere'))
+
+ bounding_box = self.bounding_box
+
+ if bounded_type == 'sphere':
+ import math
+ bounding_box_center = (bounding_box[0] + bounding_box[1])/2
+ radius = math.dist(bounding_box[0], bounding_box[1])
+ bounding_surface = openmc.Sphere(
+ x0=bounding_box_center[0],
+ y0=bounding_box_center[1],
+ z0=bounding_box_center[2],
+ boundary_type=boundary_type,
+ r=radius,
+ )
+
+ return -bounding_surface
+
+ if bounded_type == 'box':
+ # defines plane surfaces for all six faces of the bounding box
+ lower_x = openmc.XPlane(bounding_box[0][0], boundary_type=boundary_type)
+ upper_x = openmc.XPlane(bounding_box[1][0], boundary_type=boundary_type)
+ lower_y = openmc.YPlane(bounding_box[0][1], boundary_type=boundary_type)
+ upper_y = openmc.YPlane(bounding_box[1][1], boundary_type=boundary_type)
+ lower_z = openmc.ZPlane(bounding_box[0][2], boundary_type=boundary_type)
+ upper_z = openmc.ZPlane(bounding_box[1][2], boundary_type=boundary_type)
+
+ return +lower_x & -upper_x & +lower_y & -upper_y & +lower_z & -upper_z
+
+ def bounded_universe(self, bounding_cell_id=10000, **kwargs):
+ """Returns an openmc.Universe filled with this DAGMCUniverse and bounded
+ with a cell. Defaults to a box cell with a vacuum surface however this
+ can be changed using the kwargs which are passed directly to
+ DAGMCUniverse.bounding_region().
+
+ Parameters
+ ----------
+ bounding_cell_id : int
+ The cell ID number to use for the bounding cell, defaults to 1000 to reduce
+ the chance of overlapping ID numbers with the DAGMC geometry.
+
+ Returns
+ -------
+ openmc.Universe
+ Universe instance
+ """
+
+ bounding_cell = openmc.Cell(fill=self, cell_id =bounding_cell_id, region=self.bounding_region(**kwargs))
+ return openmc.Universe(cells=[bounding_cell])
+
@classmethod
def from_hdf5(cls, group):
"""Create DAGMC universe from HDF5 group
diff --git a/src/dagmc.cpp b/src/dagmc.cpp
index 8ce5aabdad..dc3bc2b2ce 100644
--- a/src/dagmc.cpp
+++ b/src/dagmc.cpp
@@ -183,7 +183,9 @@ void DAGUniverse::init_geometry()
} else {
warning(fmt::format("DAGMC Cell IDs: {}", dagmc_ids_for_dim(3)));
fatal_error(fmt::format("Cell ID {} exists in both DAGMC Universe {} "
- "and the CSG geometry.",
+ "and the CSG geometry. Setting auto_geom_ids "
+ "to True when initiating the DAGMC Universe may "
+ "resolve this issue",
c->id_, this->id_));
}
diff --git a/tests/regression_tests/dagmc/universes/inputs_true.dat b/tests/regression_tests/dagmc/universes/inputs_true.dat
index 4443f9a35d..2165a78b6c 100644
--- a/tests/regression_tests/dagmc/universes/inputs_true.dat
+++ b/tests/regression_tests/dagmc/universes/inputs_true.dat
@@ -1,8 +1,8 @@
- |
+ |
-
+
24.0 24.0
2 2
-24.0 -24.0
@@ -10,12 +10,12 @@
9 9
9 9
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/tests/regression_tests/dagmc/universes/test.py b/tests/regression_tests/dagmc/universes/test.py
index 6726b4b448..f2eb3882f2 100644
--- a/tests/regression_tests/dagmc/universes/test.py
+++ b/tests/regression_tests/dagmc/universes/test.py
@@ -46,11 +46,32 @@ class DAGMCUniverseTest(PyAPITestHarness):
# create the DAGMC universe
pincell_univ = openmc.DAGMCUniverse(filename='dagmc.h5m', auto_geom_ids=True)
+ # creates another DAGMC universe, this time with within a bounded cell
+ bound_pincell_universe = openmc.DAGMCUniverse(filename='dagmc.h5m').bounded_universe()
+ # uses the bound_dag_cell as the root argument to test the type checks in openmc.Geometry
+ bound_pincell_geometry = openmc.Geometry(root=bound_pincell_universe)
+ # assigns the bound_dag_geometry to the model to test the type checks in model.Geometry setter
+ model.Geometry = bound_pincell_geometry
+
# checks that the bounding box is calculated correctly
bounding_box = pincell_univ.bounding_box
assert bounding_box[0].tolist() == [-25., -25., -25.]
assert bounding_box[1].tolist() == [25., 25., 25.]
+ # checks that the bounding region is six surfaces each with a vacuum boundary type
+ b_region = pincell_univ.bounding_region(bounded_type='box', boundary_type='vacuum')
+ assert isinstance(b_region, openmc.Region)
+ assert len(b_region.get_surfaces()) == 6
+ for surface in list(b_region.get_surfaces().values()):
+ assert surface.boundary_type == 'vacuum'
+
+ # checks that the bounding region is a single surface with a reflective boundary type
+ b_region = pincell_univ.bounding_region(bounded_type='sphere', boundary_type='reflective')
+ assert isinstance(b_region, openmc.Region)
+ assert len(b_region.get_surfaces()) == 1
+ for surface in list(b_region.get_surfaces().values()):
+ assert surface.boundary_type == 'reflective'
+
# create a 2 x 2 lattice using the DAGMC pincell
pitch = np.asarray((24.0, 24.0))
lattice = openmc.RectLattice()