Improved automatic MGXS generation for random ray (#3658)

Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
John Tramm 2025-12-03 01:48:38 -06:00 committed by GitHub
parent 10706510bf
commit ad5a876bee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 511 additions and 31 deletions

View file

@ -644,7 +644,8 @@ model to use these multigroup cross sections. An example is given below::
nparticles=2000,
overwrite_mgxs_library=False,
mgxs_path="mgxs.h5",
correction=None
correction=None,
source_energy=None
)
The most important parameter to set is the ``method`` parameter, which can be
@ -706,6 +707,31 @@ generation and use an existing library file.
with a :math:`\rho` default value of 1.0, which can be adjusted with the
``settings.random_ray['diagonal_stabilization_rho']`` parameter.
When generating MGXS data with either the ``stochastic_slab`` or
``infinite_medium`` methods, by default the simulation will use a uniform source
distribution spread evenly over all energy groups. This ensures that all energy
groups receive tallies and therefore produce non-zero total multigroup cross
sections. Additionally, the function will convert any sources in the model into
simplified spatial sources that retain the original energy distributions. If
sources are present, they will be used 99% of the time to sample source energies
during MGXS generation. The other 1% of the time, energies will be sampled
uniformly over all energy groups to ensure that all groups receive some tallies.
However, the user may wish to specify a different source energy spectrum (for
instance, if they are using a FileSource, such that the energy distribution
cannot be extracted from the python source object). This can be done by
providing a :class:`openmc.stats.Univariate` distribution as the
``source_energy`` parameter of the :meth:`openmc.Model.convert_to_multigroup`
method. If provided, it will override any sources present in the model and will
be used 99% of the time to sample source energies during MGXS generation. The
other 1% of the time, energies will be sampled uniformly over all energy groups
to ensure that all groups receive some tallies.
For instance, a D-D fusion simulation may involve a complex file source. In this
case, the user may wish to provide a discrete 2.45 MeV energy source
distribution for MGXS generation as::
source_energy = openmc.stats.delta_function(2.45e6)
Ultimately, the methods described above are all just approximations.
Approximations in the generated MGXS data will fundamentally limit the potential
accuracy of the random ray solver. However, the methods described above are all

View file

@ -1687,6 +1687,91 @@ class Model:
self.geometry.get_all_materials().values()
)
def _create_mgxs_sources(
self,
groups: openmc.mgxs.EnergyGroups,
spatial_dist: openmc.stats.Spatial,
source_energy: openmc.stats.Univariate | None = None,
) -> list[openmc.IndependentSource]:
"""Create a list of independent sources to use with MGXS generation.
Note that in all cases, a discrete source that is uniform over all
energy groups is created (strength = 0.01) to ensure that total cross
sections are generated for all energy groups. In the case that the user
has provided a source_energy distribution as an argument, an additional
source (strength = 0.99) is created using that energy distribution. If
the user has not provided a source_energy distribution, but the model
has sources defined, and all of those sources are of IndependentSource
type, then additional sources are created based on the model's existing
sources, keeping their energy distributions but replacing their
spatial/angular distributions, with their combined strength being 0.99.
If the user has not provided a source_energy distribution and no sources
are defined on the model and the run mode is 'eigenvalue', then a
default Watt spectrum source (strength = 0.99) is added.
Parameters
----------
groups : openmc.mgxs.EnergyGroups
Energy group structure for the MGXS.
spatial_dist : openmc.stats.Spatial
Spatial distribution to use for all sources.
source_energy : openmc.stats.Univariate, optional
Energy distribution to use when generating MGXS data, replacing any
existing sources in the model.
Returns
-------
list[openmc.IndependentSource]
A list of independent sources to use for MGXS generation.
"""
# Make a discrete source that is uniform over the bins of the group structure
midpoints = []
strengths = []
for i in range(groups.num_groups):
bounds = groups.get_group_bounds(i+1)
midpoints.append((bounds[0] + bounds[1]) / 2.0)
strengths.append(1.0)
uniform_energy = openmc.stats.Discrete(x=midpoints, p=strengths)
uniform_distribution = openmc.IndependentSource(spatial_dist, energy=uniform_energy, strength=0.01)
sources = [uniform_distribution]
# If the user provided an energy distribution, use that
if source_energy is not None:
user_energy = openmc.IndependentSource(
space=spatial_dist, energy=source_energy, strength=0.99)
sources.append(user_energy)
# If the user did not provide an energy distribution, create sources
# based on what is in their model, keeping the energy spectrum but
# replacing the spatial/angular distributions. We only do this if ALL
# sources are of IndependentSource type, as we can't pull the energy
# distribution from e.g. CompiledSource or FileSource types.
else:
if self.settings.source is not None:
for src in self.settings.source:
if not isinstance(src, openmc.IndependentSource):
break
else:
n_user_sources = len(self.settings.source)
for src in self.settings.source:
# Create a new IndependentSource with adjusted strength, space, and angle
user_source = openmc.IndependentSource(
space=spatial_dist,
energy=src.energy,
strength=0.99 / n_user_sources
)
sources.append(user_source)
else:
# No user sources defined. If we are in eigenvalue mode, then use the default Watt spectrum.
if self.settings.run_mode == 'eigenvalue':
watt_energy = openmc.stats.Watt()
watt_source = openmc.IndependentSource(
space=spatial_dist, energy=watt_energy, strength=0.99)
sources.append(watt_source)
return sources
def _generate_infinite_medium_mgxs(
self,
groups: openmc.mgxs.EnergyGroups,
@ -1694,6 +1779,7 @@ class Model:
mgxs_path: PathLike,
correction: str | None,
directory: PathLike,
source_energy: openmc.stats.Univariate | None = None,
):
"""Generate a MGXS library by running multiple OpenMC simulations, each
representing an infinite medium simulation of a single isolated
@ -1702,6 +1788,20 @@ class Model:
method that ignores all spatial self shielding effects and all resonance
shielding effects between materials.
Note that in all cases, a discrete source that is uniform over all
energy groups is created (strength = 0.01) to ensure that total cross
sections are generated for all energy groups. In the case that the user
has provided a source_energy distribution as an argument, an additional
source (strength = 0.99) is created using that energy distribution. If
the user has not provided a source_energy distribution, but the model
has sources defined, and all of those sources are of IndependentSource
type, then additional sources are created based on the model's existing
sources, keeping their energy distributions but replacing their
spatial/angular distributions, with their combined strength being 0.99.
If the user has not provided a source_energy distribution and no sources
are defined on the model and the run mode is 'eigenvalue', then a
default Watt spectrum source (strength = 0.99) is added.
Parameters
----------
groups : openmc.mgxs.EnergyGroups
@ -1715,9 +1815,10 @@ class Model:
"P0".
directory : str
Directory to run the simulation in, so as to contain XML files.
source_energy : openmc.stats.Univariate, optional
Energy distribution to use when generating MGXS data, replacing any
existing sources in the model.
"""
warnings.warn("The infinite medium method of generating MGXS may hang "
"if a material has a k-infinity > 1.0.")
mgxs_sets = []
for material in self.materials:
model = openmc.Model()
@ -1728,20 +1829,16 @@ class Model:
# Settings
model.settings.batches = 100
model.settings.particles = nparticles
model.settings.source = self._create_mgxs_sources(
groups,
spatial_dist=openmc.stats.Point(),
source_energy=source_energy
)
model.settings.run_mode = 'fixed source'
model.settings.create_fission_neutrons = False
# Make a discrete source that is uniform over the bins of the group structure
n_groups = groups.num_groups
midpoints = []
strengths = []
for i in range(n_groups):
bounds = groups.get_group_bounds(i+1)
midpoints.append((bounds[0] + bounds[1]) / 2.0)
strengths.append(1.0)
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
model.settings.source = openmc.IndependentSource(
space=openmc.stats.Point(), energy=energy_distribution)
model.settings.output = {'summary': True, 'tallies': False}
# Geometry
@ -1891,6 +1988,7 @@ class Model:
mgxs_path: PathLike,
correction: str | None,
directory: PathLike,
source_energy: openmc.stats.Univariate | None = None,
) -> None:
"""Generate MGXS assuming a stochastic "sandwich" of materials in a layered
slab geometry. While geometry-specific spatial shielding effects are not
@ -1915,6 +2013,23 @@ class Model:
"P0".
directory : str
Directory to run the simulation in, so as to contain XML files.
source_energy : openmc.stats.Univariate, optional
Energy distribution to use when generating MGXS data, replacing any
existing sources in the model. In all cases, a discrete source that
is uniform over all energy groups is created (strength = 0.01) to
ensure that total cross sections are generated for all energy
groups. In the case that the user has provided a source_energy
distribution as an argument, an additional source (strength = 0.99)
is created using that energy distribution. If the user has not
provided a source_energy distribution, but the model has sources
defined, and all of those sources are of IndependentSource type,
then additional sources are created based on the model's existing
sources, keeping their energy distributions but replacing their
spatial/angular distributions, with their combined strength being
0.99. If the user has not provided a source_energy distribution and
no sources are defined on the model and the run mode is
'eigenvalue', then a default Watt spectrum source (strength = 0.99)
is added.
"""
model = openmc.Model()
model.materials = self.materials
@ -1924,24 +2039,20 @@ class Model:
model.settings.inactive = 100
model.settings.particles = nparticles
model.settings.output = {'summary': True, 'tallies': False}
model.settings.run_mode = self.settings.run_mode
# Stochastic slab geometry
model.geometry, spatial_distribution = Model._create_stochastic_slab_geometry(
model.materials)
# Make a discrete source that is uniform over the bins of the group structure
n_groups = groups.num_groups
midpoints = []
strengths = []
for i in range(n_groups):
bounds = groups.get_group_bounds(i+1)
midpoints.append((bounds[0] + bounds[1]) / 2.0)
strengths.append(1.0)
# Define the sources
model.settings.source = self._create_mgxs_sources(
groups,
spatial_dist=spatial_distribution,
source_energy=source_energy
)
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
model.settings.source = [openmc.IndependentSource(
space=spatial_distribution, energy=energy_distribution, strength=1.0)]
model.settings.run_mode = 'fixed source'
model.settings.create_fission_neutrons = False
model.settings.output = {'summary': True, 'tallies': False}
@ -2099,6 +2210,7 @@ class Model:
overwrite_mgxs_library: bool = False,
mgxs_path: PathLike = "mgxs.h5",
correction: str | None = None,
source_energy: openmc.stats.Univariate | None = None,
):
"""Convert all materials from continuous energy to multigroup.
@ -2121,6 +2233,24 @@ class Model:
correction : str, optional
Transport correction to apply to the MGXS. Options are None and
"P0".
source_energy : openmc.stats.Univariate, optional
Energy distribution to use when generating MGXS data, replacing any
existing sources in the model. In all cases, a discrete source that
is uniform over all energy groups is created (strength = 0.01) to
ensure that total cross sections are generated for all energy
groups. In the case that the user has provided a source_energy
distribution as an argument, an additional source (strength = 0.99)
is created using that energy distribution. If the user has not
provided a source_energy distribution, but the model has sources
defined, and all of those sources are of IndependentSource type,
then additional sources are created based on the model's existing
sources, keeping their energy distributions but replacing their
spatial/angular distributions, with their combined strength being
0.99. If the user has not provided a source_energy distribution and
no sources are defined on the model and the run mode is
'eigenvalue', then a default Watt spectrum source (strength = 0.99)
is added. Note that this argument is only used when using the
"stochastic_slab" or "infinite_medium" MGXS generation methods.
"""
if isinstance(groups, str):
groups = openmc.mgxs.EnergyGroups(groups)
@ -2150,13 +2280,13 @@ class Model:
if not Path(mgxs_path).is_file() or overwrite_mgxs_library:
if method == "infinite_medium":
self._generate_infinite_medium_mgxs(
groups, nparticles, mgxs_path, correction, tmpdir)
groups, nparticles, mgxs_path, correction, tmpdir, source_energy)
elif method == "material_wise":
self._generate_material_wise_mgxs(
groups, nparticles, mgxs_path, correction, tmpdir)
elif method == "stochastic_slab":
self._generate_stochastic_slab_mgxs(
groups, nparticles, mgxs_path, correction, tmpdir)
groups, nparticles, mgxs_path, correction, tmpdir, source_energy)
else:
raise ValueError(
f'MGXS generation method "{method}" not recognized')

View file

@ -1,2 +1,2 @@
k-combined:
7.797252E-01 1.055731E-02
7.479770E-01 1.624548E-02

View file

@ -1,2 +1,2 @@
k-combined:
7.496641E-01 8.282032E-03
6.413334E-01 2.083132E-02

View file

@ -0,0 +1,61 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
</material>
<material id="3" name="Hot_borated_water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
</material>
</materials>
<geometry>
<cell id="1" name="Fuel" material="1" region="-1" universe="0"/>
<cell id="2" name="Cladding" material="2" region="1 -2" universe="0"/>
<cell id="3" name="Water" material="3" region="2 3 -4 5 -6" universe="0"/>
<surface id="1" name="Fuel OR" type="z-cylinder" coeffs="0 0 0.39218"/>
<surface id="2" name="Clad OR" type="z-cylinder" coeffs="0 0 0.4572"/>
<surface id="3" name="left" type="x-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="4" name="right" type="x-plane" boundary="reflective" coeffs="0.63"/>
<surface id="5" name="bottom" type="y-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="6" name="top" type="y-plane" boundary="reflective" coeffs="0.63"/>
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>100</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="1.0" particle="neutron">
<energy type="discrete">
<parameters>7000000.0 1.0</parameters>
</energy>
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>
<mesh id="1">
<domain id="0" type="universe"/>
</mesh>
</source_region_meshes>
<source_shape>linear</source_shape>
</random_ray>
<mesh id="1">
<dimension>2 2</dimension>
<lower_left>-0.63 -0.63</lower_left>
<upper_right>0.63 0.63</upper_right>
</mesh>
</settings>
</model>

View file

@ -0,0 +1,2 @@
k-combined:
7.657815E-01 2.317564E-02

View file

@ -0,0 +1,64 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
</material>
<material id="3" name="Hot_borated_water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
</material>
</materials>
<geometry>
<cell id="1" name="Fuel" material="1" region="-1" universe="0"/>
<cell id="2" name="Cladding" material="2" region="1 -2" universe="0"/>
<cell id="3" name="Water" material="3" region="2 3 -4 5 -6" universe="0"/>
<surface id="1" name="Fuel OR" type="z-cylinder" coeffs="0 0 0.39218"/>
<surface id="2" name="Clad OR" type="z-cylinder" coeffs="0 0 0.4572"/>
<surface id="3" name="left" type="x-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="4" name="right" type="x-plane" boundary="reflective" coeffs="0.63"/>
<surface id="5" name="bottom" type="y-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="6" name="top" type="y-plane" boundary="reflective" coeffs="0.63"/>
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>100</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1 0.63 0.63 1</parameters>
</space>
<constraints>
<fissionable>true</fissionable>
</constraints>
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>
<mesh id="1">
<domain id="0" type="universe"/>
</mesh>
</source_region_meshes>
<source_shape>linear</source_shape>
</random_ray>
<mesh id="1">
<dimension>2 2</dimension>
<lower_left>-0.63 -0.63</lower_left>
<upper_right>0.63 0.63</upper_right>
</mesh>
</settings>
</model>

View file

@ -0,0 +1,2 @@
k-combined:
7.827784E-01 2.062954E-02

View file

@ -0,0 +1,61 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
</material>
<material id="3" name="Hot_borated_water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
</material>
</materials>
<geometry>
<cell id="1" name="Fuel" material="1" region="-1" universe="0"/>
<cell id="2" name="Cladding" material="2" region="1 -2" universe="0"/>
<cell id="3" name="Water" material="3" region="2 3 -4 5 -6" universe="0"/>
<surface id="1" name="Fuel OR" type="z-cylinder" coeffs="0 0 0.39218"/>
<surface id="2" name="Clad OR" type="z-cylinder" coeffs="0 0 0.4572"/>
<surface id="3" name="left" type="x-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="4" name="right" type="x-plane" boundary="reflective" coeffs="0.63"/>
<surface id="5" name="bottom" type="y-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="6" name="top" type="y-plane" boundary="reflective" coeffs="0.63"/>
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>100</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="1.0" particle="neutron">
<energy type="discrete">
<parameters>7000000.0 1.0</parameters>
</energy>
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>
<mesh id="1">
<domain id="0" type="universe"/>
</mesh>
</source_region_meshes>
<source_shape>linear</source_shape>
</random_ray>
<mesh id="1">
<dimension>2 2</dimension>
<lower_left>-0.63 -0.63</lower_left>
<upper_right>0.63 0.63</upper_right>
</mesh>
</settings>
</model>

View file

@ -0,0 +1,2 @@
k-combined:
7.479571E-01 2.398563E-02

View file

@ -0,0 +1,64 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
</material>
<material id="3" name="Hot_borated_water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
</material>
</materials>
<geometry>
<cell id="1" name="Fuel" material="1" region="-1" universe="0"/>
<cell id="2" name="Cladding" material="2" region="1 -2" universe="0"/>
<cell id="3" name="Water" material="3" region="2 3 -4 5 -6" universe="0"/>
<surface id="1" name="Fuel OR" type="z-cylinder" coeffs="0 0 0.39218"/>
<surface id="2" name="Clad OR" type="z-cylinder" coeffs="0 0 0.4572"/>
<surface id="3" name="left" type="x-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="4" name="right" type="x-plane" boundary="reflective" coeffs="0.63"/>
<surface id="5" name="bottom" type="y-plane" boundary="reflective" coeffs="-0.63"/>
<surface id="6" name="top" type="y-plane" boundary="reflective" coeffs="0.63"/>
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>100</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1 0.63 0.63 1</parameters>
</space>
<constraints>
<fissionable>true</fissionable>
</constraints>
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>
<mesh id="1">
<domain id="0" type="universe"/>
</mesh>
</source_region_meshes>
<source_shape>linear</source_shape>
</random_ray>
<mesh id="1">
<dimension>2 2</dimension>
<lower_left>-0.63 -0.63</lower_left>
<upper_right>0.63 0.63</upper_right>
</mesh>
</settings>
</model>

View file

@ -0,0 +1,2 @@
k-combined:
7.620306E-01 2.175179E-02

View file

@ -0,0 +1,66 @@
import os
import openmc
from openmc.examples import pwr_pin_cell
from openmc import RegularMesh
from openmc.utility_funcs import change_directory
import pytest
from tests.testing_harness import TolerantPyAPITestHarness
class MGXSTestHarness(TolerantPyAPITestHarness):
def _cleanup(self):
super()._cleanup()
f = 'mgxs.h5'
if os.path.exists(f):
os.remove(f)
@pytest.mark.parametrize("source_type", ["model", "user"])
@pytest.mark.parametrize("method", ["stochastic_slab", "infinite_medium"])
def test_random_ray_auto_convert_source_energy(method, source_type):
dirname = f"{method}/{source_type}"
with change_directory(dirname):
openmc.reset_auto_ids()
# Start with a normal continuous energy model
model = pwr_pin_cell()
# Define the source energy distribution, using different methods
source_energy = None
if source_type == "model":
model.settings.source = openmc.IndependentSource(
energy=openmc.stats.delta_function(7.0e6)
)
elif source_type == "user":
source_energy = openmc.stats.delta_function(1.0e4)
# Convert to a multi-group model
model.convert_to_multigroup(
method=method, groups='CASMO-8', nparticles=100,
overwrite_mgxs_library=False, mgxs_path="mgxs.h5",
source_energy=source_energy
)
# Convert to a random ray model
model.convert_to_random_ray()
# Set the number of particles
model.settings.particles = 100
# Overlay a basic 2x2 mesh
n = 2
mesh = RegularMesh()
mesh.dimension = (n, n)
bbox = model.geometry.bounding_box
mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1])
mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1])
model.settings.random_ray['source_region_meshes'] = [
(mesh, [model.geometry.root_universe])]
# Set the source shape to linear
model.settings.random_ray['source_shape'] = 'linear'
harness = MGXSTestHarness('statepoint.10.h5', model)
harness.main()