From 139824e21c07ef206536badb758001cc6f52aa03 Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 14:20:43 +0200 Subject: [PATCH 1/7] now squashing like nuclides --- openmc/material.py | 18 ++++++++++++++++- tests/unit_tests/test_material.py | 32 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/openmc/material.py b/openmc/material.py index c7b954b6666..e78afcd4aad 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -559,7 +559,23 @@ def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): if Z >= 89: self.depletable = True - self._nuclides.append(NuclideTuple(nuclide, percent, percent_type)) + # Flag to mark if we squashed the nuclide with an existing one + squashed = False + + for i, nt in enumerate(self._nuclides): + if nt.name == nuclide and nt.percent_type == percent_type: + # merge + self._nuclides[i] = NuclideTuple(nuclide, nt.percent + percent, percent_type) + squashed = True + break + elif nt.name == nuclide and nt.percent_type != percent_type: + warnings.warn( + f"Nuclide '{nuclide}' already present with percent_type '{nt.percent_type}'. " + f"Keeping separate entry for percent_type '{percent_type}'." + ) + + if not squashed: + self._nuclides.append(NuclideTuple(nuclide, percent, percent_type)) def add_components(self, components: dict, percent_type: str = 'ao'): """ Add multiple elements or nuclides to a material diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index eae814a755b..144feb50693 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -2,6 +2,7 @@ from pathlib import Path import pytest +import warnings import numpy as np @@ -766,3 +767,34 @@ def test_mean_free_path(): mat2.add_nuclide('Pb208', 1.0) mat2.set_density('g/cm3', 11.34) assert mat2.mean_free_path(energy=14e6) == pytest.approx(5.65, abs=1e-2) + + +def test_add_nuclide_squash_same_type(): + mat1 = openmc.Material() + mat1.add_nuclide('Li6', 0.02, 'ao') + mat1.add_nuclide('Li6', 0.03, 'ao') + # Should be a single entry with 0.05 ao + entries = [nt for nt in mat1.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] + assert len(entries) == 1 + assert entries[0].percent == pytest.approx(0.05) + + mat2 = openmc.Material() + mat2.add_nuclide('Li6', 0.04, 'wo') + mat2.add_nuclide('Li6', 0.05, 'wo') + # Should be a single entry with 0.09 wo + entries = [nt for nt in mat2.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] + assert len(entries) == 1 + assert entries[0].percent == pytest.approx(0.09) + + +def test_add_nuclide_keep_different_type_warns(): + mat = openmc.Material() + mat.add_nuclide('Li6', 0.02, 'ao') + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + mat.add_nuclide('Li6', 0.01, 'wo') + assert any("Keeping separate entry" in str(rec.message) for rec in w) + # Should have two entries: one ao and one wo + aos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] + wos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] + assert len(aos) == 1 and len(wos) == 1 From b65c0f6ab4c712fb404f064e8de438463ee21acc Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 14:22:36 +0200 Subject: [PATCH 2/7] updated doc string with squashing nuc info --- openmc/material.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openmc/material.py b/openmc/material.py index e78afcd4aad..7aee459159a 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -524,7 +524,10 @@ def set_density(self, units: str, density: float | None = None): self._density = density def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): - """Add a nuclide to the material + """Add a nuclide to the material. + + If nuclide with the same percent_type already exists in the material, + its percentage will be updated. Parameters ---------- From f0e7a736710fffcb416eecad853380b009dbee3b Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 14:27:36 +0200 Subject: [PATCH 3/7] refined squashing nuc doc string --- openmc/material.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 7aee459159a..187a92520b4 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -526,8 +526,8 @@ def set_density(self, units: str, density: float | None = None): def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): """Add a nuclide to the material. - If nuclide with the same percent_type already exists in the material, - its percentage will be updated. + If nuclide with the same name and percent_type already exists in the + material, its percentage will be updated. Parameters ---------- From 1981d92939667385afa485c06d647d8e2f9a37bd Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 14:28:28 +0200 Subject: [PATCH 4/7] refined code comment for squashing nucs --- openmc/material.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/material.py b/openmc/material.py index 187a92520b4..84e8134f4c1 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -567,7 +567,7 @@ def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): for i, nt in enumerate(self._nuclides): if nt.name == nuclide and nt.percent_type == percent_type: - # merge + # add the percentage the two matching nuclides self._nuclides[i] = NuclideTuple(nuclide, nt.percent + percent, percent_type) squashed = True break From cd7b93a12d81360579c919ab6a92323e85dc02c8 Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 14:30:04 +0200 Subject: [PATCH 5/7] refined code comment for squashing nucs --- openmc/material.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 84e8134f4c1..5922c044717 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -573,8 +573,9 @@ def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): break elif nt.name == nuclide and nt.percent_type != percent_type: warnings.warn( - f"Nuclide '{nuclide}' already present with percent_type '{nt.percent_type}'. " - f"Keeping separate entry for percent_type '{percent_type}'." + f"Nuclide '{nuclide}' already present with percent_type " + f"'{nt.percent_type}'. Keeping separate entry for " + f"new percent_type '{percent_type}'." ) if not squashed: From 155e92107d4179d59f8a0d39d2a077633c6e5bc3 Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 16:13:01 +0200 Subject: [PATCH 6/7] updated remove nuc test for squashing --- tests/unit_tests/test_material.py | 41 ++++++------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index 144feb50693..1004570b900 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -2,7 +2,6 @@ from pathlib import Path import pytest -import warnings import numpy as np @@ -94,8 +93,13 @@ def test_nuclides_to_ignore(run_in_tmpdir): def test_remove_nuclide(): """Test removing nuclides.""" m = openmc.Material() - for nuc, percent in [('H1', 1.0), ('H2', 1.0), ('H1', 2.0), ('H2', 2.0)]: - m.add_nuclide(nuc, percent) + for nuc, percent, percent_type in [ + ('H1', 1.0, 'ao'), + ('H2', 1.0, 'ao'), + ('H1', 2.0, 'wo'), + ('H2', 2.0, 'wo') + ]: + m.add_nuclide(nuc, percent=percent, percent_type=percent_type) m.remove_nuclide('H1') assert len(m.nuclides) == 2 assert all(nuc.name == 'H2' for nuc in m.nuclides) @@ -767,34 +771,3 @@ def test_mean_free_path(): mat2.add_nuclide('Pb208', 1.0) mat2.set_density('g/cm3', 11.34) assert mat2.mean_free_path(energy=14e6) == pytest.approx(5.65, abs=1e-2) - - -def test_add_nuclide_squash_same_type(): - mat1 = openmc.Material() - mat1.add_nuclide('Li6', 0.02, 'ao') - mat1.add_nuclide('Li6', 0.03, 'ao') - # Should be a single entry with 0.05 ao - entries = [nt for nt in mat1.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] - assert len(entries) == 1 - assert entries[0].percent == pytest.approx(0.05) - - mat2 = openmc.Material() - mat2.add_nuclide('Li6', 0.04, 'wo') - mat2.add_nuclide('Li6', 0.05, 'wo') - # Should be a single entry with 0.09 wo - entries = [nt for nt in mat2.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] - assert len(entries) == 1 - assert entries[0].percent == pytest.approx(0.09) - - -def test_add_nuclide_keep_different_type_warns(): - mat = openmc.Material() - mat.add_nuclide('Li6', 0.02, 'ao') - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - mat.add_nuclide('Li6', 0.01, 'wo') - assert any("Keeping separate entry" in str(rec.message) for rec in w) - # Should have two entries: one ao and one wo - aos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] - wos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] - assert len(aos) == 1 and len(wos) == 1 From 51e8d2b6da4491d6e370d5ebfacec54723b9cf7c Mon Sep 17 00:00:00 2001 From: shimwell Date: Thu, 11 Sep 2025 16:15:23 +0200 Subject: [PATCH 7/7] updated remove nuc test for squashing --- tests/unit_tests/test_material.py | 32 ++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index 1004570b900..3de0f88d49f 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -106,7 +106,6 @@ def test_remove_nuclide(): assert m.nuclides[0].percent == 1.0 assert m.nuclides[1].percent == 2.0 - def test_remove_elements(): """Test removing elements.""" m = openmc.Material() @@ -771,3 +770,34 @@ def test_mean_free_path(): mat2.add_nuclide('Pb208', 1.0) mat2.set_density('g/cm3', 11.34) assert mat2.mean_free_path(energy=14e6) == pytest.approx(5.65, abs=1e-2) + + +def test_add_nuclide_squash_same_type(): + mat1 = openmc.Material() + mat1.add_nuclide('Li6', 0.02, 'ao') + mat1.add_nuclide('Li6', 0.03, 'ao') + # Should be a single entry with 0.05 ao + entries = [nt for nt in mat1.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] + assert len(entries) == 1 + assert entries[0].percent == pytest.approx(0.05) + + mat2 = openmc.Material() + mat2.add_nuclide('Li6', 0.04, 'wo') + mat2.add_nuclide('Li6', 0.05, 'wo') + # Should be a single entry with 0.09 wo + entries = [nt for nt in mat2.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] + assert len(entries) == 1 + assert entries[0].percent == pytest.approx(0.09) + + +def test_add_nuclide_keep_different_type_warns(): + mat = openmc.Material() + mat.add_nuclide('Li6', 0.02, 'ao') + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + mat.add_nuclide('Li6', 0.01, 'wo') + assert any("Keeping separate entry" in str(rec.message) for rec in w) + # Should have two entries: one ao and one wo + aos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'ao'] + wos = [nt for nt in mat.nuclides if nt.name == 'Li6' and nt.percent_type == 'wo'] + assert len(aos) == 1 and len(wos) == 1 \ No newline at end of file