Skip to content

Commit

Permalink
adressing most @pshriwise comments
Browse files Browse the repository at this point in the history
  • Loading branch information
bam241 committed Sep 21, 2024
1 parent 6756288 commit c0680dd
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 44 deletions.
5 changes: 3 additions & 2 deletions include/openmc/capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ int openmc_cell_set_temperature(
int openmc_cell_set_translation(int32_t index, const double xyz[]);
int openmc_cell_set_rotation(int32_t index, const double rot[], size_t rot_len);
int openmc_get_dagmc_cell_ids(int32_t univ_id, int32_t* ids, size_t* n);
int openmc_energy_filter_get_bins(
int32_t index, const double** energies, size_t* n);
int openmc_dagmc_universe_get_num_cells(
int32_t univ_id, size_t* n) 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(
Expand Down
73 changes: 52 additions & 21 deletions openmc/dagmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class DAGMCUniverse(openmc.UniverseBase):
.. versionadded:: 0.15
material_overrides : dict
A dictionary of material overrides. The keys are material name
strings and the values are Iterables of openmc.Material objects. If a material name
is found in the DAGMC file, the material will be replaced with the
strings and the values are Iterables of openmc.Material objects. If a
material name is found in the DAGMC file, the material will be replaced with the
openmc.Material object in the value.
"""

Expand All @@ -85,7 +85,7 @@ def __init__(self,
name='',
auto_geom_ids=False,
auto_mat_ids=False,
mat_overrides={}):
mat_overrides=None):
super().__init__(universe_id, name)
# Initialize class attributes
self.filename = filename
Expand All @@ -112,6 +112,17 @@ def bounding_box(self):
def filename(self):
return self._filename

@property
def material_overrides(self):
return self._material_overrides

@material_overrides.setter
def material_overrides(self, val):
if val is not None:
cv.check_type('material overrides', val, dict)

self._material_overrides = val

@filename.setter
def filename(self, val):
cv.check_type('DAGMC filename', val, (Path, str))
Expand Down Expand Up @@ -216,7 +227,7 @@ def create_xml_subelement(self, xml_element, memo=None):
if self.auto_mat_ids:
dagmc_element.set('auto_mat_ids', 'true')
dagmc_element.set('filename', str(self.filename))
if len(self.material_overrides) == 0:
if not self.material_overrides:
mats = self.get_all_materials()
for mat in mats.values():
if mat.name[:-4] in self.material_names:
Expand Down Expand Up @@ -379,6 +390,12 @@ def from_xml_element(cls, elem):
out.auto_geom_ids = bool(elem.get('auto_geom_ids'))
out.auto_mat_ids = bool(elem.get('auto_mat_ids'))

for item in elem.find('material_overrides').attrib:
origin_mat, overwrite = item
for mat_name in overwrite.split():
out.material_overrides.setdefault(
origin_mat.lower(), []).append(mat_name)

return out

def _partial_deepcopy(self):
Expand All @@ -402,8 +419,8 @@ def add_cell(self, cell):
"""
if not isinstance(cell, openmc.DAGMCCell):
msg = f'Unable to add a DAGMCCell to DAGMCUniverse ID="{self._id}" since ' \
f'"{cell}" is not a DAGMCCell'
msg = f'Unable to add a DAGMCCell to DAGMCUniverse ' \
f'ID="{self._id}" since "{cell}" is not a DAGMCCell'
raise TypeError(msg)

cell_id = cell.id
Expand Down Expand Up @@ -437,11 +454,19 @@ def sync_dagmc_cells(self, mats={}):
"""
import openmc.lib
if not openmc.lib.is_initialized:
raise RuntimeError("This universe must be part of an openmc.Model initialized via Model.init_lib "
"before calling this method.")
raise RuntimeError("This universe must be part of an openmc.Model "
"initialized via Model.init_lib before calling "
"this method.")

dagmc_cell_ids = openmc.lib.dagmc.get_dagmc_cell_ids(self.id)
if len(dagmc_cell_ids) != self.n_cells:
raise ValueError(
f"Number of cells in DAGMC universe {self.id} does not match "
f"the number of cells in the Python universe."
)

mats_per_id = {mat.id: mat for mat in mats}
for dag_cell_id in openmc.lib.dagmc.get_dagmc_cell_ids(self.id, self.n_cells):
for dag_cell_id in dagmc_cell_ids:
dag_cell = openmc.lib.cells[dag_cell_id]
if isinstance(dag_cell.fill, Iterable):
fill = [mats_per_id[mat_id.id]
Expand All @@ -461,22 +486,21 @@ class DAGMCCell(openmc.Cell):
Parameters
----------
cell_id : int or None, optional
Unique identifier for the cell. If None, an identifier will be automatically assigned.
Unique identifier for the cell. If None, an identifier will be
automatically assigned.
name : str, optional
Name of the cell.
fill : openmc.Material or None, optional
Material filling the cell. If None, the cell is filled with vacuum.
region : openmc.Region or None, optional
Region of space that the cell occupies. If None, the cell is filled with vacuum.
Attributes
----------
DAG_parent_universe : int
The parent universe of the cell.
"""
def __init__(self, cell_id=None, name='', fill=None, region=None):
super().__init__(cell_id, name, fill, region)
def __init__(self, cell_id=None, name='', fill=None):
super().__init__(cell_id, name, fill, None)

@property
def DAG_parent_universe(self):
Expand All @@ -489,30 +513,37 @@ def DAG_parent_universe(self, universe):
self._parent_universe = universe.id

def boundingbox(self):
warnings.warn("Bounding box is not available for cells in a DAGMC universe", Warning)
warnings.warn("Bounding box is not available for cells in a DAGMC "
"universe", Warning)
return BoundingBox.infinite()

def get_all_cells(self, memo=None):
warnings.warn("get_all_cells is not available for cells in a DAGMC universe", Warning)
warnings.warn("get_all_cells is not available for cells in a DAGMC "
"universe", Warning)
return {}

def get_all_universes(self, memo=None):
warnings.warn("get_all_universes is not available for cells in a DAGMC universe", Warning)
warnings.warn("get_all_universes is not available for cells in a "
"DAGMC universe", Warning)
return {}

def clone(self, clone_materials=True, clone_regions=True, memo=None):
warnings.warn("clone is not available for cells in a DAGMC universe", Warning)
warnings.warn("clone is not available for cells in a DAGMC universe",
Warning)
return None

def plot(self, *args, **kwargs):
warnings.warn("plot is not available for cells in a DAGMC universe", Warning)
warnings.warn("plot is not available for cells in a DAGMC universe",
Warning)
return None

def create_xml_subelement(self, xml_element, memo=None):
warnings.warn("create_xml_subelement is not available for cells in a DAGMC universe", Warning)
warnings.warn("create_xml_subelement is not available for cells in a "
"DAGMC universe", Warning)
return None

@classmethod
def from_xml_element(cls, elem, surfaces, materials, get_universe):
warnings.warn("from_xml_element is not available for cells in a DAGMC universe", Warning)
warnings.warn("from_xml_element is not available for cells in a DAGMC "
"universe", Warning)
return None
40 changes: 30 additions & 10 deletions openmc/lib/dagmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,52 @@
_dll.openmc_get_dagmc_cell_ids.argtypes = [c_int32, POINTER(c_int32), POINTER(c_size_t)]
_dll.openmc_get_dagmc_cell_ids.restype = c_int
_dll.openmc_get_dagmc_cell_ids.errcheck = _error_handler
_dll.openmc_dagmc_universe_get_num_cells.argtypes = [c_int32, POINTER(c_size_t)]
_dll.openmc_dagmc_universe_get_num_cells.restype = c_int
_dll.openmc_dagmc_universe_get_num_cells.errcheck = _error_handler


def get_dagmc_cell_ids(volume_id, n_cells):
def get_dagmc_cell_ids(dagmc_id):
"""Get the DAGMC cell IDs for a volume.
Parameters
----------
volume_id : int
ID of the volume to get DAGMC cell IDs for.
dagmc_id : int
ID of the DAGMC Universe to get cell IDs from.
n_cells : int
Number of cells in the volume.
Number of cells in the DAGMC Universe.
Returns
-------
numpy.ndarray
DAGMC cell IDs for the volume.
"""
cell_ids = np.empty(n_cells, dtype=np.int32)
n = c_size_t()
_dll.openmc_dagmc_universe_get_num_cells(dagmc_id, n)
cell_ids = np.empty(n.value, dtype=np.int32)

_dll.openmc_get_dagmc_cell_ids(
volume_id,
dagmc_id,
cell_ids.ctypes.data_as(POINTER(c_int32)),
n
)
if n.value != n_cells:
raise ValueError(f"Number of cells obtained {n.value} from DAGMC does "
f"not match the expected number of cells {n_cells}.")
return cell_ids
return cell_ids
if
def get_dagmc_universe_num_cells(dagmc_id):
"""Get the number of cells in a DAGMC universe.
Parameters
----------
dagmc_id : int
ID of the DAGMC Universe to get the number of cell from.
Returns
-------
int
Number of cells in the DAGMC Universe.
"""
n = c_size_t()
_dll.openmc_dagmc_universe_get_num_cells(dagmc_id, n)
return n.value
30 changes: 19 additions & 11 deletions openmc/model/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,24 @@ def init_lib(self, threads=None, geometry_debug=False, restart_file=None,
# communicator
openmc.lib.init(args=args, intracomm=intracomm, output=output)

if self.materials:
mats = self.materials
def sync_dagmc_universe(self):
"""
Synchronize all DAGMC universes with the current geometry.
This method iterates over all DAGMC universes in the geometry and
synchronizes their cells with the current material assignments.
Returns:
None
"""
if self.is_initialized:
if self.materials:
mats = self.materials
else:
mats = self.geometry.get_all_materials().values()
for dagmc_universe in self.geometry.get_all_dagmc_universes().values():
dagmc_universe.sync_dagmc_cells(mats)
else:
mats = self.geometry.get_all_materials().values()
for dagmc_universe in self.geometry.get_all_dagmc_universes().values():
dagmc_universe.sync_dagmc_cells(mats)
raise ValueError("The model must be initialized before calling "
"this method")

def finalize_lib(self):
"""Finalize simulation and free memory allocated for the C API
Expand Down Expand Up @@ -1059,12 +1071,8 @@ def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bo

# Extract all depletable materials which have multiple instances
distribmats = set(
[
mat
for mat in self.materials
if (mat.depletable or not depletable_only) and mat.num_instances > 1
]
)
[mat for mat in self.materials
if mat.depletable and mat.num_instances > 1])

if diff_volume_method == "divide equally":
for mat in distribmats:
Expand Down
16 changes: 16 additions & 0 deletions src/dagmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,19 @@ extern "C" int openmc_get_dagmc_cell_ids(
*n = dag_cell_ids.size();
}

extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n)
{
// make sure the universe id is a DAGMC Universe
const auto& univ = model::universes[model::universe_map[univ_id]];
if (univ->geom_type() != GeometryType::DAG) {
fatal_error(
"Universe " + std::to_string(univ_id) + " is not a DAGMC Universe!");
}

std::vector<int32_t> dag_cell_ids;
*n = univ->cells_.size();
}

} // namespace openmc

#else
Expand All @@ -871,6 +884,9 @@ namespace openmc {
extern "C" int openmc_get_dagmc_cell_ids(
int32_t univ_id, int32_t* ids, size_t* n) {};

extern "C" int openmc_dagmc_universe_get_num_cells(
int32_t univ_id, size_t* n) {};

void read_dagmc_universes(pugi::xml_node node)
{
if (check_for_node(node, "dagmc_universe")) {
Expand Down
1 change: 1 addition & 0 deletions tests/unit_tests/dagmc/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def pattern(center, bc):
p = Path("differentiate_depletable_mats/divide_equally")
p.mkdir(parents=True, exist_ok=True)
model.init_lib()
model.sync_dagmc_universe()
model.calculate_volumes(cwd=p)
volume_before = np.sum([m.volume for m in model.materials if m.name == "Fuel"])
nmat = len(model.materials)
Expand Down

0 comments on commit c0680dd

Please sign in to comment.