Use constant FY if cutoff energy outside provided yields

The FissionYieldCutoffHelper will always find a set of yields
to use for all nuclides with yield data now, rather than raise
an error. Previously, if the cutoff was outside the provided
bounds, an error was raised because there wasn't a clear set of
"fast" and "thermal" yields to use. However, this caused issues
with nuclides that are missing a set of lower yields, like
Th232 with yields at 5e5 and 6e6 per ENDF/B-VII.1 data.

Now, if the cutoff energy is outside the bounds of provided
yield data, the closet set of yields to the cutoff is taken to
be constant. These nuclides will not be tallied during the
transport routine.
This commit is contained in:
Andrew Johnson 2019-08-22 11:24:39 -05:00
parent 4f46aa895c
commit 7b175961fa
No known key found for this signature in database
GPG key ID: 253418E91B7F6FEB
2 changed files with 50 additions and 43 deletions

View file

@ -199,8 +199,6 @@ class ConstantFissionYieldHelper(FissionYieldHelper):
continue
# Specific energy not found, use closest energy
distances = [abs(energy - ene) for ene in nuc.yield_energies]
min_index = min(
range(len(nuc.yield_energies)), key=distances.__getitem__)
min_E = min(nuc.yield_energies, key=lambda e: abs(e - energy))
self._constant_yields[name] = nuc.yield_data[min_E]
@ -307,21 +305,24 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper):
self._cutoff = cutoff
self._thermal_yields = {}
self._fast_yields = {}
convert_to_constant = set()
for name, nuc in self._chain_nuclides.items():
yields = nuc.yield_data
energies = nuc.yield_energies
thermal = yields.get(thermal_energy)
fast = yields.get(fast_energy)
if thermal is None or fast is None:
if cutoff <= energies[0]:
# use lowest energy yields as constant
self._constant_yields[name] = yields[energies[0]]
convert_to_constant.add(name)
continue
if cutoff >= energies[-1]:
# use highest energy yields as constant
self._constant_yields[name] = yields[energies[-1]]
convert_to_constant.add(name)
continue
cutoff_ix = bisect.bisect_left(energies, cutoff)
# if zero, then all energies > cutoff
# if len(energies), then all energies <= cutoff
if cutoff_ix == 0 or cutoff_ix == len(energies):
tail = map("{:5.3e}".format, energies)
raise ValueError(
"Cannot find replacement fission yields for {} given "
"cutoff {:5.3e} eV. Yields provided at [{}] eV".format(
name, cutoff, ", ".join(tail)))
# find closest energy to requested thermal, fast energies
if thermal is None:
min_E = min(energies[:cutoff_ix],
@ -333,6 +334,8 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper):
fast = yields[min_E]
self._thermal_yields[name] = thermal
self._fast_yields[name] = fast
for name in convert_to_constant:
self._chain_nuclides.pop(name)
@classmethod
def from_operator(cls, operator, **kwargs):

View file

@ -111,7 +111,6 @@ def nuclide_bundle():
pu239 = Nuclide("Pu239")
pu239.yield_data = FissionYieldDistribution({
0.0253: {"Xe135": 3.141e-3, "Sm149": 8.19e-10, "Gd155": 1.66e-9},
5.0e5: {"Xe135": 6.14e-3, "Sm149": 9.429e-10, "Gd155": 5.24e-9},
2e6: {"Xe135": 6.15e-3, "Sm149": 9.42e-10, "Gd155": 5.29e-9}})
@ -127,8 +126,8 @@ def test_constant_helper(nuclide_bundle, input_energy, yield_energy):
assert helper.energy == input_energy
assert helper.constant_yields == {
"U235": nuclide_bundle.u235.yield_data[yield_energy],
"U238": nuclide_bundle.u238.yield_data[5.00e5], # only epithermal
"Pu239": nuclide_bundle.pu239.yield_data[yield_energy]}
"U238": nuclide_bundle.u238.yield_data[5.00e5],
"Pu239": nuclide_bundle.pu239.yield_data[5e5]}
assert helper.constant_yields == helper.weighted_yields(1)
@ -140,50 +139,54 @@ def test_cutoff_construction(nuclide_bundle):
# defaults
helper = FissionYieldCutoffHelper(nuclide_bundle, 1)
assert helper.constant_yields == {
"U238": u238.yield_data[5.0e5]}
assert helper.thermal_yields == {
"U235": u235.yield_data[0.0253],
"Pu239": pu239.yield_data[0.0253]}
assert helper.fast_yields == {
"U235": u235.yield_data[5e5],
"U238": u238.yield_data[5.0e5],
"Pu239": pu239.yield_data[5e5]}
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
# use 14 MeV yields
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, fast_energy=14e6)
assert helper.constant_yields == {
"U238": u238.yield_data[5.0e5]}
assert helper.thermal_yields == {
"U235": u235.yield_data[0.0253],
"Pu239": pu239.yield_data[0.0253]}
assert helper.fast_yields == {
"U235": u235.yield_data[14e6],
"Pu239": pu239.yield_data[2e6]}
"U238": u238.yield_data[5.0e5],
"Pu239": pu239.yield_data[5e5]}
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
assert helper.fast_yields == {"U235": u235.yield_data[14e6]}
# specify missing thermal yields -> use 0.0253
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, thermal_energy=1)
assert helper.thermal_yields == {
"U235": u235.yield_data[0.0253],
"Pu239": pu239.yield_data[0.0253]}
assert helper.fast_yields == {
"U235": u235.yield_data[5e5],
"Pu239": pu239.yield_data[5e5]}
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
# request missing fast yields -> use epithermal
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, fast_energy=1e4)
assert helper.thermal_yields == {"U235": u235.yield_data[0.0253]}
assert helper.fast_yields == {"U235": u235.yield_data[5e5]}
# higher cutoff energy -> obtain fast and "faster" yields
helper = FissionYieldCutoffHelper(nuclide_bundle, 1, cutoff=1e6,
thermal_energy=5e5, fast_energy=14e6)
assert helper.constant_yields == {"U238": u238.yield_data[5e5]}
assert helper.thermal_yields == {
"U235": u235.yield_data[0.0253],
"Pu239": pu239.yield_data[0.0253]}
"U235": u235.yield_data[5e5], "Pu239": pu239.yield_data[5e5]}
assert helper.fast_yields == {
"U235": u235.yield_data[5e5],
"U235": u235.yield_data[14e6], "Pu239": pu239.yield_data[2e6]}
# test super low and super high cutoff energies
helper = FissionYieldCutoffHelper(
nuclide_bundle, 1, thermal_energy=0.001, cutoff=0.002)
assert helper.fast_yields == {}
assert helper.thermal_yields == {}
assert helper.constant_yields == {
"U235": u235.yield_data[0.0253], "U238": u238.yield_data[5e5],
"Pu239": pu239.yield_data[5e5]}
# test failures in cutoff: super low, super high
with pytest.raises(ValueError, match="replacement fission yields"):
FissionYieldCutoffHelper(
nuclide_bundle, 1, thermal_energy=0.001, cutoff=0.002)
with pytest.raises(ValueError, match="replacement fission yields"):
FissionYieldCutoffHelper(
nuclide_bundle, 1, cutoff=15e6, fast_energy=17e6)
helper = FissionYieldCutoffHelper(
nuclide_bundle, 1, cutoff=15e6, fast_energy=17e6)
assert helper.thermal_yields == {}
assert helper.fast_yields == {}
assert helper.constant_yields == {
"U235": u235.yield_data[14e6], "U238": u238.yield_data[5e5],
"Pu239": pu239.yield_data[2e6]}
@pytest.mark.parametrize("key", ("cutoff", "thermal_energy", "fast_energy"))
@ -197,7 +200,8 @@ def test_cutoff_failure(key):
# emulate some split between fast and thermal U235 fissions
@pytest.mark.parametrize("therm_frac", (0.5, 0.2, 0.8))
def test_cutoff_helper(materials, nuclide_bundle, therm_frac):
helper = FissionYieldCutoffHelper(nuclide_bundle, len(materials))
helper = FissionYieldCutoffHelper(nuclide_bundle, len(materials),
cutoff=1e6, fast_energy=14e6)
helper.generate_tallies(materials, [0])
non_zero_nucs = [n.name for n in nuclide_bundle]