From 8fc788d0b2a0c99166d00c9aa6604d86f81dd068 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Sun, 2 Feb 2020 17:46:58 +0100 Subject: [PATCH 01/11] Change interface of Element.expand function -> Adds new optional argument enrichment_target to Element.expand -> expand uses old Uranium Enrichment method if enrichment is given without enrichment target -> Adds a comment to openmc.data to clarify that NATURAL_ABUNDANCE contains atomic fractions --- openmc/data/data.py | 1 + openmc/element.py | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/openmc/data/data.py b/openmc/data/data.py index e813209f0a..b7f2133c5a 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -10,6 +10,7 @@ from warnings import warn # pp. 293-306 (2013). The "representative isotopic abundance" values from # column 9 are used except where an interval is given, in which case the # "best measurement" is used. +# Note that the abundances are given as atomic fractions! NATURAL_ABUNDANCE = { 'H1': 0.99984426, 'H2': 0.00015574, 'He3': 0.000002, 'He4': 0.999998, 'Li6': 0.07589, 'Li7': 0.92411, diff --git a/openmc/element.py b/openmc/element.py index e364603348..f5e0bc79c1 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -35,7 +35,7 @@ class Element(str): return self def expand(self, percent, percent_type, enrichment=None, - cross_sections=None): + enrichment_target=None, cross_sections=None): """Expand natural element into its naturally-occurring isotopes. An optional cross_sections argument or the OPENMC_CROSS_SECTIONS @@ -52,9 +52,12 @@ class Element(str): percent_type : {'ao', 'wo'} 'ao' for atom percent and 'wo' for weight percent enrichment : float, optional - Enrichment for U235 in weight percent. For example, input 4.95 for - 4.95 weight percent enriched U. Default is None - (natural composition). + Enrichment of an enrichment_taget nuclide in weight percent. If + enrichment_taget is not supplied then it is enrichment for U235 in + weight percent. For example, input 4.95 for 4.95 weight percent + enriched U. Default is None (natural composition). + enrichment_target: str, optional + Single nuclide name to enrich from a natural composition e.g. O16 cross_sections : str, optional Location of cross_sections.xml file. Default is None. @@ -71,8 +74,8 @@ class Element(str): `ORNL/CSD/TM-244 `_ is used to calculate the weight fractions of U234, U235, U236, and U238. Namely, the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%, - respectively, of the U235 weight fraction. The remainder of the isotopic - weight is assigned to U238. + respectively, of the U235 weight fraction. The remainder of the + isotopic weight is assigned to U238. """ @@ -110,8 +113,8 @@ class Element(str): mutual_nuclides = sorted(list(mutual_nuclides)) absent_nuclides = sorted(list(absent_nuclides)) - # If all natural nuclides are present in the library, expand element - # using all natural nuclides + # If all natural nuclides are present in the library, + # expand element using all natural nuclides if len(absent_nuclides) == 0: for nuclide in mutual_nuclides: abundances[nuclide] = NATURAL_ABUNDANCE[nuclide] @@ -164,7 +167,8 @@ class Element(str): abundances[nuclide] = NATURAL_ABUNDANCE[nuclide] # Modify mole fractions if enrichment provided - if enrichment is not None: + # Old treatment for Uranium + if enrichment is not None and enrichment_target is None: # Calculate the mass fractions of isotopes abundances['U234'] = 0.0089 * enrichment @@ -181,6 +185,11 @@ class Element(str): for nuclide in abundances.keys(): abundances[nuclide] /= sum_abundances + # Modify mole fractions if enrichment provided + # New treatment for arbitrary element + elif enrichment is not None and enrichment_target is None: + raise ValueError() + # Compute the ratio of the nuclide atomic masses to the element # atomic mass if percent_type == 'wo': From 77c147dd3df22b73fface52bb1cc87021874b273 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Sun, 2 Feb 2020 20:54:41 +0100 Subject: [PATCH 02/11] Initial enrichment option in Element.expand -> Implementation supports only wt% enrichment -> Multiple unnecessary conversions from at% to wt% can happen -> Can produce -ve fractions if enrichment > 100 --- openmc/element.py | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index f5e0bc79c1..ce9c2ce243 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -187,8 +187,56 @@ class Element(str): # Modify mole fractions if enrichment provided # New treatment for arbitrary element - elif enrichment is not None and enrichment_target is None: - raise ValueError() + # Interpret required enrichment as weight % + elif enrichment is not None and enrichment_target is not None: + + # Check if the target nuclide is present in the mixture + if enrichment_target not in abundances.keys(): + msg = 'Could not find the the target nuclide {0} in natural '\ + 'isotopic composition of element {1}. Following ' \ + 'isotopes are available: {2} '\ + .format(enrichment_target, self, list(abundances.keys())) + raise ValueError(msg) + + # Check if is a single isotope mixture + if len(abundances) == 1: + msg = 'Element {0} consist of single isotope. Thus it cannot '\ + 'be enriched.'.format(self) + raise ValueError(msg) + + # Convert the atomic abundances to weight fractions + # Compute the element atomic mass + element_am = 0.0 + for nuclide in abundances.keys(): + element_am += atomic_mass(nuclide) * abundances[nuclide] + + # Convert the molar fractions to mass fractions + for nuclide in abundances.keys(): + abundances[nuclide] *= atomic_mass(nuclide) / element_am + + # Normalize the mass fractions to one + sum_abundances = sum(abundances.values()) + for nuclide in abundances.keys(): + abundances[nuclide] /= sum_abundances + + # Get fraction of non-enriched isotopes in nat. composition + non_enriched = 1.0 - abundances[enrichment_target] + tail_fraction = 1.0 - enrichment / 100.0 + + # Enrich the mixture + for nuclide, fraction in abundances.items(): + abundances[nuclide] = tail_fraction * fraction / non_enriched + abundances[enrichment_target] = enrichment / 100.0 + + # Convert back to atomic fractions + # Convert the mass fractions to mole fractions + for nuclide in abundances.keys(): + abundances[nuclide] /= atomic_mass(nuclide) + + # Normalize the mole fractions to one + sum_abundances = sum(abundances.values()) + for nuclide in abundances.keys(): + abundances[nuclide] /= sum_abundances # Compute the ratio of the nuclide atomic masses to the element # atomic mass From a3ac3fb4783d7720bd5171a1f2487507ebb3e117 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Sun, 2 Feb 2020 21:12:16 +0100 Subject: [PATCH 03/11] Fills gaps in docstring of Element --- openmc/element.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/openmc/element.py b/openmc/element.py index ce9c2ce243..325042e913 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -68,6 +68,22 @@ class Element(str): is a tuple consisting of a nuclide string, the atom/weight percent, and the string 'ao' or 'wo'. + Raises + ------ + ValueError + No data is available for any of natural isotopes of the element + + ValueError + If only some natural isotopes are avaiable in cross-sections data + library and element is not O, W or Ta + + ValueError + Enrichment of isotope not present in natural composition of + the element is requested + + ValueError + Enrichment is requested of the element composed of single isotope + Notes ----- When the `enrichment` argument is specified, a correlation from @@ -77,6 +93,8 @@ class Element(str): respectively, of the U235 weight fraction. The remainder of the isotopic weight is assigned to U238. + Function does not check if enrichment value is in a valid range <0;100> + """ # Get the nuclides present in nature @@ -186,7 +204,7 @@ class Element(str): abundances[nuclide] /= sum_abundances # Modify mole fractions if enrichment provided - # New treatment for arbitrary element + # New treatment for arbitrary element94.96165869352852 # Interpret required enrichment as weight % elif enrichment is not None and enrichment_target is not None: From 1e432863b17868bb94058e7095722981a9370cc3 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Fri, 14 Feb 2020 16:12:44 +0000 Subject: [PATCH 04/11] Enrichment gives exceptions for non 2 isotopes Following discussion in the issues the functionality to enrich mixtures of more then 2 nuclides is block by an exception. The algorithim should still support larger mixtures. --- openmc/element.py | 80 ++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index 325042e913..4bedda77d7 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -35,7 +35,8 @@ class Element(str): return self def expand(self, percent, percent_type, enrichment=None, - enrichment_target=None, cross_sections=None): + enrichment_target=None, enrichment_type='ao', + cross_sections=None): """Expand natural element into its naturally-occurring isotopes. An optional cross_sections argument or the OPENMC_CROSS_SECTIONS @@ -52,12 +53,15 @@ class Element(str): percent_type : {'ao', 'wo'} 'ao' for atom percent and 'wo' for weight percent enrichment : float, optional - Enrichment of an enrichment_taget nuclide in weight percent. If - enrichment_taget is not supplied then it is enrichment for U235 in + Enrichment of an enrichment_taget nuclide in percent (ao or wo). + If enrichment_taget is not supplied then it is enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). enrichment_target: str, optional Single nuclide name to enrich from a natural composition e.g. O16 + enrichment_type: {'ao', 'wo'}, optional + 'ao' for enrichment as atom percent and 'wo' for weight percent. + Default is 'ao' cross_sections : str, optional Location of cross_sections.xml file. Default is None. @@ -78,11 +82,12 @@ class Element(str): library and element is not O, W or Ta ValueError - Enrichment of isotope not present in natural composition of - the element is requested + Enrichment of isotope which is not present in natural composition + of the element is requested ValueError - Enrichment is requested of the element composed of single isotope + Enrichment is requested of the element composed of more or less + then 2 isotopes. Notes ----- @@ -208,6 +213,13 @@ class Element(str): # Interpret required enrichment as weight % elif enrichment is not None and enrichment_target is not None: + # Check if is a single isotope mixture + if len(abundances) != 2: + msg = 'Element {0} does not consist of 2 isotopes. Thus it '\ + 'cannot be enriched with in-build procedure. Please '\ + 'enter isotopic abundances manually. '.format(self) + raise ValueError(msg) + # Check if the target nuclide is present in the mixture if enrichment_target not in abundances.keys(): msg = 'Could not find the the target nuclide {0} in natural '\ @@ -216,45 +228,49 @@ class Element(str): .format(enrichment_target, self, list(abundances.keys())) raise ValueError(msg) - # Check if is a single isotope mixture - if len(abundances) == 1: - msg = 'Element {0} consist of single isotope. Thus it cannot '\ - 'be enriched.'.format(self) - raise ValueError(msg) + # If weight percent enrichment is requested convert to mass fractions + if enrichment_type == 'wo': + # Convert the atomic abundances to weight fractions + # Compute the element atomic mass + element_am = 0.0 + for nuclide in abundances.keys(): + element_am += atomic_mass(nuclide) * abundances[nuclide] - # Convert the atomic abundances to weight fractions - # Compute the element atomic mass - element_am = 0.0 - for nuclide in abundances.keys(): - element_am += atomic_mass(nuclide) * abundances[nuclide] + # Convert Molar Fractions to mass fractions + for nuclide in abundances.keys(): + abundances[nuclide] *= atomic_mass(nuclide) / element_am - # Convert the molar fractions to mass fractions - for nuclide in abundances.keys(): - abundances[nuclide] *= atomic_mass(nuclide) / element_am + # Normalise to one + sum_abundances = sum(abundances.values()) + for nuclide in abundances.keys(): + abundances[nuclide] /= sum_abundances - # Normalize the mass fractions to one - sum_abundances = sum(abundances.values()) - for nuclide in abundances.keys(): - abundances[nuclide] /= sum_abundances + # Enrich the mixture + # The procedure is more generic that it needs to be. It allows + # to enrich mixtures of more then 2 isotopes, keeping the rations + # of non-enriched nuclides the same as in natural composition # Get fraction of non-enriched isotopes in nat. composition non_enriched = 1.0 - abundances[enrichment_target] tail_fraction = 1.0 - enrichment / 100.0 - # Enrich the mixture + # Enrich all nuclides + # Do bogus operation for enrichment target but overwrite immediatly + # to avoid if statement in the loop for nuclide, fraction in abundances.items(): abundances[nuclide] = tail_fraction * fraction / non_enriched abundances[enrichment_target] = enrichment / 100.0 - # Convert back to atomic fractions - # Convert the mass fractions to mole fractions - for nuclide in abundances.keys(): - abundances[nuclide] /= atomic_mass(nuclide) + # Convert back to atomic fractions if requested + if enrichment_type == 'wo': + # Convert the mass fractions to mole fractions + for nuclide in abundances.keys(): + abundances[nuclide] /= atomic_mass(nuclide) - # Normalize the mole fractions to one - sum_abundances = sum(abundances.values()) - for nuclide in abundances.keys(): - abundances[nuclide] /= sum_abundances + # Normalize the mole fractions to one + sum_abundances = sum(abundances.values()) + for nuclide in abundances.keys(): + abundances[nuclide] /= sum_abundances # Compute the ratio of the nuclide atomic masses to the element # atomic mass From 98253ab9b4e2bc3a8cf7805ddc049adee235c17d Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Fri, 14 Feb 2020 17:54:01 +0000 Subject: [PATCH 05/11] Implemented unit tests for Element.expand --- openmc/element.py | 20 ++++++--- tests/unit_tests/test_element.py | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 tests/unit_tests/test_element.py diff --git a/openmc/element.py b/openmc/element.py index 4bedda77d7..dd3ef15359 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -54,8 +54,8 @@ class Element(str): 'ao' for atom percent and 'wo' for weight percent enrichment : float, optional Enrichment of an enrichment_taget nuclide in percent (ao or wo). - If enrichment_taget is not supplied then it is enrichment for U235 in - weight percent. For example, input 4.95 for 4.95 weight percent + If enrichment_taget is not supplied then it is enrichment for U235 + in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). enrichment_target: str, optional Single nuclide name to enrich from a natural composition e.g. O16 @@ -86,8 +86,8 @@ class Element(str): of the element is requested ValueError - Enrichment is requested of the element composed of more or less - then 2 isotopes. + Enrichment is requested of the element that is not composed of + two isotopes. Notes ----- @@ -101,6 +101,8 @@ class Element(str): Function does not check if enrichment value is in a valid range <0;100> """ + # Check input + cv.check_value('enrichment_type', enrichment_type, {'ao', 'wo'}) # Get the nuclides present in nature natural_nuclides = set() @@ -193,6 +195,12 @@ class Element(str): # Old treatment for Uranium if enrichment is not None and enrichment_target is None: + # Check that the element is Uranium + if self.name != 'U': + msg = 'Enrichment procedure for Uranium was requested, '\ + 'but the isotope is {0} not U'.format(self) + raise ValueError(msg) + # Calculate the mass fractions of isotopes abundances['U234'] = 0.0089 * enrichment abundances['U235'] = enrichment @@ -209,8 +217,8 @@ class Element(str): abundances[nuclide] /= sum_abundances # Modify mole fractions if enrichment provided - # New treatment for arbitrary element94.96165869352852 - # Interpret required enrichment as weight % + # New treatment for arbitrary element + # Interpret required enrichment as weight elif enrichment is not None and enrichment_target is not None: # Check if is a single isotope mixture diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py new file mode 100644 index 0000000000..1143b5357d --- /dev/null +++ b/tests/unit_tests/test_element.py @@ -0,0 +1,75 @@ +import openmc.element +import pytest as pt + +from openmc.data import NATURAL_ABUNDANCE, atomic_mass + +# Relative tolerance for float comparison +TOL = 1e-9 + + +def test_expand_no_ernichment(): + """ Expand Li in natural compositions""" + lithium = openmc.element.Element('Li') + + # Verify the expansion into ATOMIC fraction against natural composition + for isotope in lithium.expand(100.0, 'ao'): + assert isotope[1] == pt.approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0, rel=TOL) + + # Verify the expanction into WEIGHT fraction against natural composition + natural = {'Li6': NATURAL_ABUNDANCE['Li6'] * atomic_mass('Li6'), + 'Li7': NATURAL_ABUNDANCE['Li7'] * atomic_mass('Li7')} + li_am = sum(natural.values()) + for key in natural.keys(): + natural[key] /= li_am + + for isotope in lithium.expand(100.0, 'wo'): + assert isotope[1] == pt.approx(natural[isotope[0]] * 100.0, rel=TOL) + + +def test_expand_enrichment(): + """ Expand and verify enrichment of Li """ + lithium = openmc.element.Element('Li') + + # Verify the enrichment by atoms + ref = {'Li6': 75.0, 'Li7': 25.0} + for isotope in lithium.expand(100.0, 'ao', 25.0, 'Li7', 'ao'): + assert isotope[1] == pt.approx(ref[isotope[0]], rel=TOL) + + # Verify the enrichment by weight + for isotope in lithium.expand(100.0, 'wo', 25.0, 'Li7', 'wo'): + assert isotope[1] == pt.approx(ref[isotope[0]], rel=TOL) + + +def test_expand_exceptions(): + """ Test that correct exceptions are raiused for invalid input """ + + # 1 Isotope Element + with pt.raises(ValueError): + element = openmc.element.Element('Be') + fail = element.expand(70.0, 'ao', 4.0, 'Be9') + + # 3 Isotope Element + with pt.raises(ValueError): + element = openmc.element.Element('Cr') + fail = element.expand(70.0, 'ao', 4.0, 'Cr52') + + # Non-present Enrichment Target + with pt.raises(ValueError): + element = openmc.element.Element('H') + fail = element.expand(70.0, 'ao', 4.0, 'H4') + + # Enrichment Procedure for Uranium if not Uranium + with pt.raises(ValueError): + element = openmc.element.Element('Li') + fail = element.expand(70.0, 'ao', 4.0) + + # Missing Enrichment Target + with pt.raises(ValueError): + element = openmc.element.Element('Li') + fail = element.expand(70.0, 'ao', 4.0, enrichment_type='ao') + + # Invalid Enrichment Type Entry + with pt.raises(ValueError): + element = openmc.element.Element('Li') + fail = element.expand(70.0, 'ao', 4.0, 'Li7','Grand Moff Tarkin') + From d5f9a962e5a570f18b235430f090e9a2bdff8339 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Fri, 14 Feb 2020 18:55:50 +0000 Subject: [PATCH 06/11] Adds general element enrichment to Material Adds an option to specify an enrichment of an element composed of two isotopes to Material.add_element --- openmc/element.py | 22 ++++++++++++++++++- openmc/material.py | 36 ++++++++++++++++++++++++------- tests/unit_tests/test_material.py | 7 ++++++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index dd3ef15359..007ace2761 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -4,6 +4,7 @@ import os from xml.etree import ElementTree as ET import openmc.checkvalue as cv +from numbers import Real from openmc.data import NATURAL_ABUNDANCE, atomic_mass @@ -57,6 +58,7 @@ class Element(str): If enrichment_taget is not supplied then it is enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). + Value must be in <0;100> enrichment_target: str, optional Single nuclide name to enrich from a natural composition e.g. O16 enrichment_type: {'ao', 'wo'}, optional @@ -89,6 +91,16 @@ class Element(str): Enrichment is requested of the element that is not composed of two isotopes. + ValueError + If `enrichment_type` is not 'ao' or 'wo' + + ValueError + If `enrichment` is outside <0;100> range + + ValueError + If enrichment procedure for Uranium is used when element is not + Uranium. + Notes ----- When the `enrichment` argument is specified, a correlation from @@ -98,12 +110,20 @@ class Element(str): respectively, of the U235 weight fraction. The remainder of the isotopic weight is assigned to U238. - Function does not check if enrichment value is in a valid range <0;100> + When the `enrichment` argument is specified with `enrichment_target` a + general enrichment procedure is used. It will raise exception unless + element is composed of excatly 2 isotopes. `enrichment` is interpreted + as percent. By default it is atomic. Can be controlled by variable + `enrichment_type`. """ # Check input cv.check_value('enrichment_type', enrichment_type, {'ao', 'wo'}) + if enrichment is not None: + cv.check_less_than('enrichment', enrichment, 100.0, equality=True) + cv.check_greater_than('enrichment', enrichment, 0., equality=True) + # Get the nuclides present in nature natural_nuclides = set() for nuclide in sorted(NATURAL_ABUNDANCE.keys()): diff --git a/openmc/material.py b/openmc/material.py index 996d6a3327..ed361ca4f1 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -499,7 +499,8 @@ class Material(IDManagerMixin): if macroscopic == self._macroscopic: self._macroscopic = None - def add_element(self, element, percent, percent_type='ao', enrichment=None): + def add_element(self, element, percent, percent_type='ao', enrichment=None, + enrichment_target=None, enrichment_type='ao'): """Add a natural element to the material Parameters @@ -512,9 +513,24 @@ class Material(IDManagerMixin): 'ao' for atom percent and 'wo' for weight percent. Defaults to atom percent. enrichment : float, optional - Enrichment for U235 in weight percent. For example, input 4.95 for - 4.95 weight percent enriched U. Default is None - (natural composition). + Enrichment of an enrichment_taget nuclide in percent (ao or wo). + If enrichment_taget is not supplied then it is enrichment for U235 + in weight percent. For example, input 4.95 for 4.95 weight percent + enriched U. + Default is None (natural composition). + Value must be in <0;100> for general nuclide + Value must be in <0;100./1.008) for Uranium + enrichment_target: str, optional + Single nuclide name to enrich from a natural composition e.g. O16 + enrichment_type: {'ao', 'wo'}, optional + 'ao' for enrichment as atom percent and 'wo' for weight percent. + Default is 'ao' + + Notes + ----- + General enrichment procedure is allowed only for elements composed of + two isotopes. If `enrichment_target` is given withou `enrichment` + natural composition is added to the material. """ cv.check_type('nuclide', element, str) @@ -526,7 +542,7 @@ class Material(IDManagerMixin): 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) - if enrichment is not None: + if enrichment is not None and enrichment_target is None: if not isinstance(enrichment, Real): msg = 'Unable to add an Element to Material ID="{}" with a ' \ 'non-floating point enrichment value "{}"'\ @@ -558,7 +574,11 @@ class Material(IDManagerMixin): # Add naturally-occuring isotopes element = openmc.Element(element) - for nuclide in element.expand(percent, percent_type, enrichment): + for nuclide in element.expand(percent, + percent_type, + enrichment, + enrichment_target, + enrichment_type): self.add_nuclide(*nuclide) def add_s_alpha_beta(self, name, fraction=1.0): @@ -927,7 +947,7 @@ class Material(IDManagerMixin): Fractions of each material to be combined percent_type : {'ao', 'wo', 'vo'} Type of percentage, must be one of 'ao', 'wo', or 'vo', to signify atom - percent (molar percent), weight percent, or volume percent, + percent (molar percent), weight percent, or volume percent, optional. Defaults to 'ao' name : str The name for the new material, optional. Defaults to concatenated @@ -996,7 +1016,7 @@ class Material(IDManagerMixin): zip(materials, fracs)]) new_mat = openmc.Material(name=name) - # Compute atom fractions of nuclides and add them to the new material + # Compute atom fractions of nuclides and add them to the new material tot_nuclides_per_cc = np.sum([dens for dens in nuclides_per_cc.values()]) for nuc, atom_dens in nuclides_per_cc.items(): new_mat.add_nuclide(nuc, atom_dens/tot_nuclides_per_cc, 'ao') diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index cbff16e403..fdf88aa7dc 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -29,10 +29,17 @@ def test_elements(): m = openmc.Material() m.add_element('Zr', 1.0) m.add_element('U', 1.0, enrichment=4.5) + m.add_element('Li', 1.0, enrichment=60.0, enrichment_target='Li7') + m.add_element('H', 1.0, enrichment=50.0, enrichment_target='H2', + enrichment_type='wo') with pytest.raises(ValueError): m.add_element('U', 1.0, enrichment=100.0) with pytest.raises(ValueError): m.add_element('Pu', 1.0, enrichment=3.0) + with pytest.raises(ValueError): + m.add_element('U', 1.0, enrichment=70.0, enrichment_target='U235') + with pytest.raises(ValueError): + m.add_element('He', 1.0, enrichment=17.0, enrichment_target='He6') def test_density(): From 9078010d8898d064d93c7c927f8a07eb0f956a41 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Wed, 26 Feb 2020 12:18:19 +0000 Subject: [PATCH 07/11] Address comments by @simondrichards Also remove spaces between Raises entries in docstring of Element.expand --- docs/source/usersguide/materials.rst | 14 ++++++++++++++ openmc/element.py | 26 +++++++++++++++----------- openmc/material.py | 2 +- tests/unit_tests/test_element.py | 12 ++++++++---- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/docs/source/usersguide/materials.rst b/docs/source/usersguide/materials.rst index 8472768489..4468fd25e1 100644 --- a/docs/source/usersguide/materials.rst +++ b/docs/source/usersguide/materials.rst @@ -55,6 +55,20 @@ following would add 3.2% enriched uranium to a material:: In addition to U235 and U238, concentrations of U234 and U236 will be present and are determined through a correlation based on measured data. +It is also possible to perform enrichment of any element that is composed +of two naturally-occurring isotopes (e.g. Li, B) in terms of atomic percent. +To invoke it, provide additional arguments `enrichment_target` to +:meth:`Material.add_element`. For example the following would enrich B10 +to 30ao%:: + + mat.add_element('B', 1.0, enrichment=30.0, enrichment_target='B10') + +In order to enrich an isotope in terms of mass percent (wo%). Provide extra +argument `enrichment_type`. For example the following would enrich Li6 to 15wo%:: + + mat.add_element('Li', 1.0, enrichment=15.0, enrichment_target='Li6', + enrichment_type='wo') + Often, cross section libraries don't actually have all naturally-occurring isotopes for a given element. For example, in ENDF/B-VII.1, cross section evaluations are given for O16 and O17 but not for O18. If OpenMC is aware of diff --git a/openmc/element.py b/openmc/element.py index 007ace2761..42079bc7d4 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -78,25 +78,19 @@ class Element(str): ------ ValueError No data is available for any of natural isotopes of the element - ValueError If only some natural isotopes are avaiable in cross-sections data library and element is not O, W or Ta - ValueError Enrichment of isotope which is not present in natural composition of the element is requested - ValueError Enrichment is requested of the element that is not composed of two isotopes. - ValueError If `enrichment_type` is not 'ao' or 'wo' - ValueError If `enrichment` is outside <0;100> range - ValueError If enrichment procedure for Uranium is used when element is not Uranium. @@ -112,7 +106,7 @@ class Element(str): When the `enrichment` argument is specified with `enrichment_target` a general enrichment procedure is used. It will raise exception unless - element is composed of excatly 2 isotopes. `enrichment` is interpreted + element is composed of exactly 2 isotopes. `enrichment` is interpreted as percent. By default it is atomic. Can be controlled by variable `enrichment_type`. @@ -241,11 +235,21 @@ class Element(str): # Interpret required enrichment as weight elif enrichment is not None and enrichment_target is not None: - # Check if is a single isotope mixture + # Provide more informative error message for U235 + if enrichment_target == 'U235': + msg = "There is a special procedure for enrichment of U235 "\ + "in U. To invoke it do not specify neither "\ + "'enrichment_target' nor 'enrichment_type'. Provide "\ + "only enrichment as 'wo%'. See User Guide for more "\ + "details" + raise ValueError(msg) + + # Check if it is two-isotope mixture if len(abundances) != 2: - msg = 'Element {0} does not consist of 2 isotopes. Thus it '\ - 'cannot be enriched with in-build procedure. Please '\ - 'enter isotopic abundances manually. '.format(self) + msg = 'Element {0} does not consist of 2 naturally-occurring '\ + 'isotopes. Therefore it cannot be enriched with the '\ + 'in-build procedure. Please enter isotopic abundances '\ + 'manually.'.format(self) raise ValueError(msg) # Check if the target nuclide is present in the mixture diff --git a/openmc/material.py b/openmc/material.py index ed361ca4f1..b1c5a7ccaa 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -529,7 +529,7 @@ class Material(IDManagerMixin): Notes ----- General enrichment procedure is allowed only for elements composed of - two isotopes. If `enrichment_target` is given withou `enrichment` + two isotopes. If `enrichment_target` is given without `enrichment` natural composition is added to the material. """ diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index 1143b5357d..727fc69501 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -7,7 +7,7 @@ from openmc.data import NATURAL_ABUNDANCE, atomic_mass TOL = 1e-9 -def test_expand_no_ernichment(): +def test_expand_no_enrichment(): """ Expand Li in natural compositions""" lithium = openmc.element.Element('Li') @@ -15,7 +15,7 @@ def test_expand_no_ernichment(): for isotope in lithium.expand(100.0, 'ao'): assert isotope[1] == pt.approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0, rel=TOL) - # Verify the expanction into WEIGHT fraction against natural composition + # Verify the expansion into WEIGHT fraction against natural composition natural = {'Li6': NATURAL_ABUNDANCE['Li6'] * atomic_mass('Li6'), 'Li7': NATURAL_ABUNDANCE['Li7'] * atomic_mass('Li7')} li_am = sum(natural.values()) @@ -41,7 +41,7 @@ def test_expand_enrichment(): def test_expand_exceptions(): - """ Test that correct exceptions are raiused for invalid input """ + """ Test that correct exceptions are raised for invalid input """ # 1 Isotope Element with pt.raises(ValueError): @@ -71,5 +71,9 @@ def test_expand_exceptions(): # Invalid Enrichment Type Entry with pt.raises(ValueError): element = openmc.element.Element('Li') - fail = element.expand(70.0, 'ao', 4.0, 'Li7','Grand Moff Tarkin') + fail = element.expand(70.0, 'ao', 4.0, 'Li7', 'Grand Moff Tarkin') + # Trying to enrich Uranium + with pt.raises(ValueError): + element = openmc.element.Element('U') + fail = element.expand(70.0, 'ao', 4.0, 'U235', 'wo') From d1f71f23282960778cd9e4e77fb08a0e5cd0da3d Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Wed, 26 Feb 2020 15:50:53 +0000 Subject: [PATCH 08/11] Address further comments by @simondrichards Corrects spelling and grammar. --- docs/source/usersguide/materials.rst | 4 ++-- openmc/element.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/usersguide/materials.rst b/docs/source/usersguide/materials.rst index 4468fd25e1..4c6e867596 100644 --- a/docs/source/usersguide/materials.rst +++ b/docs/source/usersguide/materials.rst @@ -57,13 +57,13 @@ and are determined through a correlation based on measured data. It is also possible to perform enrichment of any element that is composed of two naturally-occurring isotopes (e.g. Li, B) in terms of atomic percent. -To invoke it, provide additional arguments `enrichment_target` to +To invoke this, provide the additional argument `enrichment_target` to :meth:`Material.add_element`. For example the following would enrich B10 to 30ao%:: mat.add_element('B', 1.0, enrichment=30.0, enrichment_target='B10') -In order to enrich an isotope in terms of mass percent (wo%). Provide extra +In order to enrich an isotope in terms of mass percent (wo%), provide the extra argument `enrichment_type`. For example the following would enrich Li6 to 15wo%:: mat.add_element('Li', 1.0, enrichment=15.0, enrichment_target='Li6', diff --git a/openmc/element.py b/openmc/element.py index 42079bc7d4..d18c5213f2 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -238,9 +238,9 @@ class Element(str): # Provide more informative error message for U235 if enrichment_target == 'U235': msg = "There is a special procedure for enrichment of U235 "\ - "in U. To invoke it do not specify neither "\ - "'enrichment_target' nor 'enrichment_type'. Provide "\ - "only enrichment as 'wo%'. See User Guide for more "\ + "in U. To invoke it, the arguments 'enrichment_taget'"\ + "and 'enrichment_type' should be omitted. Provide "\ + "only 'enrichment' as 'wo%'. See User Guide for more "\ "details" raise ValueError(msg) From 196c4a07356a506ca2c135a105fa96808a3615be Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Sat, 29 Feb 2020 20:34:05 +0000 Subject: [PATCH 09/11] Add exception for U enrichment with type 'ao' Remove a confusing comment. --- openmc/element.py | 18 +++++++++++------- openmc/material.py | 2 +- tests/unit_tests/test_element.py | 5 +++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index d18c5213f2..c882791095 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -36,7 +36,7 @@ class Element(str): return self def expand(self, percent, percent_type, enrichment=None, - enrichment_target=None, enrichment_type='ao', + enrichment_target=None, enrichment_type=None, cross_sections=None): """Expand natural element into its naturally-occurring isotopes. @@ -87,13 +87,11 @@ class Element(str): ValueError Enrichment is requested of the element that is not composed of two isotopes. - ValueError - If `enrichment_type` is not 'ao' or 'wo' - ValueError - If `enrichment` is outside <0;100> range ValueError If enrichment procedure for Uranium is used when element is not Uranium. + ValueError + Uranium enrichment is requested with enrichment_type=='ao' Notes ----- @@ -112,7 +110,8 @@ class Element(str): """ # Check input - cv.check_value('enrichment_type', enrichment_type, {'ao', 'wo'}) + if enrichment_type is not None: + cv.check_value('enrichment_type', enrichment_type, {'ao', 'wo'}) if enrichment is not None: cv.check_less_than('enrichment', enrichment, 100.0, equality=True) @@ -215,6 +214,12 @@ class Element(str): 'but the isotope is {0} not U'.format(self) raise ValueError(msg) + # Check that enrichment_type is not 'ao' + if enrichment_type == 'ao': + msg = 'Enrichment procedure for Uranium requires that '\ + 'enrichment value is provided as wo%.' + raise ValueError(msg) + # Calculate the mass fractions of isotopes abundances['U234'] = 0.0089 * enrichment abundances['U235'] = enrichment @@ -232,7 +237,6 @@ class Element(str): # Modify mole fractions if enrichment provided # New treatment for arbitrary element - # Interpret required enrichment as weight elif enrichment is not None and enrichment_target is not None: # Provide more informative error message for U235 diff --git a/openmc/material.py b/openmc/material.py index b1c5a7ccaa..aea6a10376 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -500,7 +500,7 @@ class Material(IDManagerMixin): self._macroscopic = None def add_element(self, element, percent, percent_type='ao', enrichment=None, - enrichment_target=None, enrichment_type='ao'): + enrichment_target=None, enrichment_type=None): """Add a natural element to the material Parameters diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index 727fc69501..5a17f1f221 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -77,3 +77,8 @@ def test_expand_exceptions(): with pt.raises(ValueError): element = openmc.element.Element('U') fail = element.expand(70.0, 'ao', 4.0, 'U235', 'wo') + + # Trying to enrich Uranium with wrong enrichment_target + with pt.raises(ValueError): + element = openmc.element.Element('U') + fail = element.expand(70.0, 'ao', 4.0, enrichment_type='ao') From bcc4a52eb9ef7e2634897025ef5531abc244879f Mon Sep 17 00:00:00 2001 From: Mikolaj-A-Kowalski <32641577+Mikolaj-A-Kowalski@users.noreply.github.com> Date: Wed, 4 Mar 2020 11:41:52 +0000 Subject: [PATCH 10/11] Apply suggestions from code review Co-Authored-By: Paul Romano --- docs/source/usersguide/materials.rst | 2 +- openmc/element.py | 72 +++++++++++++--------------- openmc/material.py | 4 +- tests/unit_tests/test_element.py | 66 ++++++++++++------------- 4 files changed, 67 insertions(+), 77 deletions(-) diff --git a/docs/source/usersguide/materials.rst b/docs/source/usersguide/materials.rst index 4c6e867596..feebbe5884 100644 --- a/docs/source/usersguide/materials.rst +++ b/docs/source/usersguide/materials.rst @@ -56,7 +56,7 @@ In addition to U235 and U238, concentrations of U234 and U236 will be present and are determined through a correlation based on measured data. It is also possible to perform enrichment of any element that is composed -of two naturally-occurring isotopes (e.g. Li, B) in terms of atomic percent. +of two naturally-occurring isotopes (e.g., Li or B) in terms of atomic percent. To invoke this, provide the additional argument `enrichment_target` to :meth:`Material.add_element`. For example the following would enrich B10 to 30ao%:: diff --git a/openmc/element.py b/openmc/element.py index c882791095..94b6ae8d6d 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -58,9 +58,8 @@ class Element(str): If enrichment_taget is not supplied then it is enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). - Value must be in <0;100> enrichment_target: str, optional - Single nuclide name to enrich from a natural composition e.g. O16 + Single nuclide name to enrich from a natural composition (e.g., 'O16') enrichment_type: {'ao', 'wo'}, optional 'ao' for enrichment as atom percent and 'wo' for weight percent. Default is 'ao' @@ -79,14 +78,13 @@ class Element(str): ValueError No data is available for any of natural isotopes of the element ValueError - If only some natural isotopes are avaiable in cross-sections data - library and element is not O, W or Ta + If only some natural isotopes are available in the cross-section data + library and the element is not O, W, or Ta ValueError - Enrichment of isotope which is not present in natural composition - of the element is requested + If a non-naturally-occurring isotope is requested ValueError - Enrichment is requested of the element that is not composed of - two isotopes. + If enrichment is requested of an element with more than two + naturally-occurring isotopes. ValueError If enrichment procedure for Uranium is used when element is not Uranium. @@ -102,11 +100,11 @@ class Element(str): respectively, of the U235 weight fraction. The remainder of the isotopic weight is assigned to U238. - When the `enrichment` argument is specified with `enrichment_target` a - general enrichment procedure is used. It will raise exception unless - element is composed of exactly 2 isotopes. `enrichment` is interpreted - as percent. By default it is atomic. Can be controlled by variable - `enrichment_type`. + When the `enrichment` argument is specified with `enrichment_target`, a + general enrichment procedure is used for elements composed of exactly + two naturally-occurring isotopes. `enrichment` is interpreted as atom + percent by default but can be controlled by the `enrichment_type` + argument. """ # Check input @@ -210,14 +208,14 @@ class Element(str): # Check that the element is Uranium if self.name != 'U': - msg = 'Enrichment procedure for Uranium was requested, '\ - 'but the isotope is {0} not U'.format(self) + msg = ('Enrichment procedure for Uranium was requested, ' + 'but the isotope is {} not U'.format(self)) raise ValueError(msg) # Check that enrichment_type is not 'ao' if enrichment_type == 'ao': - msg = 'Enrichment procedure for Uranium requires that '\ - 'enrichment value is provided as wo%.' + msg = ('Enrichment procedure for Uranium requires that ' + 'enrichment value is provided as wo%.') raise ValueError(msg) # Calculate the mass fractions of isotopes @@ -241,49 +239,43 @@ class Element(str): # Provide more informative error message for U235 if enrichment_target == 'U235': - msg = "There is a special procedure for enrichment of U235 "\ - "in U. To invoke it, the arguments 'enrichment_taget'"\ - "and 'enrichment_type' should be omitted. Provide "\ - "only 'enrichment' as 'wo%'. See User Guide for more "\ - "details" + msg = ("There is a special procedure for enrichment of U235 " + "in U. To invoke it, the arguments 'enrichment_target'" + "and 'enrichment_type' should be omitted. Provide " + "a value only for 'enrichment' in weight percent.") raise ValueError(msg) # Check if it is two-isotope mixture if len(abundances) != 2: - msg = 'Element {0} does not consist of 2 naturally-occurring '\ - 'isotopes. Therefore it cannot be enriched with the '\ - 'in-build procedure. Please enter isotopic abundances '\ - 'manually.'.format(self) + msg = ('Element {} does not consist of two naturally-occurring ' + 'isotopes. Please enter isotopic abundances manually.' + .format(self)) raise ValueError(msg) # Check if the target nuclide is present in the mixture - if enrichment_target not in abundances.keys(): - msg = 'Could not find the the target nuclide {0} in natural '\ - 'isotopic composition of element {1}. Following ' \ - 'isotopes are available: {2} '\ - .format(enrichment_target, self, list(abundances.keys())) + if enrichment_target not in abundances: + msg = ('The target nuclide {} is not one of the naturally-occurring ' + 'isotopes ({})'.format(enrichment_target, list(abundances))) raise ValueError(msg) # If weight percent enrichment is requested convert to mass fractions if enrichment_type == 'wo': # Convert the atomic abundances to weight fractions # Compute the element atomic mass - element_am = 0.0 - for nuclide in abundances.keys(): - element_am += atomic_mass(nuclide) * abundances[nuclide] + element_am = sum(atomic_mass(nuc)*abundances[nuc] for nuc in abundances) # Convert Molar Fractions to mass fractions - for nuclide in abundances.keys(): + for nuclide in abundances: abundances[nuclide] *= atomic_mass(nuclide) / element_am - # Normalise to one + # Normalize to one sum_abundances = sum(abundances.values()) - for nuclide in abundances.keys(): + for nuclide in abundances: abundances[nuclide] /= sum_abundances # Enrich the mixture # The procedure is more generic that it needs to be. It allows - # to enrich mixtures of more then 2 isotopes, keeping the rations + # to enrich mixtures of more then 2 isotopes, keeping the ratios # of non-enriched nuclides the same as in natural composition # Get fraction of non-enriched isotopes in nat. composition @@ -300,12 +292,12 @@ class Element(str): # Convert back to atomic fractions if requested if enrichment_type == 'wo': # Convert the mass fractions to mole fractions - for nuclide in abundances.keys(): + for nuclide in abundances: abundances[nuclide] /= atomic_mass(nuclide) # Normalize the mole fractions to one sum_abundances = sum(abundances.values()) - for nuclide in abundances.keys(): + for nuclide in abundances: abundances[nuclide] /= sum_abundances # Compute the ratio of the nuclide atomic masses to the element diff --git a/openmc/material.py b/openmc/material.py index aea6a10376..e9ef21db06 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -518,10 +518,8 @@ class Material(IDManagerMixin): in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). - Value must be in <0;100> for general nuclide - Value must be in <0;100./1.008) for Uranium enrichment_target: str, optional - Single nuclide name to enrich from a natural composition e.g. O16 + Single nuclide name to enrich from a natural composition (e.g., 'O16') enrichment_type: {'ao', 'wo'}, optional 'ao' for enrichment as atom percent and 'wo' for weight percent. Default is 'ao' diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index 5a17f1f221..ebbdab24e8 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -1,5 +1,5 @@ -import openmc.element -import pytest as pt +import openmc +from pytest import approx, raises from openmc.data import NATURAL_ABUNDANCE, atomic_mass @@ -9,76 +9,76 @@ TOL = 1e-9 def test_expand_no_enrichment(): """ Expand Li in natural compositions""" - lithium = openmc.element.Element('Li') + lithium = openmc.Element('Li') # Verify the expansion into ATOMIC fraction against natural composition for isotope in lithium.expand(100.0, 'ao'): - assert isotope[1] == pt.approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0, rel=TOL) + assert isotope[1] == approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0, rel=TOL) # Verify the expansion into WEIGHT fraction against natural composition natural = {'Li6': NATURAL_ABUNDANCE['Li6'] * atomic_mass('Li6'), 'Li7': NATURAL_ABUNDANCE['Li7'] * atomic_mass('Li7')} li_am = sum(natural.values()) - for key in natural.keys(): + for key in natural: natural[key] /= li_am for isotope in lithium.expand(100.0, 'wo'): - assert isotope[1] == pt.approx(natural[isotope[0]] * 100.0, rel=TOL) + assert isotope[1] == approx(natural[isotope[0]] * 100.0, rel=TOL) def test_expand_enrichment(): """ Expand and verify enrichment of Li """ - lithium = openmc.element.Element('Li') + lithium = openmc.Element('Li') # Verify the enrichment by atoms ref = {'Li6': 75.0, 'Li7': 25.0} for isotope in lithium.expand(100.0, 'ao', 25.0, 'Li7', 'ao'): - assert isotope[1] == pt.approx(ref[isotope[0]], rel=TOL) + assert isotope[1] == approx(ref[isotope[0]], rel=TOL) # Verify the enrichment by weight for isotope in lithium.expand(100.0, 'wo', 25.0, 'Li7', 'wo'): - assert isotope[1] == pt.approx(ref[isotope[0]], rel=TOL) + assert isotope[1] == approx(ref[isotope[0]], rel=TOL) def test_expand_exceptions(): """ Test that correct exceptions are raised for invalid input """ # 1 Isotope Element - with pt.raises(ValueError): - element = openmc.element.Element('Be') - fail = element.expand(70.0, 'ao', 4.0, 'Be9') + with raises(ValueError): + element = openmc.Element('Be') + element.expand(70.0, 'ao', 4.0, 'Be9') # 3 Isotope Element - with pt.raises(ValueError): - element = openmc.element.Element('Cr') - fail = element.expand(70.0, 'ao', 4.0, 'Cr52') + with raises(ValueError): + element = openmc.Element('Cr') + element.expand(70.0, 'ao', 4.0, 'Cr52') # Non-present Enrichment Target - with pt.raises(ValueError): - element = openmc.element.Element('H') - fail = element.expand(70.0, 'ao', 4.0, 'H4') + with raises(ValueError): + element = openmc.Element('H') + element.expand(70.0, 'ao', 4.0, 'H4') # Enrichment Procedure for Uranium if not Uranium - with pt.raises(ValueError): - element = openmc.element.Element('Li') - fail = element.expand(70.0, 'ao', 4.0) + with raises(ValueError): + element = openmc.Element('Li') + element.expand(70.0, 'ao', 4.0) # Missing Enrichment Target - with pt.raises(ValueError): - element = openmc.element.Element('Li') - fail = element.expand(70.0, 'ao', 4.0, enrichment_type='ao') + with raises(ValueError): + element = openmc.Element('Li') + element.expand(70.0, 'ao', 4.0, enrichment_type='ao') # Invalid Enrichment Type Entry - with pt.raises(ValueError): - element = openmc.element.Element('Li') - fail = element.expand(70.0, 'ao', 4.0, 'Li7', 'Grand Moff Tarkin') + with raises(ValueError): + element = openmc.Element('Li') + element.expand(70.0, 'ao', 4.0, 'Li7', 'Grand Moff Tarkin') # Trying to enrich Uranium - with pt.raises(ValueError): - element = openmc.element.Element('U') - fail = element.expand(70.0, 'ao', 4.0, 'U235', 'wo') + with raises(ValueError): + element = openmc.Element('U') + element.expand(70.0, 'ao', 4.0, 'U235', 'wo') # Trying to enrich Uranium with wrong enrichment_target - with pt.raises(ValueError): - element = openmc.element.Element('U') - fail = element.expand(70.0, 'ao', 4.0, enrichment_type='ao') + with raises(ValueError): + element = openmc.Element('U') + element.expand(70.0, 'ao', 4.0, enrichment_type='ao') From adcb9347a7b43882d9b3db282503d3093a40d478 Mon Sep 17 00:00:00 2001 From: Mikolaj Adam Kowalski Date: Wed, 4 Mar 2020 11:58:46 +0000 Subject: [PATCH 11/11] Address comments by @paulromano Use default rel_tol in pytest.approx in test_element.py Add info that default enrichment for U is in wo% --- openmc/element.py | 4 ++-- openmc/material.py | 2 +- tests/unit_tests/test_element.py | 11 ++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/openmc/element.py b/openmc/element.py index 94b6ae8d6d..3df2ff1f24 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -62,7 +62,7 @@ class Element(str): Single nuclide name to enrich from a natural composition (e.g., 'O16') enrichment_type: {'ao', 'wo'}, optional 'ao' for enrichment as atom percent and 'wo' for weight percent. - Default is 'ao' + Default is: 'ao' for two-isotope enrichment; 'wo' for U enrichment cross_sections : str, optional Location of cross_sections.xml file. Default is None. @@ -103,7 +103,7 @@ class Element(str): When the `enrichment` argument is specified with `enrichment_target`, a general enrichment procedure is used for elements composed of exactly two naturally-occurring isotopes. `enrichment` is interpreted as atom - percent by default but can be controlled by the `enrichment_type` + percent by default but can be controlled by the `enrichment_type` argument. """ diff --git a/openmc/material.py b/openmc/material.py index e9ef21db06..fd9f92113c 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -522,7 +522,7 @@ class Material(IDManagerMixin): Single nuclide name to enrich from a natural composition (e.g., 'O16') enrichment_type: {'ao', 'wo'}, optional 'ao' for enrichment as atom percent and 'wo' for weight percent. - Default is 'ao' + Default is: 'ao' for two-isotope enrichment; 'wo' for U enrichment Notes ----- diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index ebbdab24e8..bacb988b9a 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -3,9 +3,6 @@ from pytest import approx, raises from openmc.data import NATURAL_ABUNDANCE, atomic_mass -# Relative tolerance for float comparison -TOL = 1e-9 - def test_expand_no_enrichment(): """ Expand Li in natural compositions""" @@ -13,7 +10,7 @@ def test_expand_no_enrichment(): # Verify the expansion into ATOMIC fraction against natural composition for isotope in lithium.expand(100.0, 'ao'): - assert isotope[1] == approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0, rel=TOL) + assert isotope[1] == approx(NATURAL_ABUNDANCE[isotope[0]] * 100.0) # Verify the expansion into WEIGHT fraction against natural composition natural = {'Li6': NATURAL_ABUNDANCE['Li6'] * atomic_mass('Li6'), @@ -23,7 +20,7 @@ def test_expand_no_enrichment(): natural[key] /= li_am for isotope in lithium.expand(100.0, 'wo'): - assert isotope[1] == approx(natural[isotope[0]] * 100.0, rel=TOL) + assert isotope[1] == approx(natural[isotope[0]] * 100.0) def test_expand_enrichment(): @@ -33,11 +30,11 @@ def test_expand_enrichment(): # Verify the enrichment by atoms ref = {'Li6': 75.0, 'Li7': 25.0} for isotope in lithium.expand(100.0, 'ao', 25.0, 'Li7', 'ao'): - assert isotope[1] == approx(ref[isotope[0]], rel=TOL) + assert isotope[1] == approx(ref[isotope[0]]) # Verify the enrichment by weight for isotope in lithium.expand(100.0, 'wo', 25.0, 'Li7', 'wo'): - assert isotope[1] == approx(ref[isotope[0]], rel=TOL) + assert isotope[1] == approx(ref[isotope[0]]) def test_expand_exceptions():