From 7b175961fa45bef717b30894f1659d0f2f436a57 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 22 Aug 2019 11:24:39 -0500 Subject: [PATCH] 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. --- openmc/deplete/helpers.py | 23 +++--- .../unit_tests/test_deplete_fission_yields.py | 70 ++++++++++--------- 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index debc10403e..eb86b0ea4a 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -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): diff --git a/tests/unit_tests/test_deplete_fission_yields.py b/tests/unit_tests/test_deplete_fission_yields.py index 05f62eaceb..2842043d12 100644 --- a/tests/unit_tests/test_deplete_fission_yields.py +++ b/tests/unit_tests/test_deplete_fission_yields.py @@ -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]