FW-CADIS Weight Window Generation with Random Ray (#3273)

Co-authored-by: Olek <45364492+yardasol@users.noreply.github.com>
Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
John Tramm 2025-01-27 22:54:32 -06:00 committed by GitHub
parent 2bea7f338b
commit a8768b7845
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1351 additions and 69 deletions

View file

@ -25,6 +25,7 @@ essential aspects of using OpenMC to perform simulations.
processing
parallel
volume
variance_reduction
random_ray
troubleshoot

View file

@ -435,10 +435,11 @@ Inputting Multigroup Cross Sections (MGXS)
Multigroup cross sections for use with OpenMC's random ray solver are input the
same way as with OpenMC's traditional multigroup Monte Carlo mode. There is more
information on generating multigroup cross sections via OpenMC in the
:ref:`multigroup materials <create_mgxs>` user guide. You may also wish to
use an existing multigroup library. An example of using OpenMC's Python
interface to generate a correctly formatted ``mgxs.h5`` input file is given
in the `OpenMC Jupyter notebook collection
:ref:`multigroup materials <create_mgxs>` user guide. You may also wish to use
an existing ``mgxs.h5`` MGXS library file, or define your own given a known set
of cross section data values (e.g., as taken from a benchmark specification). An
example of using OpenMC's Python interface to generate a correctly formatted
``mgxs.h5`` input file is given in the `OpenMC Jupyter notebook collection
<https://nbviewer.org/github/openmc-dev/openmc-notebooks/blob/main/mg-mode-part-i.ipynb>`_.
.. note::
@ -447,6 +448,184 @@ in the `OpenMC Jupyter notebook collection
separate materials can be defined each with a separate multigroup dataset
corresponding to a given temperature.
.. _mgxs_gen:
-------------------------------------------
Generating Multigroup Cross Sections (MGXS)
-------------------------------------------
OpenMC is capable of generating multigroup cross sections by way of flux
collapsing data based on flux solutions obtained from a continuous energy Monte
Carlo solve. While it is a circular excercise in some respects to use continuous
energy Monte Carlo to generate cross sections to be used by a reduced-fidelity
multigroup transport solver, there are many use cases where this is nonetheless
highly desirable. For instance, generation of a multigroup library may enable
the same set of approximate multigroup cross section data to be used across a
variety of problem types (or through a multidimensional parameter sweep of
design variables) with only modest errors and at greatly reduced cost as
compared to using only continuous energy Monte Carlo.
We give here a quick summary of how to produce a multigroup cross section data
file (``mgxs.h5``) from a starting point of a typical continuous energy Monte
Carlo input file. Notably, continuous energy input files define materials as a
mixture of nuclides with different densities, whereas multigroup materials are
simply defined by which name they correspond to in a ``mgxs.h5`` library file.
To generate the cross section data, we begin with a continuous energy Monte
Carlo input deck and add in the required tallies that will be needed to generate
our library. In this example, we will specify material-wise cross sections and a
two group energy decomposition::
# Define geometry
...
...
geometry = openmc.Geometry()
...
...
# Initialize MGXS library with a finished OpenMC geometry object
mgxs_lib = openmc.mgxs.Library(geometry)
# Pick energy group structure
groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2'])
mgxs_lib.energy_groups = groups
# Disable transport correction
mgxs_lib.correction = None
# Specify needed cross sections for random ray
mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',
'nu-scatter matrix', 'multiplicity matrix', 'chi']
# Specify a "cell" domain type for the cross section tally filters
mgxs_lib.domain_type = "material"
# Specify the cell domains over which to compute multi-group cross sections
mgxs_lib.domains = geom.get_all_materials().values()
# Do not compute cross sections on a nuclide-by-nuclide basis
mgxs_lib.by_nuclide = False
# Check the library - if no errors are raised, then the library is satisfactory.
mgxs_lib.check_library_for_openmc_mgxs()
# Construct all tallies needed for the multi-group cross section library
mgxs_lib.build_library()
# Create a "tallies.xml" file for the MGXS Library
tallies = openmc.Tallies()
mgxs_lib.add_to_tallies_file(tallies, merge=True)
# Export
tallies.export_to_xml()
...
When selecting an energy decomposition, you can manually define group boundaries
or pick out a group structure already known to OpenMC (a list of which can be
found at :class:`openmc.mgxs.GROUP_STRUCTURES`). Once the above input deck has
been run, the resulting statepoint file will contain the needed flux and
reaction rate tally data so that a MGXS library file can be generated. Below is
the postprocessing script needed to generate the ``mgxs.h5`` library file given
a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g.,
``summary.h5``) that resulted from running our previous example::
import openmc
import openmc.mgxs as mgxs
summary = openmc.Summary('summary.h5')
geom = summary.geometry
mats = summary.materials
statepoint_filename = 'statepoint.100.h5'
sp = openmc.StatePoint(statepoint_filename)
groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2'])
mgxs_lib = openmc.mgxs.Library(geom)
mgxs_lib.energy_groups = groups
mgxs_lib.correction = None
mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',
'nu-scatter matrix', 'multiplicity matrix', 'chi']
# Specify a "cell" domain type for the cross section tally filters
mgxs_lib.domain_type = "material"
# Specify the cell domains over which to compute multi-group cross sections
mgxs_lib.domains = geom.get_all_materials().values()
# Do not compute cross sections on a nuclide-by-nuclide basis
mgxs_lib.by_nuclide = False
# Check the library - if no errors are raised, then the library is satisfactory.
mgxs_lib.check_library_for_openmc_mgxs()
# Construct all tallies needed for the multi-group cross section library
mgxs_lib.build_library()
mgxs_lib.load_from_statepoint(sp)
names = []
for mat in mgxs_lib.domains: names.append(mat.name)
# Create a MGXS File which can then be written to disk
mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names)
# Write the file to disk using the default filename of "mgxs.h5"
mgxs_file.export_to_hdf5("mgxs.h5")
Notably, the postprocessing script needs to match the same
:class:`openmc.mgxs.Library` settings that were used to generate the tallies,
but otherwise is able to discern the rest of the simulation details from the
statepoint and summary files. Once the postprocessing script is successfully
run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC.
If you want to convert continuous energy material objects in an OpenMC input
deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below
example. Here we begin with the original continuous energy materials we used to
generate our MGXS library::
fuel = openmc.Material(name='UO2 (2.4%)')
fuel.set_density('g/cm3', 10.29769)
fuel.add_nuclide('U234', 4.4843e-6)
fuel.add_nuclide('U235', 5.5815e-4)
fuel.add_nuclide('U238', 2.2408e-2)
fuel.add_nuclide('O16', 4.5829e-2)
water = openmc.Material(name='Hot borated water')
water.set_density('g/cm3', 0.740582)
water.add_nuclide('H1', 4.9457e-2)
water.add_nuclide('O16', 2.4672e-2)
water.add_nuclide('B10', 8.0042e-6)
water.add_nuclide('B11', 3.2218e-5)
water.add_s_alpha_beta('c_H_in_H2O')
materials = openmc.Materials([fuel, water])
Once the ``mgxs.h5`` library file has been generated, we can then manually make
the necessary edits to the material definitions so that they load from the
multigroup library instead of defining their isotopic contents, as::
# Instantiate some Macroscopic Data
fuel_data = openmc.Macroscopic('UO2 (2.4%)')
water_data = openmc.Macroscopic('Hot borated water')
# Instantiate some Materials and register the appropriate Macroscopic objects
fuel= openmc.Material(name='UO2 (2.4%)')
fuel.set_density('macro', 1.0)
fuel.add_macroscopic(fuel_data)
water= openmc.Material(name='Hot borated water')
water.set_density('macro', 1.0)
water.add_macroscopic(water_data)
# Instantiate a Materials collection and export to XML
materials = openmc.Materials([fuel, water])
materials.cross_sections = "mgxs.h5"
In the above example, our ``fuel`` and ``water`` materials will now load MGXS
data from the ``mgxs.h5`` file instead of loading continuous energy isotopic
cross section data.
--------------
Linear Sources
--------------
@ -597,9 +776,7 @@ estimator, the following code would be used:
Adjoint Flux Mode
-----------------
The adjoint flux random ray solver mode can be enabled as:
entire
::
The adjoint flux random ray solver mode can be enabled as::
settings.random_ray['adjoint'] = True

View file

@ -0,0 +1,162 @@
.. _variance_reduction:
==================
Variance Reduction
==================
Global variance reduction in OpenMC is accomplished by weight windowing
techniques. OpenMC is capable of generating weight windows using either the
MAGIC or FW-CADIS methods. Both techniques will produce a ``weight_windows.h5``
file that can be loaded and used later on. In this section, we break down the
steps required to both generate and then apply weight windows.
.. _ww_generator:
------------------------------------
Generating 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. 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 agressively 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.
------------------------------------------------------
Generating 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. 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 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. Produce approximate multigroup cross section data (stored in a ``mgxs.h5``
library). There is more information on generating multigroup cross sections
via OpenMC in the :ref:`multigroup materials <create_mgxs>` user guide, and a
specific example of generating cross section data for use with random ray in
the :ref:`random ray MGXS guide <mgxs_gen>`.
2. Make a copy of your continuous energy Python input file. You'll edit the new
file to work in multigroup mode with random ray for producing weight windows.
3. Adjust the material definitions in your new multigroup Python file to utilize
the multigroup cross sections instead of nuclide-wise continuous energy data.
There is a specific example of making this conversion in the :ref:`random ray
MGXS guide <mgxs_gen>`.
4. Configure OpenMC to run in random ray mode (by adding several standard random
ray input flags and settings to the :attr:`openmc.Settings.random_ray`
dictionary). More information can be found in the :ref:`Random Ray User
Guide <random_ray>`.
5. 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"``::
# 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='fw_cadis',
mesh=ww_mesh,
max_realizations=settings.batches
)
# 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 cells in the problem. In the future, this
restriction is intended to be relaxed, but for now subdivision of cells by a
mesh tally will result in undefined behavior.
6. 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 = openmc.hdf5_to_wws('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.