Skip to content

Commit b67771a

Browse files
jtrammpaulromano
andauthored
Random Ray AutoMagic Setup (#3351)
Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
1 parent 24655df commit b67771a

File tree

26 files changed

+1243
-92
lines changed

26 files changed

+1243
-92
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ jobs:
8181
RDMAV_FORK_SAFE: 1
8282

8383
steps:
84+
- name: Setup cmake
85+
uses: jwlawson/actions-setup-cmake@v2
86+
with:
87+
cmake-version: '3.31'
88+
8489
- name: Checkout repository
8590
uses: actions/checkout@v4
8691
with:

docs/source/io_formats/settings.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,14 @@ found in the :ref:`random ray user guide <random_ray>`.
487487

488488
:type:
489489
The type of the domain. Can be ``material``, ``cell``, or ``universe``.
490+
491+
:diagonal_stabilization_rho:
492+
The rho factor for use with diagonal stabilization. This technique is
493+
applied when negative diagonal (in-group) elements are detected in
494+
the scattering matrix of input MGXS data, which is a common feature
495+
of transport corrected MGXS data.
496+
497+
*Default*: 1.0
490498

491499
----------------------------------
492500
``<resonance_scattering>`` Element

docs/source/pythonapi/deplete.rst

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,18 @@ A minimal example for performing depletion would be:
7878
>>> import openmc.deplete
7979
>>> geometry = openmc.Geometry.from_xml()
8080
>>> settings = openmc.Settings.from_xml()
81-
>>> model = openmc.model.Model(geometry, settings)
81+
>>> model = openmc.Model(geometry, settings)
8282
8383
# Representation of a depletion chain
8484
>>> chain_file = "chain_casl.xml"
85-
>>> operator = openmc.deplete.CoupledOperator(
86-
... model, chain_file)
85+
>>> operator = openmc.deplete.CoupledOperator(model, chain_file)
8786
8887
# Set up 5 time steps of one day each
8988
>>> dt = [24 * 60 * 60] * 5
9089
>>> power = 1e6 # constant power of 1 MW
9190
9291
# Deplete using mid-point predictor-corrector
93-
>>> cecm = openmc.deplete.CECMIntegrator(
94-
... operator, dt, power)
92+
>>> cecm = openmc.deplete.CECMIntegrator(operator, dt, power)
9593
>>> cecm.integrate()
9694
9795
Internal Classes and Functions

docs/source/usersguide/random_ray.rst

Lines changed: 184 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,76 @@ active batches <usersguide_batches>`. However, there are a couple of settings
1111
that are unique to the random ray solver and a few areas that the random ray
1212
run strategy differs, both of which will be described in this section.
1313

14+
.. _quick_start:
15+
16+
-----------
17+
Quick Start
18+
-----------
19+
20+
While this page contains a comprehensive guide to the random ray solver and
21+
its various parameters, the process of converting an existing continuous energy
22+
Monte Carlo model to a random ray model can be largely automated via convenience
23+
functions in OpenMC's Python interface::
24+
25+
# Define continuous energy model as normal
26+
model = openmc.Model()
27+
...
28+
29+
# Convert model to multigroup (will auto-generate MGXS library if needed)
30+
model.convert_to_multigroup()
31+
32+
# Convert model to random ray and initialize random ray parameters
33+
# to reasonable defaults based on the specifics of the geometry
34+
model.convert_to_random_ray()
35+
36+
# (Optional) Overlay source region decomposition mesh to improve fidelity of the
37+
# random ray solver. Adjust 'n' for fidelity vs runtime.
38+
n = 100
39+
mesh = openmc.RegularMesh()
40+
mesh.dimension = (n, n, n)
41+
mesh.lower_left = model.geometry.bounding_box.lower_left
42+
mesh.upper_right = model.geometry.bounding_box.upper_right
43+
model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])]
44+
45+
# (Optional) Improve fidelity of the random ray solver by enabling linear sources
46+
model.settings.random_ray['source_shape'] = 'linear'
47+
48+
# (Optional) Increase the number of rays/batch, to reduce uncertainty
49+
model.settings.particles = 500
50+
51+
The above strategy first converts the continuous energy model to a multigroup
52+
one using the :meth:`openmc.Model.convert_to_multigroup` method. By default,
53+
this will internally run a coarsely converged continuous energy Monte Carlo
54+
simulation to produce an estimated multigroup macroscopic cross section set for
55+
each material specified in the model, and store this data into a multigroup
56+
cross section library file (``mgxs.h5``) that can be used by the random ray
57+
solver.
58+
59+
The :meth:`openmc.Model.convert_to_random_ray` method enables random ray mode
60+
and performs an analysis of the model geometry to determine reasonable values
61+
for all required parameters. If default behavior is not satisfactory, the user
62+
can manually adjust the settings in the :attr:`~openmc.Settings.random_ray`
63+
dictionary in the :class:`openmc.Settings` as described in the sections below.
64+
65+
Finally a few optional steps are shown. The first (recommended) step overlays a
66+
mesh over the geometry to create smaller source regions so that source
67+
resolution improves and the random ray solver becomes more accurate. Varying the
68+
mesh resolution can be used to trade off between accuracy and runtime.
69+
High-fidelity fission reactor simulation may require source region sizes below 1
70+
cm, while larger fixed source problems with some tolerance for error may be able
71+
to use source regions of 10 or 100 cm.
72+
73+
We also enable linear sources, which can improve the accuracy of the random ray
74+
solver and/or allow for a much coarser mesh resolution to be overlaid. Finally,
75+
the number of rays per batch is adjusted. The goal here is to ensure that the
76+
source region miss rate is below 1%, which is reported by OpenMC at the end of
77+
the simulation (or before via a warning if it is very high).
78+
79+
.. warning::
80+
If using a mesh filter for tallying or weight window generation, ensure that
81+
the same mesh is used for source region decomposition via
82+
``model.settings.random_ray['source_region_meshes']``.
83+
1484
------------------------
1585
Enabling Random Ray Mode
1686
------------------------
@@ -557,37 +627,126 @@ variety of problem types (or through a multidimensional parameter sweep of
557627
design variables) with only modest errors and at greatly reduced cost as
558628
compared to using only continuous energy Monte Carlo.
559629

630+
~~~~~~~~~~~~
631+
The Easy Way
632+
~~~~~~~~~~~~
633+
634+
The easiest way to generate a multigroup cross section library is to use the
635+
:meth:`openmc.Model.convert_to_multigroup` method. This method will
636+
automatically output a multigroup cross section library file (``mgxs.h5``) from
637+
a continuous energy Monte Carlo model and alter the material definitions in the
638+
model to use these multigroup cross sections. An example is given below::
639+
640+
# Assume we already have a working continuous energy model
641+
model.convert_to_multigroup(
642+
method="material_wise",
643+
groups="CASMO-2",
644+
nparticles=2000,
645+
overwrite_mgxs_library=False,
646+
mgxs_path="mgxs.h5",
647+
correction=None
648+
)
649+
650+
The most important parameter to set is the ``method`` parameter, which can be
651+
either "stochastic_slab", "material_wise", or "infinite_medium". An overview
652+
of these methods is given below:
653+
654+
.. list-table:: Comparison of Automatic MGXS Generation Methods
655+
:header-rows: 1
656+
:widths: 10 30 30 30
657+
658+
* - Method
659+
- Description
660+
- Pros
661+
- Cons
662+
* - ``material_wise`` (default)
663+
- * Higher Fidelity
664+
* Runs a CE simulation with the original geometry and source, tallying
665+
cross sections with a material filter.
666+
- * Typically the most accurate of the three methods
667+
* Accurately captures (averaged over the full problem domain)
668+
both spatial and resonance self shielding effects
669+
- * Potentially slower as the full geometry must be run
670+
* If a material is only present far from the source and doesn't get tallied
671+
to in the CE simulation, the MGXS will be zero for that material.
672+
* - ``stochastic_slab``
673+
- * Medium Fidelity
674+
* Runs a CE simulation with a greatly simplified geometry, where materials
675+
are randomly assigned to layers in a 1D "stochastic slab sandwich" geometry
676+
- * Still captures resonant self shielding and resonance effects between materials
677+
* Fast due to the simplified geometry
678+
* Able to produce cross section data for all materials, regardless of how
679+
far they are from the source in the original geometry
680+
- * Does not capture most spatial self shielding effects, e.g., no lattice physics.
681+
* - ``infinite_medium``
682+
- * Lower Fidelity
683+
* Runs one CE simulation per material independently. Each simulation is just
684+
an infinite medium slowing down problem, with an assumed external source term.
685+
- * Simple
686+
- * Poor accuracy (no spatial information, no lattice physics, no resonance effects
687+
between materials)
688+
* May hang if a material has a k-infinity greater than 1.0
689+
690+
When selecting a non-default energy group structure, you can manually define
691+
group boundaries or specify the name of a known group structure (a list of which
692+
can be found at :data:`openmc.mgxs.GROUP_STRUCTURES`). The ``nparticles``
693+
parameter can be adjusted upward to improve the fidelity of the generated cross
694+
section library. The ``correction`` parameter can be set to ``"P0"`` to enable
695+
P0 transport correction. The ``overwrite_mgxs_library`` parameter can be set to
696+
``True`` to overwrite an existing MGXS library file, or ``False`` to skip
697+
generation and use an existing library file.
698+
699+
.. note::
700+
MGXS transport correction (via setting the ``correction`` parameter in the
701+
:meth:`openmc.Model.convert_to_multigroup` method to ``"P0"``) may
702+
result in negative in-group scattering cross sections, which can cause
703+
numerical instability. To mitigate this, during a random ray solve OpenMC
704+
will automatically apply
705+
`diagonal stabilization <https://doi.org/10.1016/j.anucene.2018.10.036>`_
706+
with a :math:`\rho` default value of 1.0, which can be adjusted with the
707+
``settings.random_ray['diagonal_stabilization_rho']`` parameter.
708+
709+
Ultimately, the methods described above are all just approximations.
710+
Approximations in the generated MGXS data will fundamentally limit the potential
711+
accuracy of the random ray solver. However, the methods described above are all
712+
useful in that they can provide a good starting point for a random ray
713+
simulation, and if more fidelity is needed the user may wish to follow the
714+
instructions below or experiment with transport correction techniques to improve
715+
the fidelity of the generated MGXS data.
716+
717+
~~~~~~~~~~~~
718+
The Hard Way
719+
~~~~~~~~~~~~
720+
560721
We give here a quick summary of how to produce a multigroup cross section data
561722
file (``mgxs.h5``) from a starting point of a typical continuous energy Monte
562-
Carlo input file. Notably, continuous energy input files define materials as a
563-
mixture of nuclides with different densities, whereas multigroup materials are
564-
simply defined by which name they correspond to in a ``mgxs.h5`` library file.
723+
Carlo model. Notably, continuous energy models define materials as a mixture of
724+
nuclides with different densities, whereas multigroup materials are simply
725+
defined by which name they correspond to in a ``mgxs.h5`` library file.
565726

566727
To generate the cross section data, we begin with a continuous energy Monte
567-
Carlo input deck and add in the required tallies that will be needed to generate
568-
our library. In this example, we will specify material-wise cross sections and a
569-
two group energy decomposition::
728+
Carlo model and add in the tallies that are needed to generate our library. In
729+
this example, we will specify material-wise cross sections and a two-group
730+
energy decomposition::
570731

571732
# Define geometry
572733
...
573-
...
574734
geometry = openmc.Geometry()
575735
...
576-
...
577736

578737
# Initialize MGXS library with a finished OpenMC geometry object
579738
mgxs_lib = openmc.mgxs.Library(geometry)
580739

581740
# Pick energy group structure
582-
groups = openmc.mgxs.EnergyGroups(openmc.mgxs.GROUP_STRUCTURES['CASMO-2'])
741+
groups = openmc.mgxs.EnergyGroups('CASMO-2')
583742
mgxs_lib.energy_groups = groups
584743

585744
# Disable transport correction
586745
mgxs_lib.correction = None
587746

588747
# Specify needed cross sections for random ray
589748
mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',
590-
'nu-scatter matrix', 'multiplicity matrix', 'chi']
749+
'nu-scatter matrix', 'multiplicity matrix', 'chi']
591750

592751
# Specify a "cell" domain type for the cross section tally filters
593752
mgxs_lib.domain_type = "material"
@@ -614,24 +773,21 @@ two group energy decomposition::
614773
...
615774

616775
When selecting an energy decomposition, you can manually define group boundaries
617-
or pick out a group structure already known to OpenMC (a list of which can be
618-
found at :class:`openmc.mgxs.GROUP_STRUCTURES`). Once the above input deck has
619-
been run, the resulting statepoint file will contain the needed flux and
620-
reaction rate tally data so that a MGXS library file can be generated. Below is
621-
the postprocessing script needed to generate the ``mgxs.h5`` library file given
622-
a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g.,
623-
``summary.h5``) that resulted from running our previous example::
776+
or specify the name of known group structure (a list of which can be found at
777+
:data:`openmc.mgxs.GROUP_STRUCTURES`). Once the above model has been run, the
778+
resulting statepoint file will contain the needed flux and reaction rate tally
779+
data so that a MGXS library file can be generated. Below is the postprocessing
780+
script needed to generate the ``mgxs.h5`` library file given a statepoint file
781+
(e.g., ``statepoint.100.h5``) file and summary file (e.g., ``summary.h5``) that
782+
resulted from running our previous example::
624783

625784
import openmc
626785

627786
summary = openmc.Summary('summary.h5')
628787
geom = summary.geometry
629788
mats = summary.materials
630789

631-
statepoint_filename = 'statepoint.100.h5'
632-
sp = openmc.StatePoint(statepoint_filename)
633-
634-
groups = openmc.mgxs.EnergyGroups(openmc.mgxs.GROUP_STRUCTURES['CASMO-2'])
790+
groups = openmc.mgxs.EnergyGroups('CASMO-2')
635791
mgxs_lib = openmc.mgxs.Library(geom)
636792
mgxs_lib.energy_groups = groups
637793
mgxs_lib.correction = None
@@ -653,10 +809,10 @@ a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g.,
653809
# Construct all tallies needed for the multi-group cross section library
654810
mgxs_lib.build_library()
655811

656-
mgxs_lib.load_from_statepoint(sp)
812+
with openmc.StatePoint('statepoint.100.h5') as sp:
813+
mgxs_lib.load_from_statepoint(sp)
657814

658-
names = []
659-
for mat in mgxs_lib.domains: names.append(mat.name)
815+
names = [mat.name for mat in mgxs_lib.domains]
660816

661817
# Create a MGXS File which can then be written to disk
662818
mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names)
@@ -665,8 +821,8 @@ a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g.,
665821
mgxs_file.export_to_hdf5("mgxs.h5")
666822

667823
Notably, the postprocessing script needs to match the same
668-
:class:`openmc.mgxs.Library` settings that were used to generate the tallies,
669-
but otherwise is able to discern the rest of the simulation details from the
824+
:class:`openmc.mgxs.Library` settings that were used to generate the tallies but
825+
is otherwise able to discern the rest of the simulation details from the
670826
statepoint and summary files. Once the postprocessing script is successfully
671827
run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC.
672828

@@ -701,11 +857,11 @@ multigroup library instead of defining their isotopic contents, as::
701857
water_data = openmc.Macroscopic('Hot borated water')
702858

703859
# Instantiate some Materials and register the appropriate Macroscopic objects
704-
fuel= openmc.Material(name='UO2 (2.4%)')
860+
fuel = openmc.Material(name='UO2 (2.4%)')
705861
fuel.set_density('macro', 1.0)
706862
fuel.add_macroscopic(fuel_data)
707863

708-
water= openmc.Material(name='Hot borated water')
864+
water = openmc.Material(name='Hot borated water')
709865
water.set_density('macro', 1.0)
710866
water.add_macroscopic(water_data)
711867

0 commit comments

Comments
 (0)