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)