mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
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:
parent
2bea7f338b
commit
a8768b7845
16 changed files with 1351 additions and 69 deletions
|
|
@ -25,6 +25,7 @@ essential aspects of using OpenMC to perform simulations.
|
|||
processing
|
||||
parallel
|
||||
volume
|
||||
variance_reduction
|
||||
random_ray
|
||||
troubleshoot
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
162
docs/source/usersguide/variance_reduction.rst
Normal file
162
docs/source/usersguide/variance_reduction.rst
Normal 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue