Skip to content

Commit 42b8e3d

Browse files
authored
Merge pull request #11 from openmc-dev/develop
Update with latest develop before open pr
2 parents 6eb6651 + 7b0eb9d commit 42b8e3d

File tree

17 files changed

+405
-82
lines changed

17 files changed

+405
-82
lines changed

include/openmc/dagmc.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class DAGSurface : public Surface {
3737
public:
3838
DAGSurface(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx);
3939

40+
moab::EntityHandle mesh_handle() const;
41+
4042
double evaluate(Position r) const override;
4143
double distance(Position r, Direction u, bool coincident) const override;
4244
Direction normal(Position r) const override;
@@ -45,7 +47,7 @@ class DAGSurface : public Surface {
4547
inline void to_hdf5_inner(hid_t group_id) const override {};
4648

4749
// Accessor methods
48-
const std::shared_ptr<moab::DagMC>& dagmc_ptr() const { return dagmc_ptr_; }
50+
moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); }
4951
int32_t dag_index() const { return dag_index_; }
5052

5153
private:
@@ -57,6 +59,8 @@ class DAGCell : public Cell {
5759
public:
5860
DAGCell(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx);
5961

62+
moab::EntityHandle mesh_handle() const;
63+
6064
bool contains(Position r, Direction u, int32_t on_surface) const override;
6165

6266
std::pair<double, int32_t> distance(
@@ -67,7 +71,7 @@ class DAGCell : public Cell {
6771
void to_hdf5_inner(hid_t group_id) const override;
6872

6973
// Accessor methods
70-
const std::shared_ptr<moab::DagMC>& dagmc_ptr() const { return dagmc_ptr_; }
74+
moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); }
7175
int32_t dag_index() const { return dag_index_; }
7276

7377
private:
@@ -122,6 +126,16 @@ class DAGUniverse : public Universe {
122126
void legacy_assign_material(
123127
std::string mat_string, std::unique_ptr<DAGCell>& c) const;
124128

129+
//! Return the index into the model cells vector for a given DAGMC volume
130+
//! handle in the universe
131+
//! \param[in] vol MOAB handle to the DAGMC volume set
132+
int32_t cell_index(moab::EntityHandle vol) const;
133+
134+
//! Return the index into the model surfaces vector for a given DAGMC surface
135+
//! handle in the universe
136+
//! \param[in] surf MOAB handle to the DAGMC surface set
137+
int32_t surface_index(moab::EntityHandle surf) const;
138+
125139
//! Generate a string representing the ranges of IDs present in the DAGMC
126140
//! model. Contiguous chunks of IDs are represented as a range (i.e. 1-10). If
127141
//! there is a single ID a chunk, it will be represented as a single number
@@ -142,6 +156,7 @@ class DAGUniverse : public Universe {
142156
//!< universe in OpenMC's surface vector
143157

144158
// Accessors
159+
moab::DagMC* dagmc_ptr() const { return dagmc_instance_.get(); }
145160
bool has_graveyard() const { return has_graveyard_; }
146161

147162
private:

openmc/deplete/chain.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -686,16 +686,16 @@ def form_matrix(self, rates, fission_yields=None):
686686
dict.update(matrix_dok, matrix)
687687
return matrix_dok.tocsr()
688688

689-
def form_rr_term(self, transfer_rates, materials):
689+
def form_rr_term(self, tr_rates, mats):
690690
"""Function to form the transfer rate term matrices.
691691
692692
.. versionadded:: 0.13.4
693693
694694
Parameters
695695
----------
696-
transfer_rates : openmc.deplete.TransferRates
696+
tr_rates : openmc.deplete.TransferRates
697697
Instance of openmc.deplete.TransferRates
698-
materials : string or two-tuple of strings
698+
mats : string or two-tuple of strings
699699
Two cases are possible:
700700
701701
1) Material ID as string:
@@ -719,25 +719,27 @@ def form_rr_term(self, transfer_rates, materials):
719719
"""
720720
matrix = defaultdict(float)
721721

722-
for i, nuclide in enumerate(self.nuclides):
723-
element = re.split(r'\d+', nuclide.name)[0]
722+
for i, nuc in enumerate(self.nuclides):
723+
elm = re.split(r'\d+', nuc.name)[0]
724724
# Build transfer terms matrices
725-
if isinstance(materials, str):
726-
material = materials
727-
components = transfer_rates.get_components(material)
728-
if element in components:
729-
matrix[i, i] = transfer_rates.get_transfer_rate(material, element)
730-
elif nuclide.name in components:
731-
matrix[i, i] = transfer_rates.get_transfer_rate(material, nuclide.name)
725+
if isinstance(mats, str):
726+
mat = mats
727+
components = tr_rates.get_components(mat)
728+
if elm in components:
729+
matrix[i, i] = sum(tr_rates.get_transfer_rate(mat, elm))
730+
elif nuc.name in components:
731+
matrix[i, i] = sum(tr_rates.get_transfer_rate(mat, nuc.name))
732732
else:
733733
matrix[i, i] = 0.0
734734
#Build transfer terms matrices
735-
elif isinstance(materials, tuple):
736-
destination_material, material = materials
737-
if transfer_rates.get_destination_material(material, element) == destination_material:
738-
matrix[i, i] = transfer_rates.get_transfer_rate(material, element)
739-
elif transfer_rates.get_destination_material(material, nuclide.name) == destination_material:
740-
matrix[i, i] = transfer_rates.get_transfer_rate(material, nuclide.name)
735+
elif isinstance(mats, tuple):
736+
dest_mat, mat = mats
737+
if dest_mat in tr_rates.get_destination_material(mat, elm):
738+
dest_mat_idx = tr_rates.get_destination_material(mat, elm).index(dest_mat)
739+
matrix[i, i] = tr_rates.get_transfer_rate(mat, elm)[dest_mat_idx]
740+
elif dest_mat in tr_rates.get_destination_material(mat, nuc.name):
741+
dest_mat_idx = tr_rates.get_destination_material(mat, nuc.name).index(dest_mat)
742+
matrix[i, i] = tr_rates.get_transfer_rate(mat, nuc.name)[dest_mat_idx]
741743
else:
742744
matrix[i, i] = 0.0
743745
#Nothing else is allowed

openmc/deplete/coupled_operator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def _generate_materials_xml(self):
416416
for mat in self.materials:
417417
mat._nuclides.sort(key=lambda x: nuclides.index(x[0]))
418418

419-
self.materials.export_to_xml()
419+
self.materials.export_to_xml(nuclides_to_ignore=self._decay_nucs)
420420

421421
def __call__(self, vec, source_rate):
422422
"""Runs a simulation.

openmc/deplete/openmc_operator.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
from abc import abstractmethod
9+
from warnings import warn
910
from typing import List, Tuple, Dict
1011

1112
import numpy as np
@@ -133,6 +134,18 @@ def __init__(
133134
# This nuclides variables contains every nuclides
134135
# for which there is an entry in the micro_xs parameter
135136
openmc.reset_auto_ids()
137+
138+
self.nuclides_with_data = self._get_nuclides_with_data(
139+
self.cross_sections)
140+
141+
# Select nuclides with data that are also in the chain
142+
self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides
143+
if nuc.name in self.nuclides_with_data]
144+
145+
# Select nuclides without data that are also in the chain
146+
self._decay_nucs = [nuc.name for nuc in self.chain.nuclides
147+
if nuc.name not in self.nuclides_with_data]
148+
136149
self.burnable_mats, volumes, all_nuclides = self._get_burnable_mats()
137150
self.local_mats = _distribute(self.burnable_mats)
138151

@@ -142,13 +155,6 @@ def __init__(
142155
if self.prev_res is not None:
143156
self._load_previous_results()
144157

145-
self.nuclides_with_data = self._get_nuclides_with_data(
146-
self.cross_sections)
147-
148-
# Select nuclides with data that are also in the chain
149-
self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides
150-
if nuc.name in self.nuclides_with_data]
151-
152158
# Extract number densities from the geometry / previous depletion run
153159
self._extract_number(self.local_mats,
154160
volumes,
@@ -171,7 +177,7 @@ def _get_burnable_mats(self) -> Tuple[List[str], Dict[str, float], List[str]]:
171177
Returns
172178
-------
173179
burnable_mats : list of str
174-
List of burnable material IDs
180+
list of burnable material IDs
175181
volume : dict of str to float
176182
Volume of each material in [cm^3]
177183
nuclides : list of str
@@ -188,7 +194,13 @@ def _get_burnable_mats(self) -> Tuple[List[str], Dict[str, float], List[str]]:
188194
# Iterate once through the geometry to get dictionaries
189195
for mat in self.materials:
190196
for nuclide in mat.get_nuclides():
191-
model_nuclides.add(nuclide)
197+
if nuclide in self.nuclides_with_data or self._decay_nucs:
198+
model_nuclides.add(nuclide)
199+
else:
200+
msg = (f"Nuclilde {nuclide} in material {mat.id} is not "
201+
"present in the depletion chain and has no cross "
202+
"section data.")
203+
raise warn(msg)
192204
if mat.depletable:
193205
burnable_mats.add(str(mat.id))
194206
if mat.volume is None:

openmc/deplete/transfer_rates.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ def get_transfer_rate(self, material, component):
9191
9292
Returns
9393
-------
94-
transfer_rate : float
95-
Transfer rate value
94+
transfer_rate : list of floats
95+
Transfer rate values
9696
9797
"""
9898
material_id = self._get_material_id(material)
9999
check_type('component', component, str)
100-
return self.transfer_rates[material_id][component][0]
100+
return [i[0] for i in self.transfer_rates[material_id][component]]
101101

102102
def get_destination_material(self, material, component):
103103
"""Return destination material for given material and
@@ -112,15 +112,17 @@ def get_destination_material(self, material, component):
112112
113113
Returns
114114
-------
115-
destination_material_id : str
115+
destination_material_id : list of str
116116
Depletable material ID to where the element or nuclide gets
117117
transferred
118118
119119
"""
120120
material_id = self._get_material_id(material)
121121
check_type('component', component, str)
122122
if component in self.transfer_rates[material_id]:
123-
return self.transfer_rates[material_id][component][1]
123+
return [i[1] for i in self.transfer_rates[material_id][component]]
124+
else:
125+
return []
124126

125127
def get_components(self, material):
126128
"""Extract removing elements and/or nuclides for a given material
@@ -217,7 +219,11 @@ def set_transfer_rate(self, material, components, transfer_rate,
217219
f'where element {element} already has '
218220
'a transfer rate.')
219221

220-
self.transfer_rates[material_id][component] = \
221-
transfer_rate / unit_conv, destination_material_id
222+
if component in self.transfer_rates[material_id]:
223+
self.transfer_rates[material_id][component].append(
224+
(transfer_rate / unit_conv, destination_material_id))
225+
else:
226+
self.transfer_rates[material_id][component] = [
227+
(transfer_rate / unit_conv, destination_material_id)]
222228
if destination_material_id is not None:
223229
self.index_transfer.add((destination_material_id, material_id))

openmc/material.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ def clone(self, memo: Optional[dict] = None) -> Material:
12501250

12511251
return memo[self]
12521252

1253-
def _get_nuclide_xml(self, nuclide: str) -> ET.Element:
1253+
def _get_nuclide_xml(self, nuclide: NuclideTuple) -> ET.Element:
12541254
xml_element = ET.Element("nuclide")
12551255
xml_element.set("name", nuclide.name)
12561256

@@ -1267,15 +1267,28 @@ def _get_macroscopic_xml(self, macroscopic: str) -> ET.Element:
12671267

12681268
return xml_element
12691269

1270-
def _get_nuclides_xml(self, nuclides: typing.Iterable[str]) -> List[ET.Element]:
1270+
def _get_nuclides_xml(
1271+
self, nuclides: typing.Iterable[NuclideTuple],
1272+
nuclides_to_ignore: Optional[typing.Iterable[str]] = None)-> List[ET.Element]:
12711273
xml_elements = []
1272-
for nuclide in nuclides:
1273-
xml_elements.append(self._get_nuclide_xml(nuclide))
1274+
1275+
# Remove any nuclides to ignore from the XML export
1276+
if nuclides_to_ignore:
1277+
nuclides = [nuclide for nuclide in nuclides if nuclide.name not in nuclides_to_ignore]
1278+
1279+
xml_elements = [self._get_nuclide_xml(nuclide) for nuclide in nuclides]
1280+
12741281
return xml_elements
12751282

1276-
def to_xml_element(self) -> ET.Element:
1283+
def to_xml_element(
1284+
self, nuclides_to_ignore: Optional[typing.Iterable[str]] = None) -> ET.Element:
12771285
"""Return XML representation of the material
12781286
1287+
Parameters
1288+
----------
1289+
nuclides_to_ignore : list of str
1290+
Nuclides to ignore when exporting to XML.
1291+
12791292
Returns
12801293
-------
12811294
element : lxml.etree._Element
@@ -1320,7 +1333,8 @@ def to_xml_element(self) -> ET.Element:
13201333

13211334
if self._macroscopic is None:
13221335
# Create nuclide XML subelements
1323-
subelements = self._get_nuclides_xml(self._nuclides)
1336+
subelements = self._get_nuclides_xml(self._nuclides,
1337+
nuclides_to_ignore=nuclides_to_ignore)
13241338
for subelement in subelements:
13251339
element.append(subelement)
13261340
else:
@@ -1576,7 +1590,8 @@ def make_isotropic_in_lab(self):
15761590
for material in self:
15771591
material.make_isotropic_in_lab()
15781592

1579-
def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_indent=True):
1593+
def _write_xml(self, file, header=True, level=0, spaces_per_level=2,
1594+
trailing_indent=True, nuclides_to_ignore=None):
15801595
"""Writes XML content of the materials to an open file handle.
15811596
15821597
Parameters
@@ -1591,6 +1606,8 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_in
15911606
Number of spaces per indentation
15921607
trailing_indentation : bool
15931608
Whether or not to write a trailing indentation for the materials element
1609+
nuclides_to_ignore : list of str
1610+
Nuclides to ignore when exporting to XML.
15941611
15951612
"""
15961613
indentation = level*spaces_per_level*' '
@@ -1611,7 +1628,7 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_in
16111628

16121629
# Write the <material> elements.
16131630
for material in sorted(self, key=lambda x: x.id):
1614-
element = material.to_xml_element()
1631+
element = material.to_xml_element(nuclides_to_ignore=nuclides_to_ignore)
16151632
clean_indentation(element, level=level+1)
16161633
element.tail = element.tail.strip(' ')
16171634
file.write((level+1)*spaces_per_level*' ')
@@ -1626,13 +1643,16 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_in
16261643
if trailing_indent:
16271644
file.write(indentation)
16281645

1629-
def export_to_xml(self, path: PathLike = 'materials.xml'):
1646+
def export_to_xml(self, path: PathLike = 'materials.xml',
1647+
nuclides_to_ignore: Optional[typing.Iterable[str]] = None):
16301648
"""Export material collection to an XML file.
16311649
16321650
Parameters
16331651
----------
16341652
path : str
16351653
Path to file to write. Defaults to 'materials.xml'.
1654+
nuclides_to_ignore : list of str
1655+
Nuclides to ignore when exporting to XML.
16361656
16371657
"""
16381658
# Check if path is a directory
@@ -1645,7 +1665,7 @@ def export_to_xml(self, path: PathLike = 'materials.xml'):
16451665
# one go.
16461666
with open(str(p), 'w', encoding='utf-8',
16471667
errors='xmlcharrefreplace') as fh:
1648-
self._write_xml(fh)
1668+
self._write_xml(fh, nuclides_to_ignore=nuclides_to_ignore)
16491669

16501670
@classmethod
16511671
def from_xml_element(cls, elem) -> Material:

openmc/region.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import numpy as np
66

7-
from .checkvalue import check_type
87
from .bounding_box import BoundingBox
98

109

@@ -362,6 +361,9 @@ class Intersection(Region, MutableSequence):
362361

363362
def __init__(self, nodes):
364363
self._nodes = list(nodes)
364+
for node in nodes:
365+
if not isinstance(node, Region):
366+
raise ValueError('Intersection operands must be of type Region')
365367

366368
def __and__(self, other):
367369
new = Intersection(self)
@@ -450,6 +452,9 @@ class Union(Region, MutableSequence):
450452

451453
def __init__(self, nodes):
452454
self._nodes = list(nodes)
455+
for node in nodes:
456+
if not isinstance(node, Region):
457+
raise ValueError('Union operands must be of type Region')
453458

454459
def __or__(self, other):
455460
new = Union(self)
@@ -566,7 +571,8 @@ def node(self):
566571

567572
@node.setter
568573
def node(self, node):
569-
check_type('node', node, Region)
574+
if not isinstance(node, Region):
575+
raise ValueError('Complement operand must be of type Region')
570576
self._node = node
571577

572578
@property

0 commit comments

Comments
 (0)