From 80bf6c752839c083482d99975fb18cb2f5a2c0e9 Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Wed, 9 Nov 2016 22:20:29 -0500 Subject: [PATCH 1/7] add get_molar_mass() method to material and fixed two other issues --- examples/python/pincell/build-xml.py | 2 +- openmc/data/data.py | 23 +++++++++++++++++++++++ openmc/element.py | 2 +- openmc/material.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index 979614d635..2a550b9d73 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -51,7 +51,7 @@ o = openmc.Element('O') # Instantiate some Materials and register the appropriate Nuclides uo2 = openmc.Material(material_id=1, name='UO2 fuel at 2.4% wt enrichment') uo2.set_density('g/cm3', 10.29769) -uo2.add_element(u, 1., enrichment=0.024) +uo2.add_element(u, 1., enrichment=2.4) uo2.add_element(o, 2.) helium = openmc.Material(material_id=2, name='Helium for gap') diff --git a/openmc/data/data.py b/openmc/data/data.py index 1f759d3d4d..5dee5aca73 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -1,5 +1,6 @@ import itertools import os +import re # Isotopic abundances from M. Berglund and M. E. Wieser, "Isotopic compositions @@ -149,6 +150,28 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: + + # If the isotope represents all natural isotopes of the element + # (e.g. C0), set atomic mass manually using the values from Atomic + # weights of the elements 2013 (IUPAC Technical Report) + # (doi:10.1515/pac-2015-0305). In cases where an atomic mass range is + # given (e.g. C), the average value is used. + if int(re.split(r"(\d+)", isotope)[1]) == 0: + if re.split(r"(\d+)", isotope)[0] == 'C': + _ATOMIC_MASS[isotope.lower()] = 12.0106 + elif re.split(r"(\d+)", isotope)[0] == 'Zn': + _ATOMIC_MASS[isotope.lower()] = 65.38 + elif re.split(r"(\d+)", isotope)[0] == 'Pt': + _ATOMIC_MASS[isotope.lower()] = 195.084 + elif re.split(r"(\d+)", isotope)[0] == 'Os': + _ATOMIC_MASS[isotope.lower()] = 190.23 + elif re.split(r"(\d+)", isotope)[0] == 'Tl': + _ATOMIC_MASS[isotope.lower()] = 204.3835 + else: + msg = 'Could not get the atomic mass for zero isotope'\ + ' {0}.'.format(isotope) + raise ValueError(msg) + # Load data from AME2012 file mass_file = os.path.join(os.path.dirname(__file__), 'mass.mas12') with open(mass_file, 'r') as ame: diff --git a/openmc/element.py b/openmc/element.py index d56c3b3507..ce0b5e4386 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -233,7 +233,7 @@ class Element(object): # Compute the ratio of the nuclide atomic masses to the element # atomic mass - if percent_type == 'wo': + if percent_type == 'wo' and len(abundances) > 1: # Compute the element atomic mass element_am = 0. diff --git a/openmc/material.py b/openmc/material.py index c265c90694..abd5467b81 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -4,6 +4,7 @@ from numbers import Real, Integral import warnings from xml.etree import ElementTree as ET import sys +import re from six import string_types @@ -581,6 +582,33 @@ class Material(object): return nuclides + def get_molar_mass(self): + """Returns the molar mass of the material + + Returns + ------- + molar_mass : float + The molar mass of the material + + """ + + # Get a list of all the nuclides, with elements expanded + nuclide_densities = self.get_nuclide_densities() + + # Using the sum of specified atomic or weight amounts as a basis, sum + # the mass and moles of the material + mass = 0. + moles = 0. + for nuc,vals in nuclide_densities.items(): + if vals[2] == 'ao': + mass += vals[1] * openmc.data.atomic_mass(nuc) + moles += vals[1] + else: + moles += vals[1] / openmc.data.atomic_mass(nuc) + mass += vals[1] + + return (mass / moles) + def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") xml_element.set("name", nuclide[0].name) From 9e9e401aaad77bad96630b5cfd8a06c4607cb332 Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Wed, 9 Nov 2016 22:23:59 -0500 Subject: [PATCH 2/7] removed import of re in material.py --- openmc/material.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index abd5467b81..8003cc1929 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -4,7 +4,6 @@ from numbers import Real, Integral import warnings from xml.etree import ElementTree as ET import sys -import re from six import string_types @@ -607,7 +606,9 @@ class Material(object): moles += vals[1] / openmc.data.atomic_mass(nuc) mass += vals[1] - return (mass / moles) + # Compute and return the molar mass + molar_mass = mass / moles + return molar_mass def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") From e16b0388253b5507a93fe5675127357ce338672f Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Wed, 9 Nov 2016 22:29:22 -0500 Subject: [PATCH 3/7] removed modification to element.expand() --- openmc/element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/element.py b/openmc/element.py index ce0b5e4386..d56c3b3507 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -233,7 +233,7 @@ class Element(object): # Compute the ratio of the nuclide atomic masses to the element # atomic mass - if percent_type == 'wo' and len(abundances) > 1: + if percent_type == 'wo': # Compute the element atomic mass element_am = 0. From 2208800981ec4a5e74026e400726ffaa9bfc7a33 Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Wed, 9 Nov 2016 23:00:08 -0500 Subject: [PATCH 4/7] modified data.py to set the atomic masses for all zero isotopes --- openmc/data/data.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/openmc/data/data.py b/openmc/data/data.py index 5dee5aca73..2d1e471d26 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -1,6 +1,5 @@ import itertools import os -import re # Isotopic abundances from M. Berglund and M. E. Wieser, "Isotopic compositions @@ -151,26 +150,16 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: - # If the isotope represents all natural isotopes of the element + # For the isotope represented by all natural isotopes of the element # (e.g. C0), set atomic mass manually using the values from Atomic # weights of the elements 2013 (IUPAC Technical Report) # (doi:10.1515/pac-2015-0305). In cases where an atomic mass range is # given (e.g. C), the average value is used. - if int(re.split(r"(\d+)", isotope)[1]) == 0: - if re.split(r"(\d+)", isotope)[0] == 'C': - _ATOMIC_MASS[isotope.lower()] = 12.0106 - elif re.split(r"(\d+)", isotope)[0] == 'Zn': - _ATOMIC_MASS[isotope.lower()] = 65.38 - elif re.split(r"(\d+)", isotope)[0] == 'Pt': - _ATOMIC_MASS[isotope.lower()] = 195.084 - elif re.split(r"(\d+)", isotope)[0] == 'Os': - _ATOMIC_MASS[isotope.lower()] = 190.23 - elif re.split(r"(\d+)", isotope)[0] == 'Tl': - _ATOMIC_MASS[isotope.lower()] = 204.3835 - else: - msg = 'Could not get the atomic mass for zero isotope'\ - ' {0}.'.format(isotope) - raise ValueError(msg) + _ATOMIC_MASS['c0'] = 12.0106 + _ATOMIC_MASS['zn0'] = 65.38 + _ATOMIC_MASS['pt0'] = 195.084 + _ATOMIC_MASS['os0'] = 190.23 + _ATOMIC_MASS['tl0'] = 204.3835 # Load data from AME2012 file mass_file = os.path.join(os.path.dirname(__file__), 'mass.mas12') From e375620e78627728b0d27094a83b3d9d7d1019b0 Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Wed, 9 Nov 2016 23:02:22 -0500 Subject: [PATCH 5/7] fixed typo in data.py --- openmc/data/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/data/data.py b/openmc/data/data.py index 2d1e471d26..e3a6d53601 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -150,7 +150,7 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: - # For the isotope represented by all natural isotopes of the element + # For the isotopes representing all natural isotopes of their element # (e.g. C0), set atomic mass manually using the values from Atomic # weights of the elements 2013 (IUPAC Technical Report) # (doi:10.1515/pac-2015-0305). In cases where an atomic mass range is From 8394970acb28f2bbfd81795ea8cad5d989931680 Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Thu, 10 Nov 2016 15:42:22 -0500 Subject: [PATCH 6/7] addressed PR comments --- openmc/data/data.py | 24 ++++++++++--------- openmc/material.py | 56 ++++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/openmc/data/data.py b/openmc/data/data.py index e3a6d53601..a3e7158126 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -1,5 +1,6 @@ import itertools import os +import re # Isotopic abundances from M. Berglund and M. E. Wieser, "Isotopic compositions @@ -150,17 +151,6 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: - # For the isotopes representing all natural isotopes of their element - # (e.g. C0), set atomic mass manually using the values from Atomic - # weights of the elements 2013 (IUPAC Technical Report) - # (doi:10.1515/pac-2015-0305). In cases where an atomic mass range is - # given (e.g. C), the average value is used. - _ATOMIC_MASS['c0'] = 12.0106 - _ATOMIC_MASS['zn0'] = 65.38 - _ATOMIC_MASS['pt0'] = 195.084 - _ATOMIC_MASS['os0'] = 190.23 - _ATOMIC_MASS['tl0'] = 204.3835 - # Load data from AME2012 file mass_file = os.path.join(os.path.dirname(__file__), 'mass.mas12') with open(mass_file, 'r') as ame: @@ -171,6 +161,18 @@ def atomic_mass(isotope): line[100:106] + '.' + line[107:112]) _ATOMIC_MASS[name.lower()] = mass + # For isotopes found in some libraries that represent all natural + # isotopes of their element (e.g. C0), calculate the atomic mass as + # the sum of the atomic mass times the natural abudance of the isotopes + # that make up the element. + for element in ['C', 'Zn', 'Pt', 'Os', 'Tl']: + isotope_zero = element.lower() + '0' + _ATOMIC_MASS[isotope_zero] = 0. + for iso, abundance in NATURAL_ABUNDANCE.items(): + if re.match(r'{}\d+'.format(element), iso): + _ATOMIC_MASS[isotope_zero] += abundance * \ + _ATOMIC_MASS[iso.lower()] + # Get rid of metastable information if '_' in isotope: isotope = isotope[:isotope.find('_')] diff --git a/openmc/material.py b/openmc/material.py index 8003cc1929..4b382c5e34 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -64,6 +64,12 @@ class Material(object): List in which each item is a 3-tuple consisting of an :class:`openmc.Nuclide` instance, the percent density, and the percent type ('ao' or 'wo'). + molar_mass : float + The molar mass of the material computed in units of grams per mole of + nuclides in a material. This entails that the molar mass does not depend + on the magnitude of the sum of atomic amounts of elements and nuclides + in the material. For instance, the molar mass of UO2 would be + ~90 g/mol. """ @@ -194,6 +200,27 @@ class Material(object): def distrib_otf_file(self): return self._distrib_otf_file + @property + def molar_mass(self): + + # Get a list of all the nuclides, with elements expanded + nuclide_densities = self.get_nuclide_densities() + + # Using the sum of specified atomic or weight amounts as a basis, sum + # the mass and moles of the material + mass = 0. + moles = 0. + for nuc, vals in nuclide_densities.items(): + if vals[2] == 'ao': + mass += vals[1] * openmc.data.atomic_mass(nuc) + moles += vals[1] + else: + moles += vals[1] / openmc.data.atomic_mass(nuc) + mass += vals[1] + + # Compute and return the molar mass + return mass / moles + @id.setter def id(self, material_id): @@ -581,35 +608,6 @@ class Material(object): return nuclides - def get_molar_mass(self): - """Returns the molar mass of the material - - Returns - ------- - molar_mass : float - The molar mass of the material - - """ - - # Get a list of all the nuclides, with elements expanded - nuclide_densities = self.get_nuclide_densities() - - # Using the sum of specified atomic or weight amounts as a basis, sum - # the mass and moles of the material - mass = 0. - moles = 0. - for nuc,vals in nuclide_densities.items(): - if vals[2] == 'ao': - mass += vals[1] * openmc.data.atomic_mass(nuc) - moles += vals[1] - else: - moles += vals[1] / openmc.data.atomic_mass(nuc) - mass += vals[1] - - # Compute and return the molar mass - molar_mass = mass / moles - return molar_mass - def _get_nuclide_xml(self, nuclide, distrib=False): xml_element = ET.Element("nuclide") xml_element.set("name", nuclide[0].name) From 4dd663dd781560802f8e4374a2ddf769a71894db Mon Sep 17 00:00:00 2001 From: Sam Shaner Date: Thu, 10 Nov 2016 17:19:39 -0500 Subject: [PATCH 7/7] changed molar_mass to average_molar_mass --- openmc/material.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 4b382c5e34..70a070ddd6 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -64,12 +64,10 @@ class Material(object): List in which each item is a 3-tuple consisting of an :class:`openmc.Nuclide` instance, the percent density, and the percent type ('ao' or 'wo'). - molar_mass : float - The molar mass of the material computed in units of grams per mole of - nuclides in a material. This entails that the molar mass does not depend - on the magnitude of the sum of atomic amounts of elements and nuclides - in the material. For instance, the molar mass of UO2 would be - ~90 g/mol. + average_molar_mass : float + The average molar mass of nuclides in the material in units of grams per + mol. For example, UO2 with 3 nuclides will have an average molar mass + of 270 / 3 = 90 g / mol. """ @@ -201,7 +199,7 @@ class Material(object): return self._distrib_otf_file @property - def molar_mass(self): + def average_molar_mass(self): # Get a list of all the nuclides, with elements expanded nuclide_densities = self.get_nuclide_densities()