Merge branch 'develop' into reduced-absorption-xs

This commit is contained in:
Paul Romano 2022-08-08 12:17:18 -05:00
commit c5a5a3b9a6
48 changed files with 3426 additions and 1084 deletions

View file

@ -103,16 +103,17 @@ integrate over the entire timestep.
Our aim here is not to exhaustively describe all integration methods but rather
to give a few examples that elucidate the main considerations one must take into
account when choosing a method. Generally, there is a tradeoff between the
accuracy of the method and its computational expense. The expense is driven
almost entirely by the time to compute a transport solution, i.e., to evaluate
:math:`\mathbf{A}` for a given :math:`\mathbf{n}`. Thus, the cost of a method
scales with the number of :math:`\mathbf{A}` evaluations that are performed per
timestep. On the other hand, methods that require more evaluations generally
achieve higher accuracy. The predictor method only requires one evaluation and
its error converges as :math:`\mathcal{O}(h)`. The CE/CM method requires two
evaluations and is thus twice as expensive as the predictor method, but achieves
an error of :math:`\mathcal{O}(h^2)`. An exhaustive description of time
integration methods and their merits can be found in the `thesis of Colin Josey
accuracy of the method and its computational expense. In the case of
transport-coupled depletion, the expense is driven almost entirely by the time
to compute a transport solution, i.e., to evaluate :math:`\mathbf{A}` for a
given :math:`\mathbf{n}`. Thus, the cost of a method scales with the number of
:math:`\mathbf{A}` evaluations that are performed per timestep. On the other
hand, methods that require more evaluations generally achieve higher accuracy.
The predictor method only requires one evaluation and its error converges as
:math:`\mathcal{O}(h)`. The CE/CM method requires two evaluations and is thus
twice as expensive as the predictor method, but achieves an error of
:math:`\mathcal{O}(h^2)`. An exhaustive description of time integration methods
and their merits can be found in the `thesis of Colin Josey
<http://dspace.mit.edu/handle/1721.1/7582>`_.
OpenMC does not rely on a single time integration method but rather has several
@ -169,12 +170,14 @@ Data Considerations
In principle, solving Eq. :eq:`depletion-matrix` using CRAM is fairly simple:
just construct the burnup matrix at various times and solve a set of sparse
linear systems. However, constructing the burnup matrix itself involves not only
solving the transport equation to estimate transmutation reaction rates but also
a series of choices about what data to include. In OpenMC, the burnup matrix is
constructed based on data inside of a *depletion chain* file, which includes
fundamental data gathered from ENDF incident neutron, decay, and fission product
yield sublibraries. For each nuclide, this file includes:
linear systems. However, constructing the burnup matrix itself involves not
only solving the transport equation to estimate transmutation reaction rates
(in the case of transport-coupled depletion) or to obtain microscopic cross
sections (in the case of transport-independent depletion), but also a series of
choices about what data to include. In OpenMC, the burnup matrix is constructed
based on data inside of a *depletion chain* file, which includes fundamental
data gathered from ENDF incident neutron, decay, and fission product yield
sublibraries. For each nuclide, this file includes:
- What transmutation reactions are possible, their Q values, and their products;
- If a nuclide is not stable, what decay modes are possible, their branching
@ -185,9 +188,12 @@ yield sublibraries. For each nuclide, this file includes:
Transmutation Reactions
-----------------------
OpenMC will setup tallies in a problem based on what transmutation reactions are
available in a depletion chain file, so any arbitrary number of transmutation
reactions can be tracked. The pregenerated chain files that are available on
In transport-coupled depletion, OpenMC will setup tallies in a problem based on
what transmutation reactions are available in a depletion chain file, so any
arbitrary number of transmutation reactions can be tracked. In
transport-independent depletion, OpenMC will calculate reaction rates for every
reaction that is present in both the available cross sections and the depletion
chain file. The pregenerated chain files that are available on
https://openmc.org include the following transmutation reactions: fission, (n,\
:math:`\gamma`\ ), (n,2n), (n,3n), (n,4n), (n,p), and (n,\ :math:`\alpha`\ ).
@ -202,11 +208,12 @@ accurately model the branching of the capture reaction in Am241. This is
complicated by the fact that the branching ratio may depend on the incident
neutron energy causing capture.
OpenMC does not currently allow energy-dependent capture branching ratios.
However, the depletion chain file does allow a transmutation reaction to be
listed multiple times with different branching ratios resulting in different
products. Spectrum-averaged capture branching ratios have been computed in LWR
and SFR spectra and are available at https://openmc.org/depletion-chains.
OpenMC's transport solver does not currently allow energy-dependent capture
branching ratios. However, the depletion chain file does allow a transmutation
reaction to be listed multiple times with different branching ratios resulting
in different products. Spectrum-averaged capture branching ratios have been
computed in LWR and SFR spectra and are available at
https://openmc.org/depletion-chains.
Fission Product Yields
----------------------
@ -217,26 +224,31 @@ energies. It is an open question as to what the best way to handle this energy
dependence is. OpenMC includes three methods for treating the energy dependence
of FPY:
1. Use FPY data corresponding to a specified energy.
1. Use FPY data corresponding to a specified energy. This is used by default in
both transport-coupled and transport-independent depletion.
2. Tally fission rates above and below a specified cutoff energy. Assume that
all fissions below the cutoff energy correspond to thermal FPY data and all
fission above the cutoff energy correspond to fast FPY data.
fission above the cutoff energy correspond to fast FPY data. Only applicable
to transport-coupled depletion.
3. Compute the average energy at which fission events occur and use an effective
FPY by linearly interpolating between FPY provided at neighboring energies.
Only applicable to transport-coupled depletion.
The method can be selected through the ``fission_yield_mode`` argument to the
:class:`openmc.deplete.Operator` constructor.
The method for transport-coupled depletion can be selected through the
``fission_yield_mode`` argument to the :class:`openmc.deplete.CoupledOperator`
constructor.
Power Normalization
-------------------
The reaction rates provided OpenMC are given in units of reactions per source
particle. For depletion, it is necessary to compute an absolute reaction rate in
reactions per second. To do so, the reaction rates are normalized based on a
specified power. A complete description of how this normalization can be
performed is described in :ref:`usersguide_tally_normalization`. Here, we simply
note that the main depletion class, :class:`openmc.deplete.Operator`, allows the
user to choose one of two methods for estimating the heating rate, including:
In transport-coupled depletion, the reaction rates provided OpenMC are given in
units of reactions per source particle. For depletion, it is necessary to
compute an absolute reaction rate in reactions per second. To do so, the
reaction rates are normalized based on a specified power. A complete
description of how this normalization can be performed is described in
:ref:`usersguide_tally_normalization`. Here, we simply note that the main
depletion class, :class:`openmc.deplete.CoupledOperator`, allows the user to
choose one of two methods for estimating the heating rate, including:
1. Using fixed Q values from a depletion chain file (useful for comparisons to
other codes that use fixed Q values), or
@ -244,4 +256,4 @@ user to choose one of two methods for estimating the heating rate, including:
energy-dependent estimate of the true heating rate.
The method for normalization can be chosen through the ``normalization_mode``
argument to the :class:`openmc.deplete.Operator` class.
argument to the :class:`openmc.deplete.CoupledOperator` class.

View file

@ -61,11 +61,13 @@ Core Functions
atomic_mass
atomic_weight
combine_distributions
decay_constant
dose_coefficients
gnd_name
half_life
isotopes
kalbach_slope
linearize
thin
water_density

View file

@ -15,16 +15,18 @@ are:
1) A transport operator
2) A time-integration scheme
The former is responsible for executing a transport code, like OpenMC,
and retaining important information required for depletion. The most common examples
are reaction rates and power normalization data. The latter is responsible for
projecting reaction rates and compositions forward in calendar time across
some step size :math:`\Delta t`, and obtaining new compositions given a power
or power density. The :class:`Operator` is provided to handle communicating with
OpenMC. 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 <http://hdl.handle.net/1721.1/113721>`_.
The former is responsible for calculating and retaining important information
required for depletion. The most common examples are reaction rates and power
normalization data. The latter is responsible for projecting reaction rates and
compositions forward in calendar time across some step size :math:`\Delta t`,
and obtaining new compositions given a power or power density. The
:class:`CoupledOperator` class is provided to obtain reaction rates via tallies
through OpenMC's transport solver, and the :class:`IndependentOperator` class is
provided to obtain reaction rates from cross-section data. 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 <http://hdl.handle.net/1721.1/113721>`_.
.. autosummary::
:toctree: generated
@ -40,18 +42,20 @@ transport-depletion coupling algorithms <http://hdl.handle.net/1721.1/113721>`_.
SICELIIntegrator
SILEQIIntegrator
Each of these classes expects a "transport operator" to be passed. An operator
specific to OpenMC is available using the following class:
Each of these classes expects a "transport operator" to be passed. OpenMC
provides The following classes implementing transpor operators:
.. autosummary::
:toctree: generated
:nosignatures:
:template: mycallable.rst
Operator
CoupledOperator
IndependentOperator
The :class:`Operator` must also have some knowledge of how nuclides transmute
and decay. This is handled by the :class:`Chain`.
The :class:`CoupledOperator` and :class:`IndependentOperator` classes must also
have some knowledge of how nuclides transmute and decay. This is handled by the
:class:`Chain`.
Minimal Example
---------------
@ -64,11 +68,12 @@ A minimal example for performing depletion would be:
>>> import openmc.deplete
>>> geometry = openmc.Geometry.from_xml()
>>> settings = openmc.Settings.from_xml()
>>> model = openmc.model.Model(geometry, settings)
# Representation of a depletion chain
>>> chain_file = "chain_casl.xml"
>>> operator = openmc.deplete.Operator(
... geometry, settings, chain_file)
>>> operator = openmc.deplete.CoupledOperator(
... model, chain_file)
# Set up 5 time steps of one day each
>>> dt = [24 * 60 * 60] * 5
@ -131,6 +136,7 @@ data, such as number densities and reaction rates for each material.
:template: myclass.rst
AtomNumber
MicroXS
OperatorResult
ReactionRates
Results
@ -172,7 +178,7 @@ with :func:`cram.CRAM48` being the default.
:class:`multiprocessing.pool.Pool` class. If set to ``None`` (default), the
number returned by :func:`os.cpu_count` is used.
The following classes are used to help the :class:`openmc.deplete.Operator`
The following classes are used to help the :class:`openmc.deplete.CoupledOperator`
compute quantities like effective fission yields, reaction rates, and
total system energy.
@ -189,14 +195,45 @@ total system energy.
helpers.FissionYieldCutoffHelper
helpers.FluxCollapseHelper
The :class:`openmc.deplete.IndependentOperator` uses inner classes subclassed
from those listed above to perform similar calculations.
Intermediate Classes
--------------------
Specific implementations of abstract base classes may utilize some of
the same methods and data structures. These methods and data are stored
in intermediate classes.
Methods common to tally-based implementation of :class:`FissionYieldHelper`
are stored in :class:`helpers.TalliedFissionYieldHelper`
.. autosummary::
:toctree: generated
:nosignatures:
:template: myclass.rst
helpers.TalliedFissionYieldHelper
Methods common to OpenMC-specific implementations of :class:`TransportOperator`
are stored in :class:`openmc_operator.OpenMCOperator`
.. autosummary::
:toctree: generated
:nosignatures:
:template: mycallable.rst
openmc_operator.OpenMCOperator
Abstract Base Classes
---------------------
A good starting point for extending capabilities in :mod:`openmc.deplete` is
to examine the following abstract base classes. Custom classes can
inherit from :class:`abc.TransportOperator` to implement alternative
schemes for collecting reaction rates and other data from a transport code
prior to depleting materials
schemes for collecting reaction rates and other data prior to depleting
materials
.. autosummary::
:toctree: generated
@ -206,7 +243,9 @@ prior to depleting materials
abc.TransportOperator
The following classes are abstract classes used to pass information from
OpenMC simulations back on to the :class:`abc.TransportOperator`
transport simulations (in the case of transport-coupled depletion) or to
simply calculate these quantities directly (in the case of
transport-independent depletion) back on to the :class:`abc.TransportOperator`
.. autosummary::
:toctree: generated
@ -216,7 +255,6 @@ OpenMC simulations back on to the :class:`abc.TransportOperator`
abc.NormalizationHelper
abc.FissionYieldHelper
abc.ReactionRateHelper
abc.TalliedFissionYieldHelper
Custom integrators or depletion solvers can be developed by subclassing from
the following abstract base classes:

View file

@ -4,50 +4,30 @@
Depletion and Transmutation
===========================
OpenMC supports coupled depletion, or burnup, calculations through the
:mod:`openmc.deplete` Python module. OpenMC solves the transport equation to
obtain transmutation reaction rates, and then the reaction rates are used to
solve a set of transmutation equations that determine the evolution of nuclide
densities within a material. The nuclide densities predicted as some future time
are then used to determine updated reaction rates, and the process is repeated
for as many timesteps as are requested.
OpenMC supports transport-coupled and transport-independent depletion, or
burnup, calculations through the :mod:`openmc.deplete` Python module. OpenMC
uses transmutation reaction rates to solve a set of transmutation equations
that determine the evolution of nuclide densities within a material. The
nuclide densities predicted at some future time are then used to determine
updated reaction rates, and the process is repeated for as many timesteps as
are requested.
The depletion module is designed such that the flux/reaction rate solution (the
The depletion module is designed such that the reaction rate solution (the
transport "operator") is completely isolated from the solution of the
transmutation equations and the method used for advancing time. At present, the
:mod:`openmc.deplete` module offers a single transport operator,
:class:`openmc.deplete.Operator` (which uses the OpenMC transport solver), but
in principle additional operator classes based on other transport codes could be
implemented and no changes to the depletion solver itself would be needed. The
operator class requires a :class:`openmc.Geometry` instance and a
:class:`openmc.Settings` instance::
geom = openmc.Geometry()
settings = openmc.Settings()
...
op = openmc.deplete.Operator(geom, settings)
Any material that contains a fissionable nuclide is depleted by default, but
this can behavior can be changed with the :attr:`Material.depletable` attribute.
.. important:: The volume must be specified for each material that is depleted by
setting the :attr:`Material.volume` attribute. This is necessary
in order to calculate the proper normalization of tally results
based on the source rate.
transmutation equations and the method used for advancing time.
:mod:`openmc.deplete` supports multiple time-integration methods for determining
material compositions over time. Each method appears as a different class.
For example, :class:`openmc.deplete.CECMIntegrator` runs a depletion calculation
using the CE/CM algorithm (deplete over a timestep using the middle-of-step
reaction rates). An instance of :class:`openmc.deplete.Operator` is passed to
one of these functions along with the timesteps and power level::
reaction rates). An instance of :class:`~openmc.deplete.abc.TransportOperator`
is passed to one of these functions along with the timesteps and power level::
power = 1200.0e6 # watts
timesteps = [10.0, 10.0, 10.0] # days
openmc.deplete.CECMIntegrator(op, timesteps, power, timestep_units='d').integrate()
The coupled transport-depletion problem is executed, and once it is done a
The depletion problem is executed, and once it is done a
``depletion_results.h5`` file is written. The results can be analyzed using the
:class:`openmc.deplete.Results` class. This class has methods that allow for
easy retrieval of k-effective, nuclide concentrations, and reaction rates over
@ -56,11 +36,41 @@ time::
results = openmc.deplete.Results("depletion_results.h5")
time, keff = results.get_keff()
Note that the coupling between the transport solver and the transmutation solver
happens in-memory rather than by reading/writing files on disk.
Note that the coupling between the reaction rate solver and the transmutation
solver happens in-memory rather than by reading/writing files on disk. OpenMC
has two categories of transport operators for obtaining transmutation reaction
rates.
.. _coupled-depletion:
Transport-coupled depletion
===========================
This category of operator solves the transport equation to obtain transmutation
reaction rates. At present, the :mod:`openmc.deplete` module offers a single
transport-coupled operator, :class:`openmc.deplete.CoupledOperator` (which uses
the OpenMC transport solver), but in principle additional transport-coupled
operator classes based on other transport codes could be implemented and no
changes to the depletion solver itself would be needed. The
:class:`openmc.deplete.CoupledOperator` class requires a :class:`~openmc.Model`
instance containing material, geometry, and settings information::
model = openmc.Model()
...
op = openmc.deplete.CoupledOperator(model)
Any material that contains a fissionable nuclide is depleted by default, but
this can behavior can be changed with the :attr:`Material.depletable` attribute.
.. important::
The volume must be specified for each material that is depleted by setting
the :attr:`Material.volume` attribute. This is necessary in order to
calculate the proper normalization of tally results based on the source rate.
Fixed-Source Transmutation
==========================
--------------------------
When the ``power`` or ``power_density`` argument is used for one of the
Integrator classes, it is assumed that OpenMC is running in k-eigenvalue mode,
@ -77,11 +87,11 @@ using the :attr:`Material.depletable` attribute::
mat = openmc.Material()
mat.depletable = True
When constructing the :class:`~openmc.deplete.Operator`, you should indicate
that normalization of tally results will be done based on the source rate rather
than a power or power density::
When constructing the :class:`~openmc.deplete.CoupledOperator`, you should
indicate that normalization of tally results will be done based on the source
rate rather than a power or power density::
op = openmc.deplete.Operator(geometry, settings, normalization_mode='source-rate')
op = openmc.deplete.CoupledOperator(model, normalization_mode='source-rate')
Finally, when creating a depletion integrator, use the ``source_rates`` argument::
@ -92,19 +102,22 @@ timestep in the calculation. A zero source rate for a given timestep will result
in a decay-only step, where all reaction rates are zero.
Caveats
=======
-------
.. _energy-deposition:
Energy Deposition
-----------------
~~~~~~~~~~~~~~~~~
The default energy deposition mode, ``"fission-q"``, instructs the
:class:`openmc.deplete.Operator` to normalize reaction rates using the product
of fission reaction rates and fission Q values taken from the depletion chain.
This approach does not consider indirect contributions to energy deposition,
such as neutron heating and energy from secondary photons. In doing this, the
energy deposited during a transport calculation will be lower than expected.
This causes the reaction rates to be over-adjusted to hit the user-specific
power, or power density, leading to an over-depletion of burnable materials.
:class:`~openmc.deplete.CoupledOperator` to normalize reaction rates using the
product of fission reaction rates and fission Q values taken from the depletion
chain. This approach does not consider indirect contributions to energy
deposition, such as neutron heating and energy from secondary photons. In doing
this, the energy deposited during a transport calculation will be lower than
expected. This causes the reaction rates to be over-adjusted to hit the
user-specific power, or power density, leading to an over-depletion of burnable
materials.
There are some remedies. First, the fission Q values can be directly set in a
variety of ways. This requires knowing what the total fission energy release
@ -113,29 +126,32 @@ should be, including indirect components. Some examples are provided below::
# use a dictionary of fission_q values
fission_q = {"U235": 202e+6} # energy in eV
# create a Model object
model = openmc.Model(geometry, settings)
# create a modified chain and write it to a new file
chain = openmc.deplete.Chain.from_xml("chain.xml", fission_q)
chain.export_to_xml("chain_mod_q.xml")
op = openmc.deplete.Operator(geometry, setting, "chain_mod_q.xml")
op = openmc.deplete.CoupledOperator(model, "chain_mod_q.xml")
# alternatively, pass the modified fission Q directly to the operator
op = openmc.deplete.Operator(geometry, setting, "chain.xml",
op = openmc.deplete.CoupledOperator(model, "chain.xml",
fission_q=fission_q)
A more complete way to model the energy deposition is to use the modified
heating reactions described in :ref:`methods_heating`. These values can be used
heating reactions described in :ref:`methods_heating`. These values can be used
to normalize reaction rates instead of using the fission reaction rates with::
op = openmc.deplete.Operator(geometry, settings, "chain.xml",
op = openmc.deplete.CoupledOperator(model, "chain.xml",
normalization_mode="energy-deposition")
These modified heating libraries can be generated by running the latest version
of :meth:`openmc.data.IncidentNeutron.from_njoy`, and will eventually be bundled
of :meth:`openmc.data.IncidentNeutron.from_njoy()`, and will eventually be bundled
into the distributed libraries.
Local Spectra and Repeated Materials
------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is not uncommon to explicitly create a single burnable material across many
locations. From a pure transport perspective, there is nothing wrong with
@ -160,7 +176,7 @@ the next transport step.
This can be countered by instructing the operator to treat repeated instances
of the same material as a unique material definition with::
op = openmc.deplete.Operator(geometry, settings, chain_file,
op = openmc.deplete.CoupledOperator(model, chain_file,
diff_burnable_mats=True)
For our example problem, this would deplete fuel on the outer region of the
@ -177,3 +193,164 @@ across all material instances.
This will increase the total memory usage and run time due to an increased
number of tallies and material definitions.
Transport-independent depletion
===============================
.. warning::
This feature is still under heavy development and has yet to be rigorously
verified. API changes and feature additions are possible and likely in
the near future.
This category of operator uses pre-calculated one-group microscopic cross
sections to obtain transmutation reaction rates. OpenMC provides the
:class:`~openmc.deplete.IndependentOperator` for this method of calculation.
While the one-group microscopic cross sections can be calculated using a
transport solver, :class:`~openmc.deplete.IndependentOperator` is not directly
coupled to any transport solver. The
:class:`~openmc.deplete.IndependentOperator` class requires a
:class:`openmc.Materials` object, a :class:`~openmc.deplete.MicroXS` object,
and a path to a depletion chain file::
# load in the microscopic cross sections
materials = openmc.Materials()
...
micro_xs = openmc.deplete.MicroXS.from_csv(micro_xs_path)
op = openmc.deplete.IndependentOperator(materials, micro_xs, chain_file)
.. note::
The same statements from :ref:`coupled-depletion` about which
materials are depleted and the requirement for depletable materials to have
a specified volume also apply here.
An alternate constructor,
:meth:`~openmc.deplete.IndependentOperator.from_nuclides`, accepts a volume and
dictionary of nuclide concentrations in place of the :class:`openmc.Materials`
object::
nuclides = {'U234': 8.92e18,
'U235': 9.98e20,
'U238': 2.22e22,
'U236': 4.57e18,
'O16': 4.64e22,
'O17': 1.76e19}
volume = 0.5
op = openmc.deplete.IndependentOperator.from_nuclides(volume,
nuclides,
micro_xs,
chain_file,
nuc_units='atom/cm3')
A user can then define an integrator class as they would for a coupled
transport-depletion calculation and follow the same steps from there.
.. note::
Ideally, one-group cross section data should be available for every
reaction in the depletion chain. If a nuclide that has a reaction
associated with it in the depletion chain is present in the `nuclides`
parameter but not the cross section data, that reaction will not be
simulated.
Generating Microscopic Cross Sections
-------------------------------------
Users can generate the one-group microscopic cross sections needed by
:class:`~openmc.deplete.IndependentOperator` using the
:class:`~openmc.deplete.MicroXS` class::
import openmc
model = openmc.Model.from_xml()
micro_xs = openmc.deplete.MicroXS.from_model(model,
model.materials[0],
chain_file)
The :meth:`~openmc.deplete.MicroXS.from_model()` method will produce a
:class:`~openmc.deplete.MicroXS` object with microscopic cross section data in
units of barns, which is what :class:`~openmc.deplete.IndependentOperator`
expects the units to be. The :class:`~openmc.deplete.MicroXS` class also
includes functions to read in cross section data directly from a ``.csv`` file
or from data arrays::
micro_xs = MicroXS.from_csv(micro_xs_path)
nuclides = ['U234', 'U235', 'U238']
reactions = ['fission', '(n,gamma)']
data = np.array([[0.1, 0.2],
[0.3, 0.4],
[0.01, 0.5]])
micro_xs = MicroXS.from_array(nuclides, reactions, data)
.. important::
Both :meth:`~openmc.deplete.MicroXS.from_csv()` and
:meth:`~openmc.deplete.MicroXS.from_array()` assume the cross section values
provided are in barns by defualt, but have no way of verifying this. Make
sure your cross sections are in the correct units before passing to a
:class:`~openmc.deplete.IndependentOperator` object.
Caveats
-------
Reaction Rate Normalization
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The :class:`~openmc.deplete.IndependentOperator` class supports two methods for
normalizing reaction rates:
.. important::
Make sure you set the correct parameter in the :class:`openmc.abc.Integrator`
class. Use the ``source_rates`` parameter when
``normalization_mode == source-rate``, and use ``power`` or ``power_density``
when ``normalization_mode == fission-q``.
1. ``source-rate`` normalization, which assumes the ``source_rate`` provided by
the time integrator is a flux, and obtains the reaction rates by multiplying
the cross-sections by the ``source-rate``.
2. ``fission-q`` normalization, which uses the ``power`` or ``power_density``
provided by the time integrator to obtain reaction rates by computing a value
for the flux based on this power. The general equation for the flux is
.. math::
\phi = \frac{P}{V \cdot \sum_i (Q_i \cdot \Sigma^f_i \cdot \rho_i)}
where :math:`\sum_i` is the sum over all nuclides :math:`i`. This equation
makes the same assumptions and issues as discussed in
:ref:`energy-deposition`. Unfortunately, the proposed solution in that
section does not apply here since we are decoupled from transport code.
However, there is a method to converge to a more accurate value for flux by
using substeps during time integration.
`This paper <https://doi.org/10.1016/j.anucene.2016.05.031>`_ provides a
good discussion of this method.
.. warning::
The accuracy of results when using ``fission-q`` is entirely dependent on
your depletion chain. Make sure it has sufficient data to resolve the
dynamics of your particular scenario.
Multiple Materials
~~~~~~~~~~~~~~~~~~
Running a depletion simulation with multiple materials using the
``source-rate`` normalization method treats each material as completely
separate with respect to reaction rates. This can be useful for running many
different cases of a particular scenario. However, running a depletion
simulation with multiple materials using the ``fission-q`` normalization method
treats each material as part of the same "reactor" due to how ``fission-q``
normalization accumulates energy values from each material to a single value.
This behavior may change in the future.
Time integration
~~~~~~~~~~~~~~~~
The one-group microscopic cross sections passed to
:class:`openmc.deplete.IndependentOperator` are fixed values for the entire
depletion simulation. This implicit assumption may produce inaccurate results
for certain scenarios.