OpenMC/docs/source/usersguide/variance_reduction.rst
2026-04-28 16:10:03 -05:00

373 lines
16 KiB
ReStructuredText

.. _variance_reduction:
==================
Variance Reduction
==================
Global and local variance reduction are possible in OpenMC through both weight
windowing and source biasing techniques. OpenMC is capable of generating weight
windows using either the MAGIC or FW-CADIS methods, the latter with an optional
capability for local variance reduction. Both techniques will produce a
``weight_windows.h5`` file that can be loaded and used later on. In
this section, we first break down the steps required to generate and apply
weight windows, then describe how source biasing may be applied.
.. _ww_generator:
-------------------------------------------
Generating Global Weight Windows with MAGIC
-------------------------------------------
As discussed in the :ref:`methods section <methods_variance_reduction>`, MAGIC
is an iterative method that uses flux tally information from a Monte Carlo
simulation to produce weight windows for a user-defined mesh with the objective
of global variance reduction. While generating the weight windows, OpenMC is
capable of applying the weight windows generated from a previous batch while
processing the next batch, allowing for progressive improvement in the weight
window quality across iterations.
The typical way of generating weight windows is to define a mesh and then add an
:class:`openmc.WeightWindowGenerator` object to an :attr:`openmc.Settings`
instance, as follows::
# Define weight window spatial mesh
ww_mesh = openmc.RegularMesh()
ww_mesh.dimension = (10, 10, 10)
ww_mesh.lower_left = (0.0, 0.0, 0.0)
ww_mesh.upper_right = (100.0, 100.0, 100.0)
# Create weight window object and adjust parameters
wwg = openmc.WeightWindowGenerator(
method='magic',
mesh=ww_mesh,
max_realizations=settings.batches
)
# Add generator to Settings instance
settings.weight_window_generators = wwg
Notably, the :attr:`max_realizations` attribute is adjusted to the number of
batches, such that all iterations are used to refine the weight window
parameters.
With the :class:`~openmc.WeightWindowGenerator` instance added to the
:attr:`~openmc.Settings`, the rest of the problem can be defined as normal. When
running, note that the second iteration and beyond may be several orders of
magnitude slower than the first. As the weight windows are applied in each
iteration, particles may be aggressively split, resulting in a large number of
secondary (split) particles being generated per initial source particle. This is
not necessarily a bad thing, as the split particles are much more efficient at
exploring low flux regions of phase space as compared to initial particles.
Thus, even though the reported "particles/second" metric of OpenMC may be much
lower when generating (or just applying) weight windows as compared to analog
MC, it typically leads to an overall improvement in the figure of merit
accounting for the reduction in the variance.
.. warning::
The number of particles per batch may need to be adjusted downward
significantly to result in reasonable runtimes when weight windows are being
generated or used.
At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk
for later use. Loading it in another subsequent simulation will be discussed in
the "Using Weight Windows" section below.
.. _usersguide_fw_cadis:
----------------------------------------------------------------------
Generating Global or Local Weight Windows with FW-CADIS and Random Ray
----------------------------------------------------------------------
Weight window generation with FW-CADIS and random ray in OpenMC uses the same
exact strategy as with MAGIC. Using FW-CADIS, however, also enables
local variance reduction in fixed source problems through the :attr:`targets`
attribute, which is described later in this section. To enable FW-CADIS, an
:class:`openmc.WeightWindowGenerator` object is added to the
:attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be generated
at the end of the simulation. The only procedural difference is that the code
must be run in random ray mode. A full description of how to enable and setup
random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
.. note::
It is a long term goal for OpenMC to be able to generate FW-CADIS weight
windows with only a few tweaks to an existing continuous energy Monte Carlo
input deck. However, at the present time, the workflow requires several
steps to generate multigroup cross section data and to configure the random
ray solver. A high level overview of the current workflow for generation of
weight windows with FW-CADIS using random ray is given below.
1. Begin by making a deep copy of your continuous energy Python model and then
convert the copy to be multigroup and use the random ray transport solver.
The conversion process can largely be automated as described in more detail
in the :ref:`random ray quick start guide <quick_start>`, summarized below::
# Define continuous energy model
ce_model = openmc.pwr_pin_cell() # example, replace with your model
# Make a copy to convert to multigroup and random ray
model = copy.deepcopy(ce_model)
# Convert model to multigroup (will auto-generate MGXS library if needed)
model.convert_to_multigroup()
# Convert model to random ray and initialize random ray parameters
# to reasonable defaults based on the specifics of the geometry
model.convert_to_random_ray()
# (Optional) Overlay source region decomposition mesh to improve fidelity of the
# random ray solver. Adjust 'n' for fidelity vs runtime.
n = 10
mesh = openmc.RegularMesh()
mesh.dimension = (n, n, n)
mesh.lower_left = model.geometry.bounding_box.lower_left
mesh.upper_right = model.geometry.bounding_box.upper_right
model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])]
# (Optional) Improve fidelity of the random ray solver by enabling linear sources
model.settings.random_ray['source_shape'] = 'linear'
# (Optional) Increase the number of rays/batch, to reduce uncertainty
model.settings.particles = 500
If you need to improve the fidelity of the MGXS library, there is more
information on generating multigroup cross sections via OpenMC in the
:ref:`random ray MGXS guide <mgxs_gen>`.
2. Add in a :class:`~openmc.WeightWindowGenerator` in a similar manner as for
MAGIC generation with Monte Carlo and set the :attr:`method` attribute set to
``"fw_cadis"``::
# Create weight window object and adjust parameters, using the same mesh
# we used for source region decomposition
wwg = openmc.WeightWindowGenerator(
method='fw_cadis',
mesh=mesh
)
# Add generator to openmc.settings object
settings.weight_window_generators = wwg
.. warning::
If using FW-CADIS weight window generation, ensure that the selected weight
window mesh does not subdivide any source regions in the problem. This can
be ensured by using the same mesh for both source region subdivision (i.e.,
assigning to ``model.settings.random_ray['source_region_meshes']``) and for
weight window generation.
3. (Optional) If local variance reduction is desired in a fixed-source problem,
populate the :attr:`targets` attribute with an :class:`openmc.Tallies`
instance or an iterable of tally IDs indicating the tallies of interest for
variance reduction::
# Build a new example and WWG for local variance reduction
from openmc.examples import random_ray_three_region_cube_with_detectors
new_model = random_ray_three_region_cube_with_detectors()
ww_mesh = openmc.RegularMesh()
n = 7
width = 35.0
ww_mesh.dimension = (n, n, n)
ww_mesh.lower_left = (0.0, 0.0, 0.0)
ww_mesh.upper_right = (width, width, width)
wwg = openmc.WeightWindowGenerator(
method="fw_cadis",
mesh=ww_mesh,
max_realizations=new_model.settings.batches
)
new_model.settings.weight_window_generators = wwg
new_model.settings.random_ray['volume_estimator'] = 'naive'
# Get the tallies of interest
target_tallies = openmc.Tallies()
for tally in list(new_model.tallies):
if tally.name in {"Detector 1 Tally", "Detector 2 Tally"}:
target_tallies.append(tally)
# Add to WeightWindowGenerator
wwg.targets = target_tallies
.. warning::
The tallies designated as FW-CADIS targets to the
:class:`~openmc.WeightWindowGenerator` must be present under the
:class:`~openmc.model.Model.tallies` attribute of the
:class:`~openmc.model.Model` as well in order to be recognized as valid
local variance reduction targets. This check is performed when the
:func:`openmc.model.Model.export_to_model_xml` or
:func:`openmc.model.Model.export_to_xml` functions are called, meaning
that the standalone :func:`openmc.Settings.export_to_xml` and
:func:`openmc.Tallies.export_to_xml` methods should not be used with
FW-CADIS local variance reduction.
4. When running your multigroup random ray input deck, OpenMC will automatically
run a forward solve followed by an adjoint solve, with a
``weight_windows.h5`` file generated at the end. The ``weight_windows.h5``
file will contain FW-CADIS generated weight windows. This file can be used in
identical manner as one generated with MAGIC, as described below.
--------------------
Using Weight Windows
--------------------
To use a ``weight_windows.h5`` weight window file with OpenMC's Monte Carlo
solver, the Python input just needs to load the h5 file::
settings.weight_window_checkpoints = {'collision': True, 'surface': True}
settings.survival_biasing = False
settings.weight_windows_file = "weight_windows.h5"
settings.weight_windows_on = True
The :class:`~openmc.WeightWindowGenerator` instance is not needed to load an
existing ``weight_windows.h5`` file. Inclusion of a
:class:`~openmc.WeightWindowGenerator` instance will cause OpenMC to generate
*new* weight windows and thus overwrite the existing ``weight_windows.h5`` file.
Weight window mesh information is embedded into the weight window file, so the
mesh does not need to be redefined. Monte Carlo solves that load a weight window
file as above will utilize weight windows to reduce the variance of the
simulation.
.. _source_biasing:
--------------
Source Biasing
--------------
In fixed source problems, source biasing provides a means to reduce the variance
on global or localized responses, depending on the biasing scheme. In either
case, the premise of the method is to sample source sites from a biased
distribution that directs a larger fraction of the simulated histories towards
phase space regions of interest than would be found there under analog sampling.
In order to preserve an unbiased estimate of the tally mean, the weight of these
with analog sampling, divided by the probability assigned by the biased
distribution. While the assignment of statistical weights is outlined in the
:ref:`methods section <methods_source_biasing>`, this section demonstrates the
implementation of source biasing to problems in OpenMC.
Source biasing in OpenMC is accomplished by applying a distribution to the
:attr:`bias` attribute of one or more of the univariate or independent
multivariate distributions which make up an :class:`~openmc.IndependentSource`
instance as follows::
# First create the biased distribution
biased_dist = openmc.stats.PowerLaw(a=0, b=3, n=3)
# Construct a new distribution with the bias applied
dist = openmc.stats.PowerLaw(a=0, b=3, n=2, bias=biased_dist)
# The bias attribute can also be set on an existing "analog" distribution:
sphere_dist = openmc.stats.spherical_uniform(r_outer=3)
sphere_dist.r.bias = biased_dist
Univariate distributions may be sampled via the Python API, returning the
sample(s) along with the associated weight(s)::
sample_vec, wgt_vec = dist.sample(n_samples=100)
Here, if the distribution is unbiased, the weight of each sample will be unity.
Finally, :class:`~openmc.IndependentSource` instances can be constructed with
biased distributions::
# Create a source with a biased spatial distribution
source = openmc.IndependentSource(space=sphere_dist)
During the simulation, source sites are then sampled using the biased
distributions where available and given starting statistical weights
corresponding to the cumulative product of the weights assigned by each
distribution in the source object. Hence multiple source variables (e.g.,
direction and energy) may be biased and the resulting source sites will have
their weights adjusted accordingly.
.. note::
Combining source biasing with weight windows can be a powerful variance
reduction technique if each is constructed appropriately for the response
of interest. For example, if a source biasing scheme is devised for
variance reduction of a specific localized response, the user may be able
to specify their own weight window structure that results in more efficient
transport than if weight windows were generated by either of OpenMC's
automatic weight window generators, which are intended for global variance
reduction.
Biased distributions that could result in degenerate weight mappings are not
recommended; this is most commonly seen when biasing the :math:`\phi`-coordinate
of spherical or cylindrical independent multivariate distributions. In such
cases degenerate behavior will be observed at the pole about which :math:`\phi`
is measured, with all values of :math:`\phi` (hence many possible statistical
weights) mapping to the same point for :math:`r=0` or :math:`\mu=0`, and large
weight gradients in the vicinity. In most cases requiring a spherical
independent source, it would be preferable to reorient the reference vector of
the distribution such that biasing could be applied to the
:math:`\mu`-coordinate instead.
When biasing a distribution, care should also be taken to ensure that both the
unbiased and biased distribution share a common support---that is, every region
of phase space mapped to a nonzero probability density by the unbiased
distribution should likewise map to nonzero probability under the biased
distribution, and vice versa. In OpenMC, this places restrictions on the set of
compatible distributions that may be used to bias sampling of each distribution
type. The following table summarizes the method for each distribution in OpenMC
that permits biased sampling.
.. list-table:: **Distributions that support biased sampling**
:header-rows: 1
:widths: 35 65
* - Discrete Univariate PDFs
- Biasing Method
* - :class:`openmc.stats.Discrete`
- Apply a vector of alternative probabilities to the :attr:`bias`
attribute
.. list-table::
:header-rows: 1
:widths: 35 65
* - Continuous Univariate PDFs
- Biasing Method
* - :class:`openmc.stats.Uniform`,
:class:`openmc.stats.PowerLaw`,
:class:`openmc.stats.Maxwell`,
:class:`openmc.stats.Watt`,
:class:`openmc.stats.Normal`,
:class:`openmc.stats.Tabular`
- Apply a second, unbiased continous univariate PDF to the :attr:`bias`
attribute, ensuring that the :attr:`support` attribute of each
distribution is the same
.. list-table::
:header-rows: 1
:widths: 35 65
* - Mixed Univariate PDFs
- Biasing Method
* - :class:`openmc.stats.Mixture`
- May be constructed from multiple biased univariate distributions, or a
second, unbiased continous univariate PDF may be applied to the
:attr:`bias` attribute
.. list-table::
:header-rows: 1
:widths: 35 65
* - Discrete Multivariate PDFs
- Biasing Method
* - :class:`openmc.stats.PointCloud`,
:class:`openmc.stats.MeshSpatial`
- Apply a vector of the new relative probabilities of each point or mesh
element under biased sampling to the :attr:`bias` attribute
.. list-table::
:header-rows: 1
:widths: 35 65
* - Continuous Multivariate PDFs
- Biasing Method
* - :class:`openmc.stats.CartesianIndependent`,
:class:`openmc.stats.CylindricalIndependent`,
:class:`openmc.stats.SphericalIndependent`,
:class:`openmc.stats.PolarAzimuthal`
- Construct from biased univariate distributions for :attr:`x`, :attr:`y`,
:attr:`z`, etc.
* - :class:`openmc.stats.Isotropic`
- Apply an unbiased :class:`openmc.stats.PolarAzimuthal` to the
:attr:`bias` attribute