Moved from deplete.abc into openmc.deplete.cram. CRAM16 and CRAM48
are aliases to __call__ methods for two instances of
IPFCramSolver: Cram16Solver and Cram48Solver, created using
16th and 48th order coefficients
Tallies created by internal depletion helpers are marked
as internal using the openmc.lib.Tally.writeable property.
This is done to resolve issue #1327 where statepoint files could
grow to be quite large after tallying reaction rates across many
burnable materials for all nuclides of interest.
A check is added in the depletion regression test to ensure that
no additional tallies are loaded to the StatePoint.
CRAM16 and CRAM48 are now aliases for __call__ methods
on two new classes: openmc.deplete.cram.Cram16Solver
and Cram48Solver. These are two concrete subclasses of
openmc.deplete.abc.IPFCramSolver and
openmc.deplete.abc.DepSystemSolver abstract classes.
The primary benefit of the class based approach is that the
16th and 48th order have nearly identical implementations. The only
differences are the alpha, theta, and alpha_0 coefficients used.
This allows both the Cram16Solver and Cram48Solver to have unique
sets of coefficient vectors, while relying on the IPFSolver base
class implementation.
The implementation of IPF CRAM has been cleaned up. The NxN identity
matrix is not re-created each iteration. Given the alpha and
theta attributes on the IPFCramSolver instances, one can
iterate through the orders using a zip command. By forcing concrete
classes to declared alpha and theta vectors, the need to re-declare
the vectors at each entrance into CRAM48 is also removed.
Using these classes, a 10% speedup is observed depleting up to 500
materials on a single MPI process. The function-based approach
took 62s, while the new classes required 52s.
Provide explicit __all__ lists for files in openmc/deplete
containing classes that should be brought into the "primary"
API. This prevents cluttering the openmc.deplete namespace
caused by the wildcard imports
```
from .nuclide import *
...
```
The abc, cram, and helpers modules are imported simply as
```
from . import abc
from . import cram
from . import helpers
```
If the system energy is found to be zero, then
Operator.__call__ will exit the simulation using
comm.Abort / sys.exit if no mpi4py. Without this, the
reaction rates will be scaled by power / 0, causing errors
downstream in setting material compositions.
Depending on settings.photon_transport, obtain the total
system energy from the 301 [heating] or 901 [heating-local]
scores. The former is used in coupled neutron-photon transport,
as this does not include any energy from neutrons or
photons, assuming these particles deposit their energy along
their life. MT901 is used for neutron transport and is the default,
e.g. if scores is None. This score includes energy from
prompt and delayed photons taken from MT458 data.
Related PR: #1344 - Ability to generate KERMAs assuming local
photon energy deposition
Introduce a new subclass of EnergyHelper, EnergyScoreHelper,
that computes the system energy using the energy-deposition score.
This energy is fed back to the Operator to normalize reaction rates.
The energy from the tally is only stored on the helper on the
MPI process 0 as to avoid scaling the system energy by the number
of processes. During the Operator unpacking, the energy reported
by each process is reduced, as the previous implementations took
fission reaction rates from the "local materials", e.g. the
materials each process is responsible for depleting.
The tally results are shared across all processes and only
contains a single quantity, the tallied energy deposition across
all materials.
This mode is controlled by passing the "energy_mode" argument passed
to the Operator. The two options are "fission-q" [default and previous
behavior] and "energy-deposition" [new features]. If energy_mode indicates using
the energy deposition score, the user-supplied fission-q dictionary is not used.
(cherry picked from commit d566f3080f)
The Chain.form_matrix method looks for information and
fission yields for all isotopes with a fission reaction.
However, the AveragedFissionYieldHelper and FissionYieldCutoffHelper
are not guaranteed to return yields to all isotopes with
fission reactions. Instead, the union on two sets of yields
are returned:
1) yields from isotopes with a single set of fission yields
2) weighted yields computed for isotopes with both multiple sets of
fission yields **and** non-zero densities.
This later item can cause some isotopes that the Chain anticipates
having fission yields, since they have a fission reaction, to not
exist in the yields library. An isotope with multiple sets of
yields but that is not physically present in the problem will not
have reaction rates and also not have fission yields computed
by these helpers. This will cause a KeyError during Chain.form_matrix
when fission yields for these isotopes are requested.
This commit changes the return type from weighted_yields on
ConstantFissionYieldHelper, AveragedFissionYieldHelper, and
FissionYieldCutoffHelper to be defaultdict(dict). This resolves
the above issue by returning an "empty" set of yields for isotopes
that potentially *should* have fission yields, but have zero density
across the problem, and therefore do not have tallied reaction
rates nor fission yields.
Documentation for the changes to these classes have been updated
openmc.deplete.cram.deplete now pre-generates a map object
that produces depletion matrices given the chain, rates,
and matrix_func. The internal cram wrapper function has
been removed, as the full inputs to CRAM48 are now known,
in zipped and mapped objects.
Some basic timing comparisons indicate that this approach
is at least as fast, if not marginally faster, for a
quarter PWR assembly and an SFR assembly.
Remove copy method.
__contains__ and __getitem__ now take advantage of the
ordering of products. This can improve time searching
for fission products and retrieving yields.
radd and rmul methods defer to their left counterparts, e.g.
x * fy => fy * x. Return NotImplemented types if addition is
not done with another set of fission yields and multiplication
is not done with a scalar.
Improve/expand special methods for FissionYield
Remove copy method.
__contains__ and __getitem__ now take advantage of the
ordering of products. This can improve time searching
for fission products and retrieving yields.
radd and rmul methods defer to their left counterparts, e.g.
x * fy => fy * x. Return NotImplemented types if addition is
not done with another set of fission yields and multiplication
is not done with a scalar.
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.
Reconfigure tests/unit_tests/test_deplete_chain.py and
tests/unit_tests/test_deplete_nuclide.py to use the new
dictionary-like representation of fission yields.
Provide a module-scoped fixture that creates a temporary
directory, adds simple settings, geometry, and material files,
and initializes the openmc C API. This fixture also provides
two empty openmc.capi.Material objects to help the helpers
generate meaningful tallies.
The main tests for AveragedFissionYieldHelper and
FissionYieldCutoffHelper now go through the built tallies
and examine the filters, nuclides, and scores. A helper
function produces mocked-like tally data based on filters,
nuclides, and scores found on a tally.
Pu239 with 0.0253 eV, 500 keV, and 2 MeV yields is included in
the nuclide_bundle fixture. This provides some additional
heterogeneity in the results, as the 2 MeV data is not present
on U235.
Had to guard against some cases where it was assumed
that yield_data would be a dictionary. For the most part,
the fission yield helpers act on nuclides that have yield data
already.
The previous default state was to use an empty dictionary.
This has been removed. A value of None for nuclide.yield_data
indicates there is no yield data.
- Change Operator attribute name for fission yield helper
- Use copy.deepcopy for constant_yields, fast_yields, and thermal_yields
- Change import location of openmc in tests
- Use bisect.bisect_left to find replacement fission yields on
FissionYieldCutoffHelper if thermal or fast energies not found
In an (n, alpha) reaction, the branching ratio for helium should
always be one, as it is produced for every reaction.
It is the branching ratio of the other targets that must be modified.
He4 is treated as a secondary particle for this case, and its
reaction is not modified nor removed from the parent.
Generalized method that allows the modification of branching
ratios for an arbitrary reaction. A similar replacement has been
made with the companion get_capture_branches -> get_branch_ratios.
Both of the new methods accept an additional reaction argument,
which defaults to "(n,gamma)", indicating what reaction to
modify/retrieve.
Also added a tolerance argument, defaults to 1e-5, for checking
the sum of user-supplied branching ratios. This tolerance is
used as 1 - tolerance < sum_br < 1 + tolerance. Additional
logic is included if the user has not specified the ground
state, which can be inferred. For this case, the lower end
is allowed to be less than 1 - tolerance, as the ground state will
have a branch ratio such the sum of ratios is unity.
Products are not checked for consistency, that is left up to the user.
tests/unit_test/test_deplete_chain.py has been modified with the
new notation, and also with a variety of calls with and without
the optional reaction argument. A minor test is added that modifies
(n,alpha) and (n,2n) reactions just to ensure that arbitrary reactions
can be used.
Minor changes:
* Internal variables changed to reflect the generality of the method
* Added documentation on what exceptions are raised in
set_branch_ratios
Related: openmc issue #1237
Renamed update_nuclides_from_operator -> update_tally_nuclides
to be more general.
The base method TalliedFissionYieldHelper.update_tally_nuclides will
raise an AttributeError if this method is called before the tallies
are generated. The inner logic for setting the tallied nuclides can
be streamlined given the assumption that the tally exists.
AveragedFissionYieldHelper.update_tally_nuclides has been improved
to set the nuclides for the weighted tally now. This was not captured
prior because the nuclides were copied over from the fission rate
tally during tally generation, prior to when nuclides were set.
If there are no nuclides with multiple sets of yields, then
the tallies needed for fission yields may or or may not exist.
Regardless, this means that using constant_yields is absolutely
appropriate and there is no need for unpacking on
FissionYieldCutoffHelper nor AveragedFissionYieldHelper.
The weighted_yields methods for these two classes simply return
the set of constant yields if this is the case.