Preserve user material names in convert_to_multigroup and avoid overwriting material with same name bug fix (#3984)
Some checks failed
Tests and Coverage / filter-changes (push) Has been cancelled
dockerhub-publish-develop / main (push) Has been cancelled
dockerhub-publish-develop-dagmc-libmesh / main (push) Has been cancelled
dockerhub-publish-develop-dagmc / main (push) Has been cancelled
dockerhub-publish-develop-libmesh / main (push) Has been cancelled
Tests and Coverage / Python 3.13 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Has been cancelled
Tests and Coverage / Python 3.14 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Has been cancelled
Tests and Coverage / Python 3.14t (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=n, mpi=n, dagmc=n, libmesh=n, event=n (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=n, libmesh=n, event=n (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=n, mpi=y, dagmc=n, libmesh=n, event=n (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=n, libmesh=n, event=n (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=y, event= (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=, event=y (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=y, libmesh=, event= (push) Has been cancelled
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=, libmesh=y, event= (push) Has been cancelled
Tests and Coverage / coverage (push) Has been cancelled
Tests and Coverage / Check CI status (push) Has been cancelled

This commit is contained in:
Jonathan Shimwell 2026-06-30 16:38:09 +02:00 committed by GitHub
parent 4d6244d93c
commit d06fdee93a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 111 additions and 75 deletions

View file

@ -2772,12 +2772,15 @@ class Model:
self.settings.run_mode = original_run_mode
break
# Make sure all materials have a name, and that the name is a valid HDF5
# dataset name
# 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
# share a name; the original names are restored at the end.
original_names = [material.name for material in self.materials]
for material in self.materials:
if not material.name or not material.name.strip():
material.name = f"material {material.id}"
material.name = re.sub(r'[^a-zA-Z0-9]', '_', material.name)
base = material.name if material.name and material.name.strip() \
else "material"
material.name = re.sub(r'[^a-zA-Z0-9]', '_', base) + f"_{material.id}"
# If needed, generate the needed MGXS data library file
if not Path(mgxs_path).is_file() or overwrite_mgxs_library:
@ -2809,6 +2812,10 @@ class Model:
self.settings.energy_mode = 'multi-group'
# Restore the user's original material names.
for material, name in zip(self.materials, original_names):
material.name = name
def convert_to_random_ray(self):
"""Convert a multigroup model to use random ray.

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true" temperature="294.0">
<material id="1" name="UO2 (2.4%)" depletable="true" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water" temperature="294.0">
<material id="3" name="Hot borated water" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true" temperature="294.0">
<material id="1" name="UO2 (2.4%)" depletable="true" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water" temperature="294.0">
<material id="3" name="Hot borated water" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true" temperature="294.0">
<material id="1" name="UO2 (2.4%)" depletable="true" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water" temperature="294.0">
<material id="3" name="Hot borated water" temperature="294.0">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -2,17 +2,17 @@
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="UO2__2_4__" depletable="true">
<material id="1" name="UO2 (2.4%)" depletable="true">
<density value="1.0" units="macro"/>
<macroscopic name="UO2__2_4__"/>
<macroscopic name="UO2__2_4___1"/>
</material>
<material id="2" name="Zircaloy">
<density value="1.0" units="macro"/>
<macroscopic name="Zircaloy"/>
<macroscopic name="Zircaloy_2"/>
</material>
<material id="3" name="Hot_borated_water">
<material id="3" name="Hot borated water">
<density value="1.0" units="macro"/>
<macroscopic name="Hot_borated_water"/>
<macroscopic name="Hot_borated_water_3"/>
</material>
</materials>
<geometry>

View file

@ -1038,3 +1038,32 @@ def test_id_map_to_rgb():
)
# Check that overlap region is green
assert np.allclose(rgb_overlap[5:, 5:], [0.0, 1.0, 0.0])
def test_convert_to_multigroup_preserves_material_names(run_in_tmpdir):
"""convert_to_multigroup leaves the user's material names unchanged and keys
the MGXS library by a unique sanitised name + id, so distinct materials that
share a name do not collapse to a single cross section."""
a = openmc.Material(name="Steel Plate #1")
a.add_element("Fe", 1.0)
a.set_density("g/cm3", 7.9)
b = openmc.Material(name="Steel Plate #1") # same name, distinct material
b.add_element("Fe", 1.0)
b.set_density("g/cm3", 7.9)
s1 = openmc.Sphere(r=1.0)
s2 = openmc.Sphere(r=2.0, boundary_type="vacuum")
c1 = openmc.Cell(fill=a, region=-s1)
c2 = openmc.Cell(fill=b, region=+s1 & -s2)
model = openmc.Model(openmc.Geometry([c1, c2]), openmc.Materials([a, b]))
# Pre-create the library so MGXS generation (and transport) is skipped.
Path("mgxs.h5").touch()
model.convert_to_multigroup(method="material_wise", mgxs_path="mgxs.h5")
# User names are preserved, not sanitised or de-duplicated.
assert [m.name for m in model.materials] == ["Steel Plate #1", "Steel Plate #1"]
# Each material reads a unique, sanitised library entry (name + id).
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