mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 06:25:30 -04:00
Add decay heat function in material (#2287)
* add decay heat in material.py * add decay_energy.json into eggs * fix a bug when returned decay_ery is None * add unit test for decayheat * fix typo in doc string * address reviewer's comments * add user defined decay energy * remove json for decay energy * address a few comments * add to docs
This commit is contained in:
parent
7a6d8cc58f
commit
a17fe6cc82
5 changed files with 138 additions and 2 deletions
|
|
@ -63,6 +63,7 @@ Core Functions
|
|||
atomic_weight
|
||||
combine_distributions
|
||||
decay_constant
|
||||
decay_energy
|
||||
decay_photon_energy
|
||||
dose_coefficients
|
||||
gnd_name
|
||||
|
|
|
|||
|
|
@ -621,3 +621,49 @@ def decay_photon_energy(nuclide: str) -> Optional[Univariate]:
|
|||
"sources listed.")
|
||||
|
||||
return _DECAY_PHOTON_ENERGY.get(nuclide)
|
||||
|
||||
|
||||
_DECAY_ENERGY = {}
|
||||
|
||||
|
||||
def decay_energy(nuclide: str):
|
||||
"""Get decay energy value resulting from the decay of a nuclide
|
||||
|
||||
This function relies on data stored in a depletion chain. Before calling it
|
||||
for the first time, you need to ensure that a depletion chain has been
|
||||
specified in openmc.config['chain_file'].
|
||||
|
||||
.. versionadded:: 0.13.3
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclide : str
|
||||
Name of nuclide, e.g., 'H3'
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
Decay energy of nuclide in [eV]. If the nuclide is stable, a value of
|
||||
0.0 is returned.
|
||||
"""
|
||||
if not _DECAY_ENERGY:
|
||||
chain_file = openmc.config.get('chain_file')
|
||||
if chain_file is None:
|
||||
raise DataError(
|
||||
"A depletion chain file must be specified with "
|
||||
"openmc.config['chain_file'] in order to load decay data."
|
||||
)
|
||||
|
||||
from openmc.deplete import Chain
|
||||
chain = Chain.from_xml(chain_file)
|
||||
for nuc in chain.nuclides:
|
||||
if nuc.decay_energy:
|
||||
_DECAY_ENERGY[nuc.name] = nuc.decay_energy
|
||||
|
||||
# If the chain file contained no decay energy, warn the user
|
||||
if not _DECAY_ENERGY:
|
||||
warn(f"Chain file '{chain_file}' does not have any decay energy.")
|
||||
|
||||
return _DECAY_ENERGY.get(nuclide, 0.0)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -990,7 +990,50 @@ class Material(IDManagerMixin):
|
|||
activity[nuclide] = inv_seconds * 1e24 * atoms_per_bcm * multiplier
|
||||
|
||||
return activity if by_nuclide else sum(activity.values())
|
||||
|
||||
def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False):
|
||||
"""Returns the decay heat of the material or for each nuclide in the
|
||||
material in units of [W], [W/g] or [W/cm3].
|
||||
|
||||
.. versionadded:: 0.13.3
|
||||
|
||||
Parameters
|
||||
----------
|
||||
units : {'W', 'W/g', 'W/cm3'}
|
||||
Specifies the units of decay heat to return. Options include total
|
||||
heat [W], specific [W/g] or volumetric heat [W/cm3].
|
||||
Default is total heat [W].
|
||||
by_nuclide : bool
|
||||
Specifies if the decay heat should be returned for the material as a
|
||||
whole or per nuclide. Default is False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[dict, float]
|
||||
If `by_nuclide` is True then a dictionary whose keys are nuclide
|
||||
names and values are decay heat is returned. Otherwise the decay heat
|
||||
of the material is returned as a float.
|
||||
"""
|
||||
|
||||
cv.check_value('units', units, {'W', 'W/g', 'W/cm3'})
|
||||
cv.check_type('by_nuclide', by_nuclide, bool)
|
||||
|
||||
if units == 'W':
|
||||
multiplier = self.volume
|
||||
elif units == 'W/cm3':
|
||||
multiplier = 1
|
||||
elif units == 'W/g':
|
||||
multiplier = 1.0 / self.get_mass_density()
|
||||
|
||||
decayheat = {}
|
||||
for nuclide, atoms_per_bcm in self.get_nuclide_atom_densities().items():
|
||||
decay_erg = openmc.data.decay_energy(nuclide)
|
||||
inv_seconds = openmc.data.decay_constant(nuclide)
|
||||
decay_erg *= openmc.data.JOULE_PER_EV
|
||||
decayheat[nuclide] = inv_seconds * decay_erg * 1e24 * atoms_per_bcm * multiplier
|
||||
|
||||
return decayheat if by_nuclide else sum(decayheat.values())
|
||||
|
||||
def get_nuclide_atoms(self):
|
||||
"""Return number of atoms of each nuclide in the material
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<depletion_chain>
|
||||
<nuclide name="I135" decay_modes="1" reactions="1" half_life="2.36520E+04">
|
||||
<nuclide name="I135" decay_modes="1" reactions="1" half_life="2.36520E+04" decay_energy="1916827.5">
|
||||
<decay type="beta" target="Xe135" branching_ratio="1.0" />
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Xe136" /> <!-- Not precisely true, but whatever -->
|
||||
<source type="discrete" particle="photon">
|
||||
<parameters>3696.125 4095.822 4477.27 5097.122 29452.1 29781.3 33566.5 33629.4 33865.1 33878.5 34395.3 34408.0 34486.2 34488.2 112780.0 113150.0 162650.0 165740.0 184490.0 197190.0 220502.0 229720.0 247500.0 254740.0 264260.0 288451.0 290270.0 304910.0 305830.0 326000.0 333600.0 342520.0 361850.0 403030.0 414830.0 417633.0 429930.0 433741.0 451630.0 530800.0 546557.0 575970.0 588280.0 616900.0 649850.0 656090.0 679220.0 684600.0 690130.0 707920.0 785480.0 795500.0 797710.0 807200.0 836804.0 960290.0 961430.0 971960.0 972620.0 995090.0 1038760.0 1096860.0 1101580.0 1124000.0 1131511.0 1151510.0 1159900.0 1169040.0 1225600.0 1240470.0 1254800.0 1260409.0 1315770.0 1334800.0 1343660.0 1367890.0 1441800.0 1448350.0 1457560.0 1502790.0 1521990.0 1543700.0 1566410.0 1678027.0 1706459.0 1791196.0 1830690.0 1845300.0 1927300.0 1948490.0 2045880.0 2112400.0 2151500.0 2189400.0 2255457.0 2408650.0 2466070.0 2477100.0 9.714352819815078e-10 7.460941651551526e-09 6.047882056201745e-09 8.510389107205747e-10 3.7979729633684727e-08 7.033747061198817e-08 6.602815946851458e-09 1.2800909198245071e-08 6.513060244589454e-11 8.894667887850525e-11 1.3843783302275766e-09 2.700005498135763e-09 1.2141115256573815e-11 1.654893875618862e-11 3.7007705885806645e-09 2.0186021392258173e-09 2.859686363903241e-09 9.16781804898392e-09 6.896890642354875e-09 9.588360161322631e-09 5.130613770532286e-07 7.06510748729036e-08 8.410842246774237e-09 6.7286737974193905e-09 5.3829390379355124e-08 9.083709626516178e-07 8.915492781580693e-08 9.251926471451662e-09 2.783988783682273e-08 6.728673797419391e-10 1.093409492080651e-08 2.5232526740322717e-10 5.467047460403255e-08 6.812782219887132e-08 8.83138435911295e-08 1.0345335963532313e-06 8.915492781580693e-08 1.623292553627428e-07 9.251926471451663e-08 9.251926471451662e-09 2.0942997194467853e-06 3.784879011048407e-08 1.513951604419363e-08 1.093409492080651e-08 1.337323917237104e-07 2.186818984161302e-08 1.5980600268871052e-08 6.7286737974193905e-09 3.784879011048407e-08 1.9344937167580748e-07 4.457746390790346e-08 6.7286737974193905e-09 5.0465053480645434e-08 1.3457347594838781e-08 1.9597262434983976e-06 1.0093010696129087e-08 4.289529545854862e-08 2.607361096500014e-07 3.53255374364518e-07 4.541854813258089e-08 2.329803302356464e-06 2.607361096500014e-08 4.7100716581935733e-07 1.059766123093554e-06 6.6193328482113254e-06 4.205421123387119e-10 3.027903208838726e-08 2.565306885266143e-07 1.2616263370161358e-08 2.649415307733885e-07 3.3643368987096953e-09 8.410842246774237e-06 1.934493716758075e-08 9.251926471451662e-09 2.2709274066290446e-08 1.7830985563161385e-07 5.046505348064544e-09 9.251926471451663e-08 2.5400743585258203e-06 3.154065842540339e-07 1.093409492080651e-08 7.569758022096815e-09 3.784879011048407e-07 2.8008104681758214e-06 1.2027504412887161e-06 2.26251656438227e-06 1.6989901338483962e-07 1.6821684493548476e-09 8.663167514177466e-08 1.8503852942903323e-08 2.5568960430193683e-07 2.0186021392258175e-08 6.560456952483906e-09 3.784879011048407e-09 1.7999202408096872e-07 2.800810468175822e-07 2.1027105616935597e-08 4.205421123387119e-10</parameters>
|
||||
</source>
|
||||
</nuclide>
|
||||
<nuclide name="Xe135" decay_modes="1" reactions="1" half_life="3.29040E+04">
|
||||
<nuclide name="Xe135" decay_modes="1" reactions="1" half_life="3.29040E+04" decay_energy="567890.1">
|
||||
<decay type=" beta" target="Cs135" branching_ratio="1.0" />
|
||||
<reaction type="(n,gamma)" Q="0.0" target="Xe136" />
|
||||
<source type="tabular" interpolation="histogram" particle="photon">
|
||||
|
|
|
|||
|
|
@ -545,6 +545,52 @@ def test_get_activity():
|
|||
assert pytest.approx(m4.get_activity(units='Bq')) == 355978108155965.94*3/2*10 # [Bq]
|
||||
|
||||
|
||||
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)
|
||||
m1.add_nuclide("U238", 0.8)
|
||||
m1.set_density('g/cm3', 10.5)
|
||||
# decay heat in W/cc and W/g should not require volume setting
|
||||
assert m1.get_decay_heat(units='W/cm3') == 0
|
||||
assert m1.get_decay_heat(units='W/g') == 0
|
||||
m1.volume = 1
|
||||
assert m1.get_decay_heat(units='W') == 0
|
||||
|
||||
# Checks that 1g of tritium has the correct decay heat scaling
|
||||
m2 = openmc.Material()
|
||||
m2.add_nuclide("I135", 1)
|
||||
m2.set_density('g/cm3', 1)
|
||||
m2.volume = 1
|
||||
assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193
|
||||
m2.set_density('g/cm3', 2)
|
||||
assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2
|
||||
m2.volume = 3
|
||||
assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2*3
|
||||
|
||||
# Checks that 1 mol of a metastable nuclides has the correct decay heat
|
||||
m3 = openmc.Material()
|
||||
m3.add_nuclide("Xe135", 1)
|
||||
m3.set_density('g/cm3', 1)
|
||||
m3.volume = 98.9
|
||||
assert pytest.approx(m3.get_decay_heat(units='W'), rel=0.001) == 846181.2921143445
|
||||
|
||||
# Checks that specific and volumetric decay heat of tritium are correct
|
||||
m4 = openmc.Material()
|
||||
m4.add_nuclide("I135", 1)
|
||||
m4.set_density('g/cm3', 1.5)
|
||||
assert pytest.approx(m4.get_decay_heat(units='W/g')) == 40175.15720273193 # [W/g]
|
||||
assert pytest.approx(m4.get_decay_heat(units='W/g', by_nuclide=True)["I135"]) == 40175.15720273193 # [W/g]
|
||||
assert pytest.approx(m4.get_decay_heat(units='W/cm3')) == 40175.15720273193*3/2 # [W/cc]
|
||||
assert pytest.approx(m4.get_decay_heat(units='W/cm3', by_nuclide=True)["I135"]) == 40175.15720273193*3/2 #[W/cc]
|
||||
# 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]
|
||||
|
||||
|
||||
def test_decay_photon_energy():
|
||||
# Set chain file for testing
|
||||
openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue