diff --git a/openmc/material.py b/openmc/material.py index 14bec12f33..9ba7360ff3 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -35,7 +35,7 @@ class Material(IDManagerMixin): 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()`. Alternatively, you can - use :meth:`Material.add_elements_or_nuclides()` to pass a dictionary + 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. @@ -405,41 +405,55 @@ class Material(IDManagerMixin): self._nuclides.append(NuclideTuple(nuclide, percent, percent_type)) - def add_elements_or_nuclides(self, components: dict): + def add_components(self, components: dict, percent_type: str = 'ao'): """ Add multiple elements or nuclides to a material Parameters ---------- - components : dict of str to tuple - Dictionary mapping element or nuclide names to a tuple containing - their atom or weight percent, as well as any other arguments. + 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': (1.0, {'enrichment': 60.0, 'enrichment_target': 'Li7'}), - >>> 'Fl': 1.0, - >>> 'Be6': (0.5, 'wo')} - >>> mat.add_elements_or_nuclides(components) + >>> components = {'Li': {'percent': 1.0, + >>> 'enrichment': 60.0, + >>> 'enrichment_target': 'Li7'}, + >>> 'Fl': 1.0, + >>> 'Be6': 0.5} + >>> mat.add_components(components) """ - for component, args in components.items(): + for component, params in components.items(): cv.check_type('component', component, str) - percent_type = 'ao' - if isinstance(args, float): - args = (args,) + 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'") + + percent = params.pop('percent') + args = (percent, percent_type) ## check if nuclide if str.isdigit(component[-1]): self.add_nuclide(component, *args) else: # is element - kwargs = {} - if isinstance(args[-1], dict): - kwargs = args[-1] - args = args[:-1] + kwargs = params self.add_element(component, *args, **kwargs) + params['percent'] = percent + 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 69ca87f2e6..2c5cc2874c 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -25,39 +25,51 @@ def test_add_nuclide(): with pytest.raises(ValueError): m.add_nuclide('H1', 1.0, 'oa') -def test_add_elements_or_nuclides(): +def test_add_components(): """Test adding multipe elements or nuclides at once""" m = openmc.Material() components = {'H1': 2.0, - 'O16': (1.0, 'wo'), - 'Zr': 1.0, - 'O': (1.0, 'wo'), - 'U': (1.0, {'enrichment': 4.5}), - 'Li': (1.0, 'ao', {'enrichment': 60.0, 'enrichment_target': 'Li7'}), - 'H': (1.0, 'ao', {'enrichment': 50.0, 'enrichment_target': 'H2', 'enrichment_type': 'wo'})} - m.add_elements_or_nuclides(components) + '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_elements_or_nuclides({'U': (1.0, 'ao', {'enrichment': 100.0})}) + m.add_components({'U': {'percent': 1.0, + 'enrichment': 100.0}}) with pytest.raises(ValueError): - m.add_elements_or_nuclides({'Pu': (1.0, 'ao', {'enrichment': 3.0})}) + m.add_components({'Pu': {'percent': 1.0, + 'enrichment': 3.0}}) with pytest.raises(ValueError): - m.add_elements_or_nuclides({'U': (1.0, 'ao', {'enrichment': 70.0, 'enrichment_target': 'U235'})}) + m.add_components({'U': {'percent': 1.0, + 'enrichment': 70.0, + 'enrichment_target':'U235'}}) with pytest.raises(ValueError): - m.add_elements_or_nuclides({'He': (1.0, 'ao', {'enrichment': 17.0, 'enrichment_target': 'He6'})}) + m.add_components({'He': {'percent': 1.0, + 'enrichment': 17.0, + 'enrichment_target': 'He6'}}) with pytest.raises(ValueError): - m.add_elements_or_nuclides({'li': (1.0, 'ao')}) # should fail as 1st char is lowercase + m.add_components({'li': 1.0}) # should fail as 1st char is lowercase with pytest.raises(ValueError): - m.add_elements_or_nuclides({'LI': (1.0, 'ao')}) # should fail as 2nd char is uppercase + m.add_components({'LI': 1.0}) # should fail as 2nd char is uppercase with pytest.raises(ValueError): - m.add_elements_or_nuclides({'Xx': (1.0, 'ao')}) # should fail as Xx is not an element + m.add_components({'Xx': 1.0}) # should fail as Xx is not an element with pytest.raises(ValueError): - m.add_elements_or_nuclides({'n': (1.0, 'ao')}) # check to avoid n for neutron being accepted + m.add_components({'n': 1.0}) # check to avoid n for neutron being accepted with pytest.raises(TypeError): - m.add_elements_or_nuclides({'H1': ('1.0', 'ao')}) + m.add_components({'H1': '1.0'}) with pytest.raises(TypeError): - m.add_elements_or_nuclides({1.0: ('H1', 'wo')}) + m.add_components({1.0: 'H1'}, percent_type = 'wo') with pytest.raises(ValueError): - m.add_elements_or_nuclides({'H1': (1.0, 'oa')}) + m.add_components({'H1': 1.0}, percent_type = 'oa') def test_remove_nuclide():