diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index d53db063e..260838439 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -6,7 +6,7 @@ .. module:: openmc.deplete -Several functions are provided that implement different time-integration +Several classes are provided that implement different time-integration algorithms for depletion calculations, which are described in detail in Colin Josey's thesis, `Development and analysis of high order neutron transport-depletion coupling algorithms `_. @@ -25,7 +25,7 @@ transport-depletion coupling algorithms `_. SICELIIntegrator SILEQIIntegrator -Each of these functions expects a "transport operator" to be passed. An operator +Each of these classes expects a "transport operator" to be passed. An operator specific to OpenMC is available using the following class: .. autosummary:: @@ -79,7 +79,6 @@ data, such as number densities and reaction rates for each material. AtomNumber ChainFissionHelper DirectReactionRateHelper - FissionYieldHelper OperatorResult ReactionRates Results @@ -94,8 +93,9 @@ The following classes are abstract classes that can be used to extend the :nosignatures: :template: myclass.rst - ReactionRateHelper EnergyHelper + FissionYieldHelper + ReactionRateHelper TransportOperator Custom integrators can be developed by subclassing from the following abstract diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 0f1203aeb..356e9186d 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -364,6 +364,108 @@ class EnergyHelper(ABC): self._nuclides = nuclides +class FissionYieldHelper(ABC): + """Abstract class for processing energy dependent fission yields + + Parameters + ---------- + chain_nuclides : iterable of openmc.deplete.Nuclide + Nuclides tracked in the depletion chain. Not necessary + that all have yield data. + + Attributes + ---------- + n_bmats : int + Number of burnable materials tracked in the problem + constant_yields : dict of str to :class:`openmc.deplete.FissionYield` + Fission yields for all nuclides that only have one set of + fission yield data. Can be accessed as ``{parent: {product: yield}}`` + """ + + def __init__(self, chain_nuclides): + self._chain_nuclides = {} + self._constant_yields = {} + + # Get all nuclides with fission yield data + for nuc in chain_nuclides: + if len(nuc.yield_data) == 1: + self._constant_yields[nuc.name] = ( + nuc.yield_data[nuc.yield_energies[0]]) + elif len(nuc.yield_data) > 1: + self._chain_nuclides[nuc.name] = nuc + self._chain_set = set(self._chain_nuclides) | set(self._constant_yields) + + @property + def constant_yields(self): + out = {} + for key, sub in self._constant_yields.items(): + out[key] = sub.copy() + return out + + @abstractmethod + def weighted_yields(self, local_mat_index): + """Return fission yields for a specific material + + Parameters + ---------- + local_mat_index : int + Index for material tracked on this process that + exists in :attr:`local_mat_index` and fits within + the first axis in :attr:`results` + + Returns + ------- + library : dict + Dictionary of ``{parent: {product: fyield}}`` + """ + + @staticmethod + def unpack(): + """Unpack tally data prior to compute fission yields. + + Called after a :meth:`openmc.deplete.Operator.__call__` + routine during the normalization of reaction rates. + + Not necessary for all subclasses to implement, unless tallies + are used. + """ + + @staticmethod + def generate_tallies(materials, mat_indexes): + """Construct tallies necessary for computing fission yields + + Called during the operator set up phase prior to depleting. + Not necessary for subclasses to implement + + Parameters + ---------- + materials : iterable of C-API materials + Materials to be used in :class:`openmc.capi.MaterialFilter` + mat_indexes : iterable of int + Indexes for materials in ``materials`` tracked on this + process + """ + + def update_nuclides_from_operator(self, nuclides): + """Return nuclides with non-zero densities and yield data + + Parameters + ---------- + nuclides : iterable of str + Nuclides with non-zero densities from the + :class:`openmc.deplete.Operator` + + Returns + ------- + nuclides : tuple of str + Union of nuclides that the :class:`openmc.deplete.Operator` + says have non-zero densities at this stage and those that + have yield data. Sorted by nuclide name + + """ + return tuple(sorted(self._chain_set & set(nuclides))) + + class Integrator(ABC): """Abstract class for solving the time-integration for depletion diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index d99c96f18..15f85aa4b 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -210,7 +210,7 @@ class Operator(TransportOperator): nuclides = self._get_tally_nuclides() self._rate_helper.nuclides = nuclides self._energy_helper.nuclides = nuclides - self._fsn_yield_helper.set_fissionable_nuclides(nuclides) + self._fsn_yield_helper.update_nuclides_from_operator(nuclides) # Run OpenMC openmc.capi.reset() @@ -590,7 +590,7 @@ class Operator(TransportOperator): mat_index, nuc_ind, react_ind) # Compute fission yields for this material - fission_yields.append(self._fsn_yield_helper.compute_yields(i)) + fission_yields.append(self._fsn_yield_helper.weighted_yields(i)) # Accumulate energy from fission self._energy_helper.update(tally_rates[:, fission_ind], mat_index)