Skip to content

Commit

Permalink
Merge pull request #2412 from paulromano/material-volume-args
Browse files Browse the repository at this point in the history
Add volume arguments on several methods in Material class
  • Loading branch information
shimwell authored Mar 17, 2023
2 parents 691f44f + 3e6441a commit d678b39
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
50 changes: 40 additions & 10 deletions openmc/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,8 @@ def get_nuclide_atom_densities(self, nuclide: Optional[str] = None):

return nuclides

def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False):
def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False,
volume: Optional[float] = None):
"""Returns the activity of the material or for each nuclide in the
material in units of [Bq], [Bq/g] or [Bq/cm3].
Expand All @@ -1044,6 +1045,11 @@ def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False):
by_nuclide : bool
Specifies if the activity should be returned for the material as a
whole or per nuclide. Default is False.
volume : float, optional
Volume of the material. If not passed, defaults to using the
:attr:`Material.volume` attribute.
.. versionadded:: 0.13.3
Returns
-------
Expand All @@ -1057,7 +1063,7 @@ def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False):
cv.check_type('by_nuclide', by_nuclide, bool)

if units == 'Bq':
multiplier = self.volume
multiplier = volume if volume is not None else self.volume
elif units == 'Bq/cm3':
multiplier = 1
elif units == 'Bq/g':
Expand All @@ -1070,7 +1076,8 @@ def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False):

return activity if by_nuclide else sum(activity.values())

def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False):
def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False,
volume: Optional[float] = None):
"""Returns the decay heat of the material or for each nuclide in the
material in units of [W], [W/g] or [W/cm3].
Expand All @@ -1085,6 +1092,11 @@ def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False):
by_nuclide : bool
Specifies if the decay heat should be returned for the material as a
whole or per nuclide. Default is False.
volume : float, optional
Volume of the material. If not passed, defaults to using the
:attr:`Material.volume` attribute.
.. versionadded:: 0.13.3
Returns
-------
Expand All @@ -1098,7 +1110,7 @@ def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False):
cv.check_type('by_nuclide', by_nuclide, bool)

if units == 'W':
multiplier = self.volume
multiplier = volume if volume is not None else self.volume
elif units == 'W/cm3':
multiplier = 1
elif units == 'W/g':
Expand All @@ -1113,23 +1125,33 @@ def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False):

return decayheat if by_nuclide else sum(decayheat.values())

def get_nuclide_atoms(self):
def get_nuclide_atoms(self, volume: Optional[float] = None):
"""Return number of atoms of each nuclide in the material
.. versionadded:: 0.13.1
Parameters
----------
volume : float, optional
Volume of the material. If not passed, defaults to using the
:attr:`Material.volume` attribute.
.. versionadded:: 0.13.3
Returns
-------
dict
Dictionary whose keys are nuclide names and values are number of
atoms present in the material.
"""
if self.volume is None:
if volume is None:
volume = self.volume
if volume is None:
raise ValueError("Volume must be set in order to determine atoms.")
atoms = {}
for nuclide, atom_per_bcm in self.get_nuclide_atom_densities().items():
atoms[nuclide] = 1.0e24 * atom_per_bcm * self.volume
atoms[nuclide] = 1.0e24 * atom_per_bcm * volume
return atoms

def get_mass_density(self, nuclide: Optional[str] = None):
Expand All @@ -1154,7 +1176,7 @@ def get_mass_density(self, nuclide: Optional[str] = None):
mass_density += density_i
return mass_density

def get_mass(self, nuclide: Optional[str] = None):
def get_mass(self, nuclide: Optional[str] = None, volume: Optional[float] = None):
"""Return mass of one or all nuclides.
Note that this method requires that the :attr:`Material.volume` has
Expand All @@ -1165,16 +1187,24 @@ def get_mass(self, nuclide: Optional[str] = None):
nuclides : str, optional
Nuclide for which mass is desired. If not specified, the density
for the entire material is given.
volume : float, optional
Volume of the material. If not passed, defaults to using the
:attr:`Material.volume` attribute.
.. versionadded:: 0.13.3
Returns
-------
float
Mass of the nuclide/material in [g]
"""
if self.volume is None:
if volume is None:
volume = self.volume
if volume is None:
raise ValueError("Volume must be set in order to determine mass.")
return self.volume*self.get_mass_density(nuclide)
return volume*self.get_mass_density(nuclide)

def clone(self, memo: Optional[dict] = None):
"""Create a copy of this material with a new unique ID.
Expand Down
2 changes: 1 addition & 1 deletion openmc/model/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def from_xml(cls, geometry='geometry.xml', materials='materials.xml',
def from_model_xml(cls, path='model.xml'):
"""Create model from single XML file
.. vesionadded:: 0.13.3
.. versionadded:: 0.13.3
Parameters
----------
Expand Down
16 changes: 14 additions & 2 deletions tests/unit_tests/test_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,9 @@ def test_get_nuclide_atoms():
atoms = mat.get_nuclide_atoms()
assert atoms['Li6'] == pytest.approx(mat.density * mat.volume)

atoms = mat.get_nuclide_atoms(volume=10.0)
assert atoms['Li6'] == pytest.approx(mat.density * 10.0)


def test_mass():
m = openmc.Material()
Expand All @@ -394,6 +397,9 @@ def test_mass():
assert m.get_mass() == pytest.approx(20.0)
assert m.fissionable_mass == pytest.approx(10.0)

# Test with volume specified as argument
assert m.get_mass('Zr90', volume=1.0) == pytest.approx(1.0)


def test_materials(run_in_tmpdir):
m1 = openmc.Material()
Expand Down Expand Up @@ -544,11 +550,14 @@ def test_get_activity():
m4.volume = 10.
assert pytest.approx(m4.get_activity(units='Bq')) == 355978108155965.94*3/2*10 # [Bq]

# Test with volume specified as argument
assert pytest.approx(m4.get_activity(units='Bq', volume=1.0)) == 355978108155965.94*3/2


def test_get_decay_heat():
# Set chain file for testing
openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml'

"""Tests the decay heat of stable, metastable and active materials"""
m1 = openmc.Material()
m1.add_nuclide("U235", 0.2)
Expand Down Expand Up @@ -589,7 +598,10 @@ def test_get_decay_heat():
# volume is required to calculate total decay heat
m4.volume = 10.
assert pytest.approx(m4.get_decay_heat(units='W')) == 40175.15720273193*3/2*10 # [W]


# Test with volume specified as argument
assert pytest.approx(m4.get_decay_heat(units='W', volume=1.0)) == 40175.15720273193*3/2


def test_decay_photon_energy():
# Set chain file for testing
Expand Down

0 comments on commit d678b39

Please sign in to comment.