Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FW-CADIS Weight Window Generation with Random Ray #3273

Merged
merged 27 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
840d66b
implemented fw cadis (simplified implementation derived from experime…
jtramm Jan 16, 2025
6b808bb
Fixed solvertype namespace issue
jtramm Jan 16, 2025
638c831
added initial variance reduction methods docs
jtramm Jan 17, 2025
be9b2f4
added variance reduction user guide
jtramm Jan 17, 2025
e377b6b
edits to variance reduction docs
jtramm Jan 17, 2025
c56860d
edits to variance reduction docs
jtramm Jan 17, 2025
87fd95f
Added more docs to variance reduction, and moved the MGXS workflow ou…
jtramm Jan 21, 2025
deffc12
added new weight window testing harness, and added FW-CADIS random ra…
jtramm Jan 22, 2025
84ce0dc
altered interface for using FW-CADIS. Now the method needs to be spec…
jtramm Jan 22, 2025
91c09d1
force adjoint to be on if FW-CADIS is selected
jtramm Jan 22, 2025
26883f8
switched to check for random ray and adjoint solve to decide if we wa…
jtramm Jan 22, 2025
de80a86
updated python interface to accommodate fw_cadis, and changed test to…
jtramm Jan 22, 2025
5899f29
more work on updating and cleaning up the docs on variance reduction
jtramm Jan 22, 2025
0f0ca76
Text wrapping on docs
jtramm Jan 22, 2025
8a342ce
docs updates
jtramm Jan 22, 2025
08c2ab0
took out cmakelists.txt change for clang
jtramm Jan 22, 2025
4613816
fixed spacing in cmakelists.txt
jtramm Jan 22, 2025
b322e0f
ran git clang format and spaced the docs
jtramm Jan 22, 2025
eb5bd7f
ran clang-format v15.0.0 on weight_windows.h
jtramm Jan 22, 2025
b7482af
Apply suggestions from @yardasol code review
jtramm Jan 24, 2025
47f7235
updates to docs incorporating @yardasol review comments`
jtramm Jan 24, 2025
c49c3e4
docs typo fix
jtramm Jan 24, 2025
bddc770
Edits in documentation
paulromano Jan 24, 2025
bb776a8
Small changes
paulromano Jan 24, 2025
5e1fb89
commit comments on docs from @yardasol review`
jtramm Jan 27, 2025
39e35c9
refactored update_magic to update_weights, and included passing in of…
jtramm Jan 27, 2025
866b301
finished refactor
jtramm Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/io_formats/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ mesh-based weight windows.
*Default*: true

:method:
Method used to update weight window values (currently only 'magic' is supported)
Method used to update weight window values (one of 'magic' or 'fw_cadis')

*Default*: magic

Expand Down
1 change: 1 addition & 0 deletions docs/source/methods/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ Theory and Methodology
energy_deposition
parallelization
cmfd
variance_reduction
random_ray
2 changes: 2 additions & 0 deletions docs/source/methods/random_ray.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,8 @@ random ray and Monte Carlo, however.
develop the scattering source by way of inactive batches before beginning
active batches.

.. _adjoint:

------------------------
Adjoint Flux Solver Mode
------------------------
Expand Down
129 changes: 129 additions & 0 deletions docs/source/methods/variance_reduction.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
.. _methods_variance_reduction:

==================
Variance Reduction
==================

.. _methods_variance_reduction_intro:

------------
Introduction
------------

Transport problems can sometimes infolve a significant degree of attenuation
jtramm marked this conversation as resolved.
Show resolved Hide resolved
between the neutron source and a detector (tally) region, which can result in a
flux differential of ten orders of magnitude (or more) throughout the simulation
domain. As Monte Carlo uncertainties tend to be inversely proportional to the
physical flux density, it can be extremely difficult to accurately resolve
tallies in locations that are optically far from the source. This issue is
particularly common in fixed source simulations, where some tally locations may
not experience a single scoring event, even after billions of analog histories.

Variance reduction techniques aim to either flatten the global uncertainty
distribution, such that all regions of phase space have a fairly similar
uncertainty, or to reduce the uncertainty in specific locations (such as a
detector). There are two strategies available in OpenMC for variance reduction:
the Monte Carlo MAGIC method, and with FW-CADIS. Both strategies work by
jtramm marked this conversation as resolved.
Show resolved Hide resolved
developing a weight window mesh, which can be utilized by subsequent Monte Carlo
solves to split particles heading towards areas of lower flux densities while
terminating particles in higher flux regions -- all while maintaining a fair
game.

------------
MAGIC Method
------------

The MAGIC method is an iterative technique that uses spatial flux information
(:math:`\phi(r)`) obtained from a normal Monte Carlo solve to produce weight
jtramm marked this conversation as resolved.
Show resolved Hide resolved
windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte
jtramm marked this conversation as resolved.
Show resolved Hide resolved
Carlo. While the first generation of weight windows produced may only help to
reduce variance slightly, use of these weights to generate another set of weight
windows results in a progressively improving iterative scheme.

Equation :eq:`magic` defines how the lower bound of weight windows
(:math:`\w_\ell(r)`) are generated with MAGIC using forward flux information.
jtramm marked this conversation as resolved.
Show resolved Hide resolved
Here, we can see that the flux at location :math:`r` is normalized by the
maximum flux in any group at that location. We can also see that the weights are
divided by a factor of two, which accounts for the typical :math:`5\times`
factor separating the lower and upper weight window bounds in OpenMC.

.. math::
:label: magic

w_\ell(r) = \frac{\phi(r)}{2\text{max}(\phi(r))}

A major advantage of this technique is that it does not require any special
transport machinery -- it simply uses multiple Monte Carlo simulations to
iteratively improve a set of weight windows (which are typically defined on a
mesh covering the simulation domain). The downside to this method is that as the
flux differential increases between areas near and far from the source, it
requires more outer Monte Carlo iterations, each of which can be highly
expensive in itself. Additionally, computation of weight windows based on
regular (forward) neutron flux tally information does not produce the most
numerically effective set of weight windows. Nonetheless, MAGIC remains a simple
and effective technique for generating weight windows.

--------
FW-CADIS
--------

As discussed in the previous section, computation of weight windows based on
regular (forward) neutron flux tally information does not produce the most
numerically efficient set of weight windows. It is highly preferable to generate
weight windows based on spatial adjoint flux (:math:`\phi^{\dag}(r)`)
information. The adjoint flux is essentially the "reverse" simulation problem,
where we sample a random point and assume this is where a particle was absorbed,
and then trace it backwards (upscattering in energy), until we sample the point
where it was born from.

The FW-CADIS method produces weight windows for global variance reduction given
adjoint flux information throughout the entire domain. It is defined in Equation
:eq:`fw_cadis`, and also involves a normalization step not shown here.
jtramm marked this conversation as resolved.
Show resolved Hide resolved

.. math::
:label: fw_cadis

w_\ell(r) = \frac{1}{2\phi^{\dag}(r)}

While the algorithm itself is quite simple, it requires estimates of the global
adjoint flux distribution, which is difficult to generate directly with Monte
Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often
deterministic) that can be more readily adapted for generating adjoint flux
information, and which is often much cheaper than Monte Carlo given that
maximal-fidelity is not needed for weight window generation.

The FW-CADIS implementation in OpenMC utilizes its own internal random ray
multigroup transport solver to generate the adjoint source distribution. No
coupling to any external transport is solver is necessary. The random ray solver
operates on the same geometry as the Monte Carlo solver, so no redefinition of
the simulation geometry is required. More details on how the adjoint flux is
computed are given in the :ref:`adjoint methods section <adjoint>`.

More information on the workflow is available in the :ref:`user guide
<variance_reduction>`, but generally production of weight windows with FW-CADIS
involves several stages (some of which are highly automated). These tasks
include generation of approximate multigroup cross section data for use by the
random ray solver, running of the random ray solver in normal (forward flux)
mode to generate a source for the adjoint solver, running of the random ray
solver in adjoint mode to generate adjoint flux tallies, and finally the
production of weight windows via the FW-CADIS method. As is discussed in the
user guide, most of these steps are automated together, making the additional
burden on the user fairly small.

The major advantage of this technique is that it typically produces much more
numerically efficient weight windows as compared to those generated with MAGIC,
sometimes with an improvement on the variance vs. runtime figure of merit
(Equation :eq:`variance_fom`) of an order of magnitude. Another major advantage
is that the cost of the random ray solver is typically negligible compared to
the cost of the subsequent Monte Carlo solve itself, making it a very cheap
method to deploy. The downside to this method is that it introduces a second
transport method into the mix (random ray), such that there are more free input
parameters for the user to know about and adjust, potentially making the method
more complex to use. However, as many of the parameters have natural choices,
much of this parameterization can be handled automatically behind the scenes
without the need for the user to be aware of this.

.. math::
:label: variance_fom

\text{FOM} = \frac{1}{\text{Time} \times \sigma^2}
1 change: 1 addition & 0 deletions docs/source/usersguide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ essential aspects of using OpenMC to perform simulations.
processing
parallel
volume
variance_reduction
random_ray
troubleshoot

181 changes: 177 additions & 4 deletions docs/source/usersguide/random_ray.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand All @@ -447,6 +448,178 @@ 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)
-------------------------------------------
paulromano marked this conversation as resolved.
Show resolved Hide resolved

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 several continuous energy materials::

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])

and make the necessary changes to turn them into multigroup library materials
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"

paulromano marked this conversation as resolved.
Show resolved Hide resolved
--------------
Linear Sources
--------------
Expand Down
Loading
Loading