diff --git a/openmc/material.py b/openmc/material.py index a837b1f17d..6c26416801 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -34,7 +34,9 @@ class Material(IDManagerMixin): To create a material, one should create an instance of this class, add nuclides or elements with :meth:`Material.add_nuclide` or :meth:`Material.add_element`, respectively, and set the total material - density with :meth:`Material.set_density()`. The material can then be + density with :meth:`Material.set_density()`. Alternatively, you can + use :meth:`Material.add_components()` to pass a dictionary + containing all the component information. The material can then be assigned to a cell using the :attr:`Cell.fill` attribute. Parameters @@ -403,6 +405,54 @@ class Material(IDManagerMixin): 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 + + .. versionadded:: 0.13.1 + + Parameters + ---------- + components : dict of str to float or dict + Dictionary mapping element or nuclide names to their atom or weight + percent. To specify enrichment of an element, the entry of + ``components`` for that element must instead be a dictionary + containing the keyword arguments as well as a value for + ``'percent'`` + percent_type : {'ao', 'wo'} + 'ao' for atom percent and 'wo' for weight percent + + Examples + -------- + >>> mat = openmc.Material() + >>> components = {'Li': {'percent': 1.0, + >>> 'enrichment': 60.0, + >>> 'enrichment_target': 'Li7'}, + >>> 'Fl': 1.0, + >>> 'Be6': 0.5} + >>> mat.add_components(components) + + """ + + for component, params in components.items(): + cv.check_type('component', component, str) + if isinstance(params, float): + params = {'percent': params} + + else: + cv.check_type('params', params, dict) + if 'percent' not in params: + raise ValueError("An entry in the dictionary does not have " + "a required key: 'percent'") + + params['percent_type'] = percent_type + + ## check if nuclide + if str.isdigit(component[-1]): + self.add_nuclide(component, **params) + else: # is element + kwargs = params + self.add_element(component, **params) + def remove_nuclide(self, nuclide: str): """Remove a nuclide from the material diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index fd0e4f6247..2c5cc2874c 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -25,6 +25,52 @@ def test_add_nuclide(): with pytest.raises(ValueError): m.add_nuclide('H1', 1.0, 'oa') +def test_add_components(): + """Test adding multipe elements or nuclides at once""" + m = openmc.Material() + components = {'H1': 2.0, + 'O16': 1.0, + 'Zr': 1.0, + 'O': 1.0, + 'U': {'percent': 1.0, + 'enrichment': 4.5}, + 'Li': {'percent': 1.0, + 'enrichment': 60.0, + 'enrichment_target': 'Li7'}, + 'H': {'percent': 1.0, + 'enrichment': 50.0, + 'enrichment_target': 'H2', + 'enrichment_type': 'wo'}} + m.add_components(components) + with pytest.raises(ValueError): + m.add_components({'U': {'percent': 1.0, + 'enrichment': 100.0}}) + with pytest.raises(ValueError): + m.add_components({'Pu': {'percent': 1.0, + 'enrichment': 3.0}}) + with pytest.raises(ValueError): + m.add_components({'U': {'percent': 1.0, + 'enrichment': 70.0, + 'enrichment_target':'U235'}}) + with pytest.raises(ValueError): + m.add_components({'He': {'percent': 1.0, + 'enrichment': 17.0, + 'enrichment_target': 'He6'}}) + with pytest.raises(ValueError): + m.add_components({'li': 1.0}) # should fail as 1st char is lowercase + with pytest.raises(ValueError): + m.add_components({'LI': 1.0}) # should fail as 2nd char is uppercase + with pytest.raises(ValueError): + m.add_components({'Xx': 1.0}) # should fail as Xx is not an element + with pytest.raises(ValueError): + m.add_components({'n': 1.0}) # check to avoid n for neutron being accepted + with pytest.raises(TypeError): + m.add_components({'H1': '1.0'}) + with pytest.raises(TypeError): + m.add_components({1.0: 'H1'}, percent_type = 'wo') + with pytest.raises(ValueError): + m.add_components({'H1': 1.0}, percent_type = 'oa') + def test_remove_nuclide(): """Test removing nuclides.""" @@ -49,7 +95,7 @@ def test_remove_elements(): assert m.nuclides[0].percent == 1.0 -def test_elements(): +def test_add_element(): """Test adding elements.""" m = openmc.Material() m.add_element('Zr', 1.0) @@ -74,7 +120,6 @@ def test_elements(): with pytest.raises(ValueError): m.add_element('n', 1.0) # check to avoid n for neutron being accepted - def test_elements_by_name(): """Test adding elements by name""" m = openmc.Material() @@ -441,7 +486,7 @@ def test_activity_of_tritium(): m1.add_nuclide("H3", 1) m1.set_density('g/cm3', 1) m1.volume = 1 - assert pytest.approx(m1.activity) == 3.559778e14 + assert pytest.approx(m1.activity) == 3.559778e14 def test_activity_of_metastable():