mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 14:35:27 -04:00
Merge f8e3d36d0b into 61c8a59cff
This commit is contained in:
commit
528b9cde8b
4 changed files with 114 additions and 5 deletions
|
|
@ -652,8 +652,8 @@ model to use these multigroup cross sections. An example is given below::
|
|||
)
|
||||
|
||||
The most important parameter to set is the ``method`` parameter, which can be
|
||||
either "stochastic_slab", "material_wise", or "infinite_medium". An overview
|
||||
of these methods is given below:
|
||||
one of "material_wise", "cell_wise", "stochastic_slab", or
|
||||
"infinite_medium". An overview of these methods is given below:
|
||||
|
||||
.. list-table:: Comparison of Automatic MGXS Generation Methods
|
||||
:header-rows: 1
|
||||
|
|
@ -673,6 +673,21 @@ of these methods is given below:
|
|||
- * Potentially slower as the full geometry must be run
|
||||
* If a material is only present far from the source and doesn't get tallied
|
||||
to in the CE simulation, the MGXS will be zero for that material.
|
||||
* - ``cell_wise``
|
||||
- * Highest Fidelity
|
||||
* Like ``material_wise``, but clones the material in each cell so every
|
||||
cell gets its own cross sections (each material-filled cell is assigned a
|
||||
distinct macroscopic).
|
||||
- * Resolves spatial variation between distinct cells that share a material,
|
||||
which ``material_wise`` averages away (e.g. a shield wall modelled as
|
||||
several cells of one material, each covering a different depth)
|
||||
* Captures spatial self shielding between cells filled with the same material
|
||||
- * Most expensive (one cross section set per cell) and a larger library
|
||||
* Fidelity is limited by the cell definitions, not the source region mesh:
|
||||
a single large cell uses one cross section set throughout, so a steep
|
||||
gradient is only resolved if the geometry is split into several cells
|
||||
* Same far-from-source limitation as ``material_wise``: a cell that is not
|
||||
tallied to yields zero cross sections for that cell
|
||||
* - ``stochastic_slab``
|
||||
- * Medium Fidelity
|
||||
* Runs a CE simulation with a greatly simplified geometry, where materials
|
||||
|
|
@ -691,6 +706,13 @@ of these methods is given below:
|
|||
between materials)
|
||||
* May hang if a material has a k-infinity greater than 1.0
|
||||
|
||||
.. note::
|
||||
The ``cell_wise`` method generates one cross section set per cell definition,
|
||||
not per cell instance. A cell that appears in several locations of a lattice
|
||||
therefore shares a single cross section set across all of those locations. If
|
||||
you need distinct cross sections per instance, subdivide the geometry into
|
||||
separate cells.
|
||||
|
||||
When selecting a non-default energy group structure, you can manually define
|
||||
group boundaries or specify the name of a known group structure (a list of which
|
||||
can be found at :data:`openmc.mgxs.GROUP_STRUCTURES`). The ``nparticles``
|
||||
|
|
|
|||
|
|
@ -2721,8 +2721,12 @@ class Model:
|
|||
|
||||
Parameters
|
||||
----------
|
||||
method : {"material_wise", "stochastic_slab", "infinite_medium"}, optional
|
||||
Method to generate the MGXS.
|
||||
method : {"material_wise", "stochastic_slab", "infinite_medium", \
|
||||
"cell_wise"}, optional
|
||||
Method to generate the MGXS. "cell_wise" is like
|
||||
"material_wise" but gives each cell its own cross sections. The
|
||||
material in each material-filled cell is cloned, so the per-material
|
||||
generation produces one cross section set per cell.
|
||||
groups : openmc.mgxs.EnergyGroups, str, or sequence of float, optional
|
||||
Energy group structure for the MGXS. Can be an
|
||||
:class:`openmc.mgxs.EnergyGroups` object, a string name of a
|
||||
|
|
@ -2790,6 +2794,18 @@ class Model:
|
|||
self.settings.run_mode = original_run_mode
|
||||
break
|
||||
|
||||
# For "cell_wise", give each cell its own cross sections by
|
||||
# cloning the material in every material-filled cell. Each clone gets
|
||||
# a unique id, so the per-material generation below produces (and
|
||||
# assigns) one cross section set per cell.
|
||||
if method == "cell_wise":
|
||||
cell_materials = []
|
||||
for cell in self.geometry.get_all_cells().values():
|
||||
if isinstance(cell.fill, openmc.Material):
|
||||
cell.fill = cell.fill.clone()
|
||||
cell_materials.append(cell.fill)
|
||||
self.materials = openmc.Materials(cell_materials)
|
||||
|
||||
# Temporarily replace each material's name with a unique, valid HDF5
|
||||
# dataset name (its name plus ID) for use as its MGXS library entry
|
||||
# and macroscopic. The ID keeps the name unique even when materials
|
||||
|
|
@ -2806,7 +2822,7 @@ class Model:
|
|||
self._generate_infinite_medium_mgxs(
|
||||
groups, nparticles, mgxs_path, correction, tmpdir, source_energy,
|
||||
temperatures, temperature_settings)
|
||||
elif method == "material_wise":
|
||||
elif method in ("material_wise", "cell_wise"):
|
||||
self._generate_material_wise_mgxs(
|
||||
groups, nparticles, mgxs_path, correction, tmpdir,
|
||||
temperatures, temperature_settings)
|
||||
|
|
|
|||
|
|
@ -51,3 +51,43 @@ def test_convert_to_multigroup_without_particles_batches(run_in_tmpdir):
|
|||
|
||||
# Verify the model was converted successfully
|
||||
assert model.settings.energy_mode == 'multi-group'
|
||||
|
||||
|
||||
def test_convert_to_multigroup_cell_wise(run_in_tmpdir):
|
||||
"""cell_wise gives each DAGMC volume its own cross sections, so two
|
||||
cells filled with the same material end up with distinct macroscopics."""
|
||||
openmc.reset_auto_ids()
|
||||
|
||||
# dagmc.h5m has two fuel volumes (both "no-void fuel"), one water volume, a
|
||||
# graveyard and an implicit complement.
|
||||
u235 = openmc.Material(name="no-void fuel")
|
||||
u235.add_nuclide("U235", 1.0)
|
||||
u235.set_density("g/cm3", 11.0)
|
||||
water = openmc.Material(name="water")
|
||||
water.add_nuclide("H1", 2.0)
|
||||
water.add_nuclide("O16", 1.0)
|
||||
water.set_density("g/cm3", 1.0)
|
||||
water.id = 41
|
||||
|
||||
dagmc_file = Path(__file__).parent / "dagmc.h5m"
|
||||
model = openmc.Model()
|
||||
model.materials = openmc.Materials([u235, water])
|
||||
model.geometry = openmc.Geometry(openmc.DAGMCUniverse(dagmc_file))
|
||||
model.settings = openmc.Settings()
|
||||
model.settings.run_mode = "fixed source"
|
||||
source = openmc.IndependentSource()
|
||||
source.energy = openmc.stats.delta_function(2.0e6)
|
||||
model.settings.source = source
|
||||
|
||||
# Pre-create the library so MGXS generation/transport is skipped; this
|
||||
# exercises the per-cell material cloning for the DAGMC cells only.
|
||||
Path("mgxs.h5").touch()
|
||||
model.convert_to_multigroup(
|
||||
method="cell_wise", groups="CASMO-2", mgxs_path="mgxs.h5")
|
||||
|
||||
# The three material-filled volumes (two fuel, one water) each get their own
|
||||
# cloned material with a distinct macroscopic; the void cells are skipped.
|
||||
assert model.settings.energy_mode == "multi-group"
|
||||
assert len(model.materials) == 3
|
||||
macros = [m._macroscopic for m in model.materials]
|
||||
assert len(set(macros)) == 3
|
||||
|
|
|
|||
|
|
@ -1090,3 +1090,34 @@ def test_convert_to_multigroup_preserves_material_names(run_in_tmpdir):
|
|||
macro = [m._macroscopic for m in model.materials]
|
||||
assert macro == [f"Steel_Plate__1_{a.id}", f"Steel_Plate__1_{b.id}"]
|
||||
assert len(set(macro)) == 2
|
||||
|
||||
|
||||
def test_convert_to_multigroup_cell_wise(run_in_tmpdir):
|
||||
"""cell_wise clones the material in each cell so two cells sharing one
|
||||
material end up with distinct (spatially-resolved) cross sections rather than a
|
||||
single shared set."""
|
||||
water = openmc.Material(name="water")
|
||||
water.add_element("H", 2.0)
|
||||
water.add_element("O", 1.0)
|
||||
water.set_density("g/cm3", 1.0)
|
||||
|
||||
s1 = openmc.Sphere(r=1.0)
|
||||
s2 = openmc.Sphere(r=2.0, boundary_type="vacuum")
|
||||
c1 = openmc.Cell(fill=water, region=-s1)
|
||||
c2 = openmc.Cell(fill=water, region=+s1 & -s2) # same material, distinct cell
|
||||
model = openmc.Model(openmc.Geometry([c1, c2]), openmc.Materials([water]))
|
||||
|
||||
# Pre-create the library so MGXS generation (and transport) is skipped; this
|
||||
# exercises the per-cell material cloning and macroscopic assignment only.
|
||||
Path("mgxs.h5").touch()
|
||||
model.convert_to_multigroup(method="cell_wise", mgxs_path="mgxs.h5")
|
||||
|
||||
# Each cell now holds its own cloned material reading a distinct macroscopic.
|
||||
assert len(model.materials) == 2
|
||||
assert c1.fill is not c2.fill
|
||||
assert c1.fill._macroscopic == f"water_{c1.fill.id}"
|
||||
assert c2.fill._macroscopic == f"water_{c2.fill.id}"
|
||||
assert c1.fill._macroscopic != c2.fill._macroscopic
|
||||
# The user's original material object is left untouched.
|
||||
assert water.name == "water"
|
||||
assert model.settings.energy_mode == "multi-group"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue