mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Improved automatic MGXS generation for random ray (#3658)
Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
parent
10706510bf
commit
ad5a876bee
14 changed files with 511 additions and 31 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
7.797252E-01 1.055731E-02
|
||||
7.479770E-01 1.624548E-02
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
7.496641E-01 8.282032E-03
|
||||
6.413334E-01 2.083132E-02
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
7.657815E-01 2.317564E-02
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
7.827784E-01 2.062954E-02
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
7.479571E-01 2.398563E-02
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
7.620306E-01 2.175179E-02
|
||||
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue