Skip to content

Commit 368ea06

Browse files
authored
Local adjoint source for Random Ray (#3717)
1 parent 1116c4b commit 368ea06

77 files changed

Lines changed: 2664 additions & 463 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/source/io_formats/settings.rst

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,14 +597,43 @@ found in the :ref:`random ray user guide <random_ray>`.
597597

598598
*Default*: None
599599

600-
:source:
600+
:ray_source:
601601
Specifies the starting ray distribution, and follows the format for
602602
:ref:`source_element`. It must be uniform in space and angle and cover the
603603
full domain. It does not represent a physical neutron or photon source -- it
604604
is only used to sample integrating ray starting locations and directions.
605605

606606
*Default*: None
607607

608+
:adjoint_source:
609+
Specifies an adjoint fixed source for adjoint transport simulations, and
610+
follows the format for :ref:`source_element`. The distributions which make
611+
up the adjoint source are subject to the same restrictions as forward
612+
fixed sources in Random Ray mode.
613+
614+
*Default*: None
615+
616+
:adjoint:
617+
Specifies whether to perform adjoint transport. The default is 'False',
618+
corresponding to forward transport.
619+
620+
*Default*: None
621+
622+
:volume_estimator:
623+
Specifies choice of volume estimator for the random ray solver. Options
624+
are 'naive', 'simulation_averaged', or 'hybrid'. The default is 'hybrid'.
625+
626+
*Default*: None
627+
628+
:volume_normalized_flux_tallies:
629+
Specifies whether to normalize flux tallies by volume (bool). The
630+
default is 'False'. When enabled, flux tallies will be reported in units
631+
of cm/cm^3. When disabled, flux tallies will be reported in units of cm
632+
(i.e., total distance traveled by neutrons in the spatial tally
633+
region).
634+
635+
*Default*: None
636+
608637
:sample_method:
609638
Specifies the method for sampling the starting ray distribution. This
610639
element can be set to "prng" or "halton".
@@ -1696,6 +1725,14 @@ mesh-based weight windows.
16961725
The ratio of the lower to upper weight window bounds.
16971726

16981727
*Default*: 5.0
1728+
1729+
For FW-CADIS:
1730+
1731+
:targets:
1732+
A sequence of IDs corresponding to the tallies which cover phase
1733+
space regions of interest for local variance reduction.
1734+
1735+
*Default*: None
16991736

17001737
---------------------------------------
17011738
``<weight_window_checkpoints>`` Element

docs/source/methods/random_ray.rst

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,28 +1081,32 @@ lifetimes.
10811081

10821082
In OpenMC, the random ray adjoint solver is implemented simply by transposing
10831083
the scattering matrix, swapping :math:`\nu\Sigma_f` and :math:`\chi`, and then
1084-
running a normal transport solve. When no external fixed source is present, no
1085-
additional changes are needed in the transport process. However, if an external
1086-
fixed forward source is present in the simulation problem, then an additional
1087-
step is taken to compute the accompanying fixed adjoint source. In OpenMC, the
1088-
adjoint flux does *not* represent a response function for a particular detector
1089-
region. Rather, the adjoint flux is the global response, making it appropriate
1090-
for use with weight window generation schemes for global variance reduction.
1091-
Thus, if using a fixed source, the external source for the adjoint mode is
1092-
simply computed as being :math:`1 / \phi`, where :math:`\phi` is the forward
1093-
scalar flux that results from a normal forward solve (which OpenMC will run
1094-
first automatically when in adjoint mode). The adjoint external source will be
1095-
computed for each source region in the simulation mesh, independent of any
1096-
tallies. The adjoint external source is always flat, even when a linear
1097-
scattering and fission source shape is used. When in adjoint mode, all reported
1098-
results (e.g., tallies, eigenvalues, etc.) are derived from the adjoint flux,
1099-
even when the physical meaning is not necessarily obvious. These values are
1100-
still reported, though we emphasize that the primary use case for adjoint mode
1101-
is for producing adjoint flux tallies to support subsequent perturbation studies
1102-
and weight window generation.
1103-
1104-
Note that the adjoint :math:`k_{eff}` is statistically the same as the forward
1105-
:math:`k_{eff}`, despite the flux distributions taking different shapes.
1084+
running a normal transport solve. When no external fixed forward source is
1085+
present, or if an adjoint fixed source is specifically provided, no additional
1086+
changes are needed in the transport process. This adjoint source can
1087+
correspond, for example, to a detector response function in a particular
1088+
region. However, if an external fixed forward source is present in the
1089+
simulation problem without an adjoint fixed source, an additional step is taken
1090+
to compute the accompanying forward-weighted adjoint source. In this case, the
1091+
adjoint flux does *not* represent the importance of locations in phase space to
1092+
detector response; rather, the "response" in question is a uniform distribution
1093+
of Monte Carlo particle density, making the importance provided by the adjoint
1094+
flux appropriate for use with weight window generation schemes for global
1095+
variance reduction. Thus, if using a fixed source, the forward-weighted
1096+
external source for adjoint mode is simply computed as being :math:`1 / \phi`,
1097+
where :math:`\phi` is the forward scalar flux that results from a normal
1098+
forward solve (which OpenMC will run first automatically when in adjoint mode).
1099+
The adjoint external source will be computed for each source region in the
1100+
simulation mesh, independent of any tallies. The adjoint external source is
1101+
always flat, even when a linear scattering and fission source shape is used.
1102+
1103+
When in adjoint mode, all reported results (e.g., tallies, eigenvalues, etc.)
1104+
are derived from the adjoint flux, even when the physical meaning is not
1105+
necessarily obvious. These values are still reported, though we emphasize that
1106+
the primary use case for adjoint mode is for producing adjoint flux tallies to
1107+
support subsequent perturbation studies and weight window generation. Note
1108+
however that the adjoint :math:`k_{eff}` is statistically the same as the
1109+
forward :math:`k_{eff}`, despite the flux distributions taking different shapes.
11061110

11071111
---------------------------
11081112
Fundamental Sources of Bias

docs/source/methods/variance_reduction.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ where it was born from.
8282

8383
The Forward-Weighted Consistent Adjoint Driven Importance Sampling method, or
8484
`FW-CADIS method <https://doi.org/10.13182/NSE12-33>`_, produces weight windows
85-
for global variance reduction given adjoint flux information throughout the
86-
entire domain. The weight window lower bound is defined in Equation
85+
for global or local variance reduction given adjoint flux information throughout
86+
the entire domain. The weight window lower bound is defined in Equation
8787
:eq:`fw_cadis`, and also involves a normalization step not shown here.
8888

8989
.. math::
@@ -135,6 +135,18 @@ aware of this.
135135
136136
\text{FOM} = \frac{1}{\text{Time} \times \sigma^2}
137137
138+
Finally, one unique capability of the FW-CADIS weight window generator is to
139+
produce weight windows for local variance reduction, given a list of the
140+
responses of interest. This is controlled by optionally specifying target
141+
tallies from the :class:`openmc.model.Model` to the
142+
:class:`openmc.WeightWindowGenerator`, as illustrated in the
143+
:ref:`user guide<variance_reduction>`. If target tallies for local variance
144+
reduction are supplied, then the adjoint sources are only populated after the
145+
initial forward simulation in the source regions associated with those tallies.
146+
In other regions, the adjoint source term is instead set to zero. The Random
147+
Ray solver then determines the adjoint flux map used to generate FW-CADIS
148+
weight windows following the usual technique.
149+
138150
.. _methods_source_biasing:
139151

140152
--------------

docs/source/usersguide/random_ray.rst

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,8 @@ as::
944944
which will greatly improve the quality of the linear source term in 2D
945945
simulations.
946946

947+
.. _usersguide_random_ray_run_modes:
948+
947949
---------------------------------
948950
Fixed Source and Eigenvalue Modes
949951
---------------------------------
@@ -1073,22 +1075,47 @@ The adjoint flux random ray solver mode can be enabled as::
10731075

10741076
settings.random_ray['adjoint'] = True
10751077

1076-
When enabled, OpenMC will first run a forward transport simulation followed by
1077-
an adjoint transport simulation. The purpose of the forward solve is to compute
1078-
the adjoint external source when an external source is present in the
1079-
simulation. Simulation settings (e.g., number of rays, batches, etc.) will be
1080-
identical for both simulations. At the conclusion of the run, all results (e.g.,
1081-
tallies, plots, etc.) will be derived from the adjoint flux rather than the
1082-
forward flux but are not labeled any differently. The initial forward flux
1083-
solution will not be stored or available in the final statepoint file. Those
1084-
wishing to do analysis requiring both the forward and adjoint solutions will
1085-
need to run two separate simulations and load both statepoint files.
1078+
When enabled, OpenMC will first run a forward transport simulation if there are
1079+
no user-specified adjoint sources present, followed by an adjoint transport
1080+
simulation. Fixed adjoint sources can be specified on the
1081+
:attr:`openmc.Settings.random_ray` dictionary as follows::
1082+
1083+
# Geometry definition
1084+
...
1085+
detector_cell = openmc.Cell(fill=detector_mat, name='cell where detector will be')
1086+
...
1087+
# Define fixed adjoint neutron source
1088+
strengths = [1.0]
1089+
midpoints = [1.0e-4]
1090+
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
1091+
1092+
adj_source = openmc.IndependentSource(
1093+
energy=energy_distribution,
1094+
constraints={'domains': [detector_cell]}
1095+
)
1096+
1097+
# Add to random_ray dict
1098+
settings.random_ray['adjoint_source'] = adj_source
1099+
1100+
The same constraints apply to the user-defined adjoint source as to the forward
1101+
source, described in the :ref:`Fixed Source and Eigenvalue section
1102+
<usersguide_random_ray_run_modes>`. If this source is not provided, a forward
1103+
solve must take place to compute the adjoint external source when a forward
1104+
external source is present in the problem. Simulation settings (e.g., number of
1105+
rays, batches, etc.) will be identical for both calculations. At the
1106+
conclusion of the run, all results (e.g., tallies, plots, etc.) will be
1107+
derived from the adjoint flux rather than the forward flux but are not labeled
1108+
any differently. The initial forward flux solution will not be stored or
1109+
available in the final statepoint file. Those wishing to do analysis requiring
1110+
both the forward and adjoint solutions will need to run two separate
1111+
simulations and load both statepoint files.
10861112

10871113
.. note::
1088-
When adjoint mode is selected, OpenMC will always perform a full forward
1089-
solve and then run a full adjoint solve immediately afterwards. Statepoint
1090-
and tally results will be derived from the adjoint flux, but will not be
1091-
labeled any differently.
1114+
Use of the automated
1115+
:ref:`FW-CADIS weight window generator<usersguide_fw_cadis>` is not
1116+
currently compatible with user-defined adjoint sources. Instead, the
1117+
initial forward calculation is used to assign "forward-weighted" adjoint
1118+
sources to the tally regions of interest.
10921119

10931120
---------------------------------------
10941121
Putting it All Together: Example Inputs

docs/source/usersguide/variance_reduction.rst

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,27 @@
44
Variance Reduction
55
==================
66

7-
Global variance reduction in OpenMC is accomplished by weight windowing
8-
or source biasing techniques, the latter of which additionally provides a
9-
local variance reduction capability. OpenMC is capable of generating weight
10-
windows using either the MAGIC or FW-CADIS methods. Both techniques will
11-
produce a ``weight_windows.h5`` file that can be loaded and used later on. In
7+
Global and local variance reduction are possible in OpenMC through both weight
8+
windowing and source biasing techniques. OpenMC is capable of generating weight
9+
windows using either the MAGIC or FW-CADIS methods, the latter with an optional
10+
capability for local variance reduction. Both techniques will produce a
11+
``weight_windows.h5`` file that can be loaded and used later on. In
1212
this section, we first break down the steps required to generate and apply
1313
weight windows, then describe how source biasing may be applied.
1414

1515
.. _ww_generator:
1616

17-
------------------------------------
18-
Generating Weight Windows with MAGIC
19-
------------------------------------
17+
-------------------------------------------
18+
Generating Global Weight Windows with MAGIC
19+
-------------------------------------------
2020

2121
As discussed in the :ref:`methods section <methods_variance_reduction>`, MAGIC
2222
is an iterative method that uses flux tally information from a Monte Carlo
23-
simulation to produce weight windows for a user-defined mesh. While generating
24-
the weight windows, OpenMC is capable of applying the weight windows generated
25-
from a previous batch while processing the next batch, allowing for progressive
26-
improvement in the weight window quality across iterations.
23+
simulation to produce weight windows for a user-defined mesh with the objective
24+
of global variance reduction. While generating the weight windows, OpenMC is
25+
capable of applying the weight windows generated from a previous batch while
26+
processing the next batch, allowing for progressive improvement in the weight
27+
window quality across iterations.
2728

2829
The typical way of generating weight windows is to define a mesh and then add an
2930
:class:`openmc.WeightWindowGenerator` object to an :attr:`openmc.Settings`
@@ -71,15 +72,20 @@ At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk
7172
for later use. Loading it in another subsequent simulation will be discussed in
7273
the "Using Weight Windows" section below.
7374

74-
------------------------------------------------------
75-
Generating Weight Windows with FW-CADIS and Random Ray
76-
------------------------------------------------------
75+
.. _usersguide_fw_cadis:
76+
77+
----------------------------------------------------------------------
78+
Generating Global or Local Weight Windows with FW-CADIS and Random Ray
79+
----------------------------------------------------------------------
7780

7881
Weight window generation with FW-CADIS and random ray in OpenMC uses the same
79-
exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is
80-
added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be
81-
generated at the end of the simulation. The only difference is that the code
82-
must be run in random ray mode. A full description of how to enable and setup
82+
exact strategy as with MAGIC. Using FW-CADIS, however, also enables
83+
local variance reduction in fixed source problems through the :attr:`targets`
84+
attribute, which is described later in this section. To enable FW-CADIS, an
85+
:class:`openmc.WeightWindowGenerator` object is added to the
86+
:attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be generated
87+
at the end of the simulation. The only procedural difference is that the code
88+
must be run in random ray mode. A full description of how to enable and setup
8389
random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
8490

8591
.. note::
@@ -90,7 +96,7 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
9096
ray solver. A high level overview of the current workflow for generation of
9197
weight windows with FW-CADIS using random ray is given below.
9298

93-
1. Begin by making a deepy copy of your continuous energy Python model and then
99+
1. Begin by making a deep copy of your continuous energy Python model and then
94100
convert the copy to be multigroup and use the random ray transport solver.
95101
The conversion process can largely be automated as described in more detail
96102
in the :ref:`random ray quick start guide <quick_start>`, summarized below::
@@ -148,7 +154,53 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
148154
assigning to ``model.settings.random_ray['source_region_meshes']``) and for
149155
weight window generation.
150156

151-
3. When running your multigroup random ray input deck, OpenMC will automatically
157+
3. (Optional) If local variance reduction is desired in a fixed-source problem,
158+
populate the :attr:`targets` attribute with an :class:`openmc.Tallies`
159+
instance or an iterable of tally IDs indicating the tallies of interest for
160+
variance reduction::
161+
162+
# Build a new example and WWG for local variance reduction
163+
from openmc.examples import random_ray_three_region_cube_with_detectors
164+
new_model = random_ray_three_region_cube_with_detectors()
165+
166+
ww_mesh = openmc.RegularMesh()
167+
n = 7
168+
width = 35.0
169+
ww_mesh.dimension = (n, n, n)
170+
ww_mesh.lower_left = (0.0, 0.0, 0.0)
171+
ww_mesh.upper_right = (width, width, width)
172+
173+
wwg = openmc.WeightWindowGenerator(
174+
method="fw_cadis",
175+
mesh=ww_mesh,
176+
max_realizations=new_model.settings.batches
177+
)
178+
new_model.settings.weight_window_generators = wwg
179+
new_model.settings.random_ray['volume_estimator'] = 'naive'
180+
181+
# Get the tallies of interest
182+
target_tallies = openmc.Tallies()
183+
184+
for tally in list(new_model.tallies):
185+
if tally.name in {"Detector 1 Tally", "Detector 2 Tally"}:
186+
target_tallies.append(tally)
187+
188+
# Add to WeightWindowGenerator
189+
wwg.targets = target_tallies
190+
191+
.. warning::
192+
The tallies designated as FW-CADIS targets to the
193+
:class:`~openmc.WeightWindowGenerator` must be present under the
194+
:class:`~openmc.model.Model.tallies` attribute of the
195+
:class:`~openmc.model.Model` as well in order to be recognized as valid
196+
local variance reduction targets. This check is performed when the
197+
:func:`openmc.model.Model.export_to_model_xml` or
198+
:func:`openmc.model.Model.export_to_xml` functions are called, meaning
199+
that the standalone :func:`openmc.Settings.export_to_xml` and
200+
:func:`openmc.Tallies.export_to_xml` methods should not be used with
201+
FW-CADIS local variance reduction.
202+
203+
4. When running your multigroup random ray input deck, OpenMC will automatically
152204
run a forward solve followed by an adjoint solve, with a
153205
``weight_windows.h5`` file generated at the end. The ``weight_windows.h5``
154206
file will contain FW-CADIS generated weight windows. This file can be used in

include/openmc/random_ray/flat_source_domain.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ class FlatSourceDomain {
4040
void random_ray_tally();
4141
virtual void accumulate_iteration_flux();
4242
void output_to_vtk() const;
43-
void convert_external_sources();
43+
void convert_external_sources(bool use_adjoint_sources);
4444
void count_external_source_regions();
45-
void set_adjoint_sources();
45+
void set_fw_adjoint_sources();
46+
void set_local_adjoint_sources();
4647
void flux_swap();
4748
virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const;
4849
double compute_fixed_source_normalization_factor() const;
@@ -76,6 +77,7 @@ class FlatSourceDomain {
7677
// Static Data members
7778
static bool volume_normalized_flux_tallies_;
7879
static bool adjoint_; // If the user wants outputs based on the adjoint flux
80+
static bool fw_cadis_local_;
7981
static double
8082
diagonal_stabilization_rho_; // Adjusts strength of diagonal stabilization
8183
// for transport corrected MGXS data
@@ -84,6 +86,8 @@ class FlatSourceDomain {
8486
static std::unordered_map<int, vector<std::pair<Source::DomainType, int>>>
8587
mesh_domain_map_;
8688

89+
static std::vector<size_t> fw_cadis_local_targets_;
90+
8791
//----------------------------------------------------------------------------
8892
// Static data members
8993
static RandomRayVolumeEstimator volume_estimator_;

0 commit comments

Comments
 (0)