Merge pull request #741 from samuelshaner/element-wo

Natural element expansion for wo and uranium enrichment option
This commit is contained in:
Paul Romano 2016-10-31 11:50:31 -05:00 committed by GitHub
commit 244da85bb8
32 changed files with 700 additions and 1561 deletions

File diff suppressed because one or more lines are too long

View file

@ -105,19 +105,6 @@ standard deviation.
*Default*: false
.. _cross_sections:
``<cross_sections>`` Element
----------------------------
The ``<cross_sections>`` element has no attributes and simply indicates the path
to an XML cross section listing file (usually named cross_sections.xml). If this
element is absent from the settings.xml file, the
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used to find the
path to the XML cross section listing when in continuous-energy mode, and the
:envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable will be used in
multi-group mode.
``<cutoff>`` Element
--------------------
@ -289,20 +276,6 @@ based on the recommended value in LA-UR-14-24530_.
.. note:: This element is not used in the multi-group :ref:`energy_mode`.
.. _multipole_library:
``<multipole_library>`` Element
-------------------------------
The ``<multipole_library>`` element indicates the directory containing a
windowed multipole library. If a windowed multipole library is available,
OpenMC can use it for on-the-fly Doppler-broadening of resolved resonance range
cross sections. If this element is absent from the settings.xml file, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used.
.. note:: The <temperature_multipole> element must also be set to "true" for
windowed multipole functionality.
``<max_order>`` Element
---------------------------
@ -316,29 +289,6 @@ then, OpenMC will only use up to the :math:`P_1` data.
.. note:: This element is not used in the continuous-energy
:ref:`energy_mode`.
.. _natural_elements:
``<natural_elements>`` Element
------------------------------
The ``<natural_elements>`` element indicates to OpenMC what nuclides are
available in the cross section library when expanding an ``<element>`` into
separate isotopes (see :ref:`material`). The accepted values are:
- ENDF/B-VII.0
- ENDF/B-VII.1
- JEFF-3.1.1
- JEFF-3.1.2
- JEFF-3.2
- JENDL-3.2
- JENDL-3.3
- JENDL-4.0
Note that the value is case-insensitive, so "ENDF/B-VII.1" is equivalent to
"endf/b-vii.1".
*Default*: ENDF/B-VII.1
``<no_reduce>`` Element
-----------------------
@ -1368,6 +1318,33 @@ Here is an example of a properly defined 2d hexagonal lattice:
Materials Specification -- materials.xml
----------------------------------------
.. _cross_sections:
``<cross_sections>`` Element
----------------------------
The ``<cross_sections>`` element has no attributes and simply indicates the path
to an XML cross section listing file (usually named cross_sections.xml). If this
element is absent from the settings.xml file, the
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used to find the
path to the XML cross section listing when in continuous-energy mode, and the
:envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable will be used in
multi-group mode.
.. _multipole_library:
``<multipole_library>`` Element
-------------------------------
The ``<multipole_library>`` element indicates the directory containing a
windowed multipole library. If a windowed multipole library is available,
OpenMC can use it for on-the-fly Doppler-broadening of resolved resonance range
cross sections. If this element is absent from the settings.xml file, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used.
.. note:: The <temperature_multipole> element must also be set to "true" for
windowed multipole functionality.
.. _material:
``<material>`` Element
@ -1440,43 +1417,6 @@ Each ``material`` element can have the following attributes or sub-elements:
.. note:: The ``scattering`` attribute/sub-element is not used in the
multi-group :ref:`energy_mode`.
:element:
Specifies that a natural element is present in the material. The natural
element is split up into individual isotopes based on `IUPAC Isotopic
Compositions of the Elements 2009`_. This element has
attributes/sub-elements called ``name``, and ``ao``. The ``name``
attribute is the atomic symbol of the element. Finally, the ``ao``
attribute specifies the atom percent of the element within the material,
respectively. One example would be as follows:
.. code-block:: xml
<element name="Al" ao="8.7115e-03" />
<element name="Mg" ao="1.5498e-04" />
<element name="Mn" ao="2.7426e-05" />
<element name="Cu" ao="1.6993e-04" />
In some cross section libraries, certain naturally occurring isotopes do not
have cross sections. The :ref:`natural_elements` option determines how a
natural element is split into isotopes in these cases.
*Default*: None
An optional attribute/sub-element for each element is ``scattering``. This
attribute may be set to "data" to use the scattering laws specified by the
cross section library (default). Alternatively, when set to "iso-in-lab",
the scattering laws are used to sample the outgoing energy but an
isotropic-in-lab distribution is used to sample the outgoing angle at each
scattering interaction. The ``scattering`` attribute may be most useful
when using OpenMC to compute multi-group cross-sections for deterministic
transport codes and to quantify the effects of anisotropic scattering.
*Default*: None
.. note:: The ``scattering`` attribute/sub-element is not used in the
multi-group :ref:`energy_mode`.
:sab:
Associates an S(a,b) table with the material. This element has one
attribute/sub-element called ``name``. The ``name`` attribute
@ -1503,9 +1443,6 @@ Each ``material`` element can have the following attributes or sub-elements:
*Default*: None
.. _IUPAC Isotopic Compositions of the Elements 2009:
http://pac.iupac.org/publications/pac/pdf/2011/pdf/8302x0397.pdf
------------------------------------
Tallies Specification -- tallies.xml
------------------------------------

View file

@ -45,18 +45,14 @@ sn119 = openmc.Nuclide('Sn119')
sn120 = openmc.Nuclide('Sn120')
sn122 = openmc.Nuclide('Sn122')
sn124 = openmc.Nuclide('Sn124')
u234 = openmc.Nuclide('U234')
u235 = openmc.Nuclide('U235')
u238 = openmc.Nuclide('U238')
u = openmc.Element('U')
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_nuclide(u234, 4.4843e-6)
uo2.add_nuclide(u235, 5.5815e-4)
uo2.add_nuclide(u238, 2.2408e-2)
uo2.add_nuclide(o16, 4.5829e-2)
uo2.add_nuclide(o17, 1.1164e-4)
uo2.add_element(u, 1., enrichment=0.024)
uo2.add_element(o, 2.)
helium = openmc.Material(material_id=2, name='Helium for gap')
helium.set_density('g/cm3', 0.001598)

View file

@ -83,6 +83,7 @@ water.add_macroscopic(h2o_data)
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, water])
materials_file.cross_sections = "./mgxs.h5"
materials_file.export_to_xml()
@ -132,7 +133,6 @@ geometry.export_to_xml()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.energy_mode = "multi-group"
settings_file.cross_sections = "./mgxs.h5"
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles

View file

@ -1,5 +1,8 @@
<?xml version="1.0"?>
<materials>
<cross_sections>./mgxs.h5</cross_sections>
<!-- UO2 -->
<material id="1">
<density units="macro" value="1.0" />

View file

@ -34,6 +34,4 @@
<survival_biasing>false</survival_biasing>
<cross_sections>./mgxs.h5</cross_sections>
</settings>

View file

@ -1,17 +1,21 @@
from collections import OrderedDict
import re
import sys
import os
from six import string_types
from xml.etree import ElementTree as ET
import openmc
from openmc.checkvalue import check_type, check_length
from openmc.data import NATURAL_ABUNDANCE
from openmc.data import NATURAL_ABUNDANCE, atomic_mass
class Element(object):
"""A natural element used in a material via <element>. Internally, OpenMC will
expand the natural element into isotopes based on the known natural
abundances.
"""A natural element that auto-expands to add the isotopes of an element to
a material in their natural abundance. Internally, the OpenMC Python API
expands the natural element into isotopes only when the materials.xml file
is created.
Parameters
----------
@ -83,16 +87,37 @@ class Element(object):
@scattering.setter
def scattering(self, scattering):
if not scattering in ['data', 'iso-in-lab']:
msg = 'Unable to set scattering for Element to {0} ' \
'which is not "data" or "iso-in-lab"'.format(scattering)
if not scattering in ['data', 'iso-in-lab', None]:
msg = 'Unable to set scattering for Element to {0} which ' \
'is not "data", "iso-in-lab", or None'.format(scattering)
raise ValueError(msg)
self._scattering = scattering
def expand(self):
def expand(self, percent, percent_type, enrichment=None,
cross_sections=None):
"""Expand natural element into its naturally-occurring isotopes.
An optional cross_sections argument or the OPENMC_CROSS_SECTIONS
environment variable is used to specify a cross_sections.xml file.
If the cross_sections.xml file is found, the element is expanded only
into the isotopes/nuclides present in cross_sections.xml. If no
cross_sections.xml file is found, the element is expanded based on its
naturally occurring isotopes.
Parameters
----------
percent : float
Atom or weight percent
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).
cross_sections : str, optional
Location of cross_sections.xml file. Default is None.
Returns
-------
isotopes : list
@ -102,9 +127,133 @@ class Element(object):
"""
# Get the nuclides present in nature
natural_nuclides = set()
for nuclide in sorted(NATURAL_ABUNDANCE.keys()):
if re.match(r'{}\d+'.format(self.name), nuclide):
natural_nuclides.add(nuclide)
# Create dict to store the expanded nuclides and abundances
abundances = OrderedDict()
# If cross_sections is None, get the cross sections from the
# OPENMC_CROSS_SECTIONS environment variable
if cross_sections is None:
cross_sections = os.environ.get('OPENMC_CROSS_SECTIONS')
# If a cross_sections library is present, check natural nuclides
# against the nuclides in the library
if cross_sections is not None:
library_nuclides = set()
tree = ET.parse(cross_sections)
root = tree.getroot()
for child in root:
nuclide = child.attrib['materials']
if re.match(r'{}\d+'.format(self.name), nuclide) and \
'_m' not in nuclide:
library_nuclides.add(nuclide)
# Get a set of the mutual and absent nuclides. Convert to lists
# and sort to avoid different ordering between Python 2 and 3.
mutual_nuclides = natural_nuclides.intersection(library_nuclides)
absent_nuclides = natural_nuclides.difference(mutual_nuclides)
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 len(absent_nuclides) == 0:
for nuclide in mutual_nuclides:
abundances[nuclide] = NATURAL_ABUNDANCE[nuclide]
# If no natural elements are present in the library, check if the
# 0 nuclide is present. If so, set the abundance to 1 for this
# nuclide. Else, raise an error.
elif len(mutual_nuclides) == 0:
nuclide_0 = self.name + '0'
if nuclide_0 in library_nuclides:
abundances[nuclide_0] = 1.0
else:
msg = 'Unable to expand element {0} because the cross '\
'section library provided does not contain any of '\
'the natural isotopes for that element.'\
.format(self.name)
raise ValueError(msg)
# If some, but not all, natural nuclides are in the library, add
# the mutual nuclides. For the absent nuclides, add them based on
# our knowledge of the common cross section libraries
# (ENDF, JEFF, and JENDL)
else:
# Add the mutual isotopes
for nuclide in mutual_nuclides:
abundances[nuclide] = NATURAL_ABUNDANCE[nuclide]
# Adjust the abundances for the absent nuclides
for nuclide in absent_nuclides:
if nuclide in ['O17', 'O18'] and 'O16' in mutual_nuclides:
abundances['O16'] += NATURAL_ABUNDANCE[nuclide]
elif nuclide == 'Ta180' and 'Ta181' in mutual_nuclides:
abundances['Ta181'] += NATURAL_ABUNDANCE[nuclide]
elif nuclide == 'W180' and 'W182' in mutual_nuclides:
abundances['W182'] += NATURAL_ABUNDANCE[nuclide]
else:
msg = 'Unsure how to partition natural abundance of ' \
'isotope {0} into other natural isotopes of ' \
'this element that are present in the cross ' \
'section library provided. Consider adding ' \
'the isotopes of this element individually.'
raise ValueError(msg)
# If a cross_section library is not present, expand the element into
# its natural nuclides
else:
for nuclide in natural_nuclides:
abundances[nuclide] = NATURAL_ABUNDNACE[nuclide]
# Modify mole fractions if enrichment provided
if enrichment is not None:
# Calculate the mass fractions of isotopes
abundances['U234'] = 0.008 * enrichment
abundances['U235'] = enrichment
abundances['U238'] = 100.0 - 1.008 * enrichment
# 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
if percent_type == 'wo':
# Compute the element atomic mass
element_am = 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
# Create a list of the isotopes in this element
isotopes = []
for isotope, abundance in sorted(NATURAL_ABUNDANCE.items()):
if re.match(r'{}\d+'.format(self.name), isotope):
nuc = openmc.Nuclide(isotope)
isotopes.append((nuc, abundance))
for nuclide, abundance in abundances.items():
nuc = openmc.Nuclide(nuclide)
nuc.scattering = self.scattering
isotopes.append((nuc, percent*abundance, percent_type))
return isotopes

View file

@ -57,9 +57,9 @@ class Material(object):
'atom/b-cm', 'atom/cm3', 'sum', or 'macro'. The 'macro' unit only
applies in the case of a multi-group calculation.
elements : list of tuple
List in which each item is a 3-tuple consisting of an
:class:`openmc.Element` instance, the percent density, and the percent
type ('ao' or 'wo').
List in which each item is a 4-tuple consisting of an
:class:`openmc.Element` instance, the percent density, the percent
type ('ao' or 'wo'), and enrichment.
nuclides : list of tuple
List in which each item is a 3-tuple consisting of an
:class:`openmc.Nuclide` instance, the percent density, and the percent
@ -82,7 +82,7 @@ class Material(object):
# (only one is allowed, hence this is different than _nuclides, etc)
self._macroscopic = None
# A list of tuples (element, percent, percent type)
# A list of tuples (element, percent, percent type, enrichment)
self._elements = []
# If specified, a list of table names
@ -148,9 +148,13 @@ class Material(object):
string += '{0: <16}\n'.format('\tElements')
for element, percent, percent_type in self._elements:
for element, percent, percent_type, enr in self._elements:
string += '{0: <16}'.format('\t{0.name}'.format(element))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
if enr is None:
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
else:
string += '=\t{0: <12} [{1}] @ {2} w/o enrichment\n'\
.format(percent, percent_type, enr)
return string
@ -401,7 +405,7 @@ class Material(object):
if macroscopic.name == self._macroscopic.name:
self._macroscopic = None
def add_element(self, element, percent, percent_type='ao', expand=False):
def add_element(self, element, percent, percent_type='ao', enrichment=None):
"""Add a natural element to the material
Parameters
@ -413,9 +417,10 @@ class Material(object):
percent_type : {'ao', 'wo'}, optional
'ao' for atom percent and 'wo' for weight percent. Defaults to atom
percent.
expand : bool, optional
Whether to expand the natural element into its naturally-occurring
isotopes. Defaults to False.
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).
"""
@ -445,14 +450,33 @@ class Material(object):
else:
element = openmc.Element(element)
if expand:
if percent_type == 'wo':
raise NotImplementedError('Expanding natural element based on '
'weight percent is not yet supported.')
for isotope, abundance in element.expand():
self._nuclides.append((isotope, percent*abundance, percent_type))
else:
self._elements.append((element, percent, percent_type))
if enrichment is not None:
if not isinstance(enrichment, Real):
msg = 'Unable to add an Element to Material ID="{0}" with a ' \
'non-floating point enrichment value "{1}"'\
.format(self._id, enrichment)
raise ValueError(msg)
elif element.name != 'U':
msg = 'Unable to use enrichment for element {0} which is not ' \
'uranium for Material ID="{1}"'.format(element.name,
self._id)
raise ValueError(msg)
# Check that the enrichment is in the valid range
cv.check_less_than('enrichment', enrichment, 100./1.008)
cv.check_greater_than('enrichment', enrichment, 0., equality=True)
if enrichment > 5.0:
msg = 'A uranium enrichment of {0} was given for Material ID='\
'"{1}". OpenMC assumes the U234/U235 mass ratio is '\
'constant at 0.008, which is only valid at low ' \
'enrichments. Consider setting the isotopic ' \
'composition manually for enrichments over 5%.'.\
format(enrichment, self._id)
warnings.warn(msg)
self._elements.append((element, percent, percent_type, enrichment))
def remove_element(self, element):
"""Remove a natural element from the material
@ -469,10 +493,10 @@ class Material(object):
'since it is not an Element'.format(self.id, element)
raise ValueError(msg)
# If the Material contains the Nuclide, delete it
# If the Material contains the Element, delete it
for elm in self._elements:
if element == elm:
self._nuclides.remove(elm)
self._elements.remove(elm)
def add_s_alpha_beta(self, name):
r"""Add an :math:`S(\alpha,\beta)` table to the material
@ -502,7 +526,6 @@ class Material(object):
self._sab.append(new_name)
def make_isotropic_in_lab(self):
for nuclide, percent, percent_type in self._nuclides:
nuclide.scattering = 'iso-in-lab'
@ -521,13 +544,15 @@ class Material(object):
nuclides = []
for nuclide, density, density_type in self._nuclides:
for nuclide, percent, percent_type in self._nuclides:
nuclides.append(nuclide.name)
for element, density, density_type in self._elements:
for ele, ele_pct, ele_pct_type, enr in self._elements:
# Expand natural element into isotopes
for isotope, abundance in element.expand():
nuclides.append(isotope.name)
isotopes = ele.expand(ele_pct, ele_pct_type, enr)
for iso, iso_pct, iso_pct_type in isotopes:
nuclides.append(iso.name)
return nuclides
@ -537,8 +562,8 @@ class Material(object):
Returns
-------
nuclides : dict
Dictionary whose keys are nuclide names and values are 2-tuples of
(nuclide, density)
Dictionary whose keys are nuclide names and values are 3-tuples of
(nuclide, density percent, density percent type)
"""
@ -547,10 +572,12 @@ class Material(object):
for nuclide, density, density_type in self._nuclides:
nuclides[nuclide.name] = (nuclide, density)
for element, density, density_type in self._elements:
for ele, ele_pct, ele_pct_type, enr in self._elements:
# Expand natural element into isotopes
for isotope, abundance in element.expand():
nuclides[isotope.name] = (isotope, density*abundance)
isotopes = ele.expand(ele_pct, ele_pct_type, enr)
for iso, iso_pct, iso_pct_type in isotopes:
nuclides[iso.name] = (iso, iso_pct, iso_pct_type)
return nuclides
@ -575,22 +602,20 @@ class Material(object):
return xml_element
def _get_element_xml(self, element, distrib=False):
xml_element = ET.Element("element")
xml_element.set("name", str(element[0].name))
def _get_element_xml(self, element, cross_sections, distrib=False):
if not distrib:
if element[2] == 'ao':
xml_element.set("ao", str(element[1]))
else:
xml_element.set("wo", str(element[1]))
# Get the nuclides in this element
nuclides = element[0].expand(element[1], element[2], element[3],
cross_sections)
if not element[0].scattering is None:
xml_element.set("scattering", element[0].scattering)
xml_elements = []
for nuclide in nuclides:
xml_elements.append(self._get_nuclide_xml(nuclide, distrib))
return xml_element
return xml_elements
def _get_nuclides_xml(self, nuclides, distrib=False):
xml_elements = []
for nuclide in nuclides:
@ -598,15 +623,19 @@ class Material(object):
return xml_elements
def _get_elements_xml(self, elements, distrib=False):
def _get_elements_xml(self, elements, cross_sections, distrib=False):
xml_elements = []
for element in elements:
xml_elements.append(self._get_element_xml(element, distrib))
nuclide_elements = self._get_element_xml(element, cross_sections,
distrib)
for nuclide_element in nuclide_elements:
xml_elements.append(nuclide_element)
return xml_elements
def get_material_xml(self):
def get_material_xml(self, cross_sections):
"""Return XML representation of the material
Returns
@ -642,7 +671,8 @@ class Material(object):
element.append(subelement)
# Create element XML subelements
subelements = self._get_elements_xml(self._elements)
subelements = self._get_elements_xml(self._elements,
cross_sections)
for subelement in subelements:
element.append(subelement)
else:
@ -656,12 +686,12 @@ class Material(object):
comps = []
allnucs = self._nuclides + self._elements
dist_per_type = allnucs[0][2]
for nuc, per, typ in allnucs:
if not typ == dist_per_type:
for nuc in allnucs:
if nuc[2] != dist_per_type:
msg = 'All nuclides and elements in a distributed ' \
'material must have the same type, either ao or wo'
raise ValueError(msg)
comps.append(per)
comps.append(nuc[1])
if self._distrib_otf_file is None:
# Create values and units subelements
@ -676,12 +706,15 @@ class Material(object):
if self._macroscopic is None:
# Create nuclide XML subelements
subelements = self._get_nuclides_xml(self._nuclides, distrib=True)
subelements = self._get_nuclides_xml(self._nuclides,
distrib=True)
for subelement_nuc in subelements:
subelement.append(subelement_nuc)
# Create element XML subelements
subelements = self._get_elements_xml(self._elements, distrib=True)
subelements = self._get_elements_xml(self._elements,
cross_sections,
distrib=True)
for subsubelement in subelements:
subelement.append(subsubelement)
else:
@ -716,15 +749,49 @@ class Materials(cv.CheckedList):
----------
materials : Iterable of openmc.Material
Materials to add to the collection
cross_sections : str
Indicates the path to an XML cross section listing file (usually named
cross_sections.xml). If it is not set, the
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for
continuous-energy calculations and
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
calculations to find the path to the XML cross section file.
multipole_library : str
Indicates the path to a directory containing a windowed multipole
cross section library. If it is not set, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used. A
multipole library is optional.
"""
def __init__(self, materials=None):
super(Materials, self).__init__(Material, 'materials collection')
self._materials_file = ET.Element("materials")
self._cross_sections = None
self._multipole_library = None
if materials is not None:
self += materials
@property
def cross_sections(self):
return self._cross_sections
@property
def multipole_library(self):
return self._multipole_library
@cross_sections.setter
def cross_sections(self, cross_sections):
cv.check_type('cross sections', cross_sections, string_types)
self._cross_sections = cross_sections
@multipole_library.setter
def multipole_library(self, multipole_library):
cv.check_type('cross sections', multipole_library, string_types)
self._multipole_library = multipole_library
def add_material(self, material):
"""Append material to collection
@ -807,9 +874,19 @@ class Materials(cv.CheckedList):
def _create_material_subelements(self):
for material in self:
xml_element = material.get_material_xml()
xml_element = material.get_material_xml(self.cross_sections)
self._materials_file.append(xml_element)
def _create_cross_sections_subelement(self):
if self._cross_sections is not None:
element = ET.SubElement(self._materials_file, "cross_sections")
element.text = str(self._cross_sections)
def _create_multipole_library_subelement(self):
if self._multipole_library is not None:
element = ET.SubElement(self._materials_file, "multipole_library")
element.text = str(self._multipole_library)
def export_to_xml(self, path='materials.xml'):
"""Export material collection to an XML file.
@ -824,6 +901,8 @@ class Materials(cv.CheckedList):
self._materials_file.clear()
self._create_material_subelements()
self._create_cross_sections_subelement()
self._create_multipole_library_subelement()
# Clean the indentation in the file to be user-readable
sort_xml_elements(self._materials_file)

View file

@ -87,9 +87,9 @@ class Nuclide(object):
@scattering.setter
def scattering(self, scattering):
if not scattering in ['data', 'iso-in-lab']:
msg = 'Unable to set scattering for Nuclide to {0} ' \
'which is not "data" or "iso-in-lab"'.format(scattering)
if not scattering in ['data', 'iso-in-lab', None]:
msg = 'Unable to set scattering for Nuclide to {0} which ' \
'is not "data", "iso-in-lab", or None'.format(scattering)
raise ValueError(msg)
self._scattering = scattering

View file

@ -603,12 +603,19 @@ class Settings(object):
@cross_sections.setter
def cross_sections(self, cross_sections):
warnings.warn('Settings.cross_sections has been deprecated and will be '
'removed in a future version. Materials.cross_sections '
'should defined instead.', DeprecationWarning)
cv.check_type('cross sections', cross_sections, string_types)
self._cross_sections = cross_sections
@multipole_library.setter
def multipole_library(self, multipole_library):
cv.check_type('cross sections', multipole_library, string_types)
warnings.warn('Settings.multipole_library has been deprecated and will '
'be removed in a future version. '
'Materials.multipole_library should defined instead.',
DeprecationWarning)
cv.check_type('multipole library', multipole_library, string_types)
self._multipole_library = multipole_library
@ptables.setter
@ -713,6 +720,7 @@ class Settings(object):
@temperature.setter
def temperature(self, temperature):
cv.check_type('temperature settings', temperature, Mapping)
for key, value in temperature.items():
cv.check_value('temperature key', key,

View file

@ -257,17 +257,6 @@ module constants
! Maximum number of partial fission reactions
integer, parameter :: PARTIAL_FISSION_MAX = 4
! Major cross section libraries
integer, parameter :: &
ENDF_BVII0 = 1, &
ENDF_BVII1 = 2, &
JEFF_311 = 3, &
JEFF_312 = 4, &
JEFF_32 = 5, &
JENDL_32 = 6, &
JENDL_33 = 7, &
JENDL_40 = 8
! Temperature treatment method
integer, parameter :: &
TEMPERATURE_NEAREST = 1, &

View file

@ -96,9 +96,6 @@ module global
! Unreoslved resonance probablity tables
logical :: urr_ptables_on = .true.
! What to assume for expanding natural elements
integer :: default_expand = ENDF_BVII1
! Default temperature and method for choosing temperatures
integer :: temperature_method = TEMPERATURE_NEAREST
logical :: temperature_multipole = .false.
@ -320,14 +317,14 @@ module global
logical :: restart_run = .false.
integer :: restart_batch
character(MAX_FILE_LEN) :: path_input ! Path to input file
character(MAX_FILE_LEN) :: path_cross_sections ! Path to cross_sections.xml
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory
character(MAX_FILE_LEN) :: path_input ! Path to input file
character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory
! The verbosity controls how much information will be printed to the
! screen and in logs

File diff suppressed because it is too large Load diff

View file

@ -42,4 +42,8 @@ element materials {
(element name { xsd:string } | attribute name { xsd:string })
}*
}+
element cross_sections { xsd:string { maxLength = "255" } }? &
element multipole_library { xsd:string { maxLength = "255" } }? &
}

View file

@ -25,10 +25,6 @@ element settings {
}
) &
element cross_sections { xsd:string { maxLength = "255" } }? &
element multipole_library { xsd:string { maxLength = "255" } }? &
element cutoff {
(element weight { xsd:double } | attribute weight { xsd:double })? &
(element weight_avg { xsd:double } | attribute weight_avg { xsd:double })?

View file

@ -524,31 +524,22 @@ class PinCellInputSet(object):
# Instantiate ZCylinder surfaces
fuel_or = openmc.ZCylinder(x0=0, y0=0, R=0.39218, name='Fuel OR')
clad_or = openmc.ZCylinder(x0=0, y0=0, R=0.45720, name='Clad OR')
left = openmc.XPlane(x0=-0.63, name='left')
right = openmc.XPlane(x0=0.63, name='right')
bottom = openmc.YPlane(y0=-0.63, name='bottom')
top = openmc.YPlane(y0=0.63, name='top')
left.boundary_type = 'reflective'
right.boundary_type = 'reflective'
top.boundary_type = 'reflective'
bottom.boundary_type = 'reflective'
left = openmc.XPlane(x0=-0.63, name='left', boundary_type='reflective')
right = openmc.XPlane(x0=0.63, name='right', boundary_type='reflective')
bottom = openmc.YPlane(y0=-0.63, name='bottom',
boundary_type='reflective')
top = openmc.YPlane(y0=0.63, name='top', boundary_type='reflective')
# Instantiate Cells
fuel_pin = openmc.Cell(name='cell 1')
cladding = openmc.Cell(name='cell 3')
water = openmc.Cell(name='cell 2')
fuel_pin = openmc.Cell(name='cell 1', fill=fuel)
cladding = openmc.Cell(name='cell 3', fill=clad)
water = openmc.Cell(name='cell 2', fill=hot_water)
# Use surface half-spaces to define regions
fuel_pin.region = -fuel_or
cladding.region = +fuel_or & -clad_or
water.region = +clad_or & +left & -right & +bottom & -top
# Register Materials with Cells
fuel_pin.fill = fuel
cladding.fill = clad
water.fill = hot_water
# Instantiate Universe
root = openmc.Universe(universe_id=0, name='root universe')
@ -757,6 +748,7 @@ class MGInputSet(InputSet):
# Define the materials file
self.xs_data = xs
self.materials += mats
self.materials.cross_sections = "../1d_mgxs.h5"
# Define surfaces.
# Assembly/Problem Boundary
@ -793,7 +785,6 @@ class MGInputSet(InputSet):
self.settings.source = Source(space=Box([0.0, 0.0, 0.0],
[10.0, 10.0, 5.]))
self.settings.energy_mode = "multi-group"
self.settings.cross_sections = "../1d_mgxs.h5"
def build_defualt_plots(self):
plot = openmc.Plot()

View file

@ -11,11 +11,11 @@
</material>
<material id="3">
<density value="2.0" units="g/cc" />
<element name="Zr" ao="1.0" />
<nuclide name="Zr90" ao="1.0" />
</material>
<material id="4">
<density value="0.1" units="g/cc" />
<element name="N" ao="1.0" />
<nuclide name="N14" ao="1.0" />
</material>
</materials>

View file

@ -1,11 +1,11 @@
k-combined:
2.531110E-01 3.041974E-03
2.511523E-01 2.296777E-03
tally 1:
2.594626E+00
1.346701E+00
2.683653E+00
1.440725E+00
9.933862E-01
1.977011E-01
1.112289E-01
2.476655E-03
2.578905E+00
1.331155E+00
2.688693E+00
1.447930E+00
9.863774E-01
1.948549E-01
1.123802E-01
2.527538E-03

View file

@ -0,0 +1,43 @@
#!/usr/bin/env python
import os
import sys
import numpy as np
sys.path.insert(0, os.pardir)
sys.path.insert(0, os.path.join(os.pardir, os.pardir))
from openmc import Material
from openmc.data import NATURAL_ABUNDANCE, atomic_mass
if __name__ == '__main__':
# This test doesn't require an OpenMC run. We just need to make sure the
# element.expand() method expands elements with the proper nuclide
# compositions.
h_am = (NATURAL_ABUNDANCE['H1'] * atomic_mass('H1') +
NATURAL_ABUNDANCE['H2'] * atomic_mass('H2'))
o_am = (NATURAL_ABUNDANCE['O17'] * atomic_mass('O17') +
(NATURAL_ABUNDANCE['O16'] + NATURAL_ABUNDANCE['O18'])
* atomic_mass('O16'))
water_am = 2 * h_am + o_am
water = Material()
water.add_element('O', o_am / water_am, 'wo')
water.add_element('H', 2 * h_am / water_am, 'wo')
densities = water.get_nuclide_densities()
for nuc in densities.keys():
assert nuc in ('H1', 'H2', 'O16', 'O17')
if nuc in ('H1', 'H2'):
val = 2 * NATURAL_ABUNDANCE[nuc] * atomic_mass(nuc) / water_am
assert np.isclose(densities[nuc][1], val, rtol=1.e-8)
if nuc == 'O16':
val = (NATURAL_ABUNDANCE[nuc] + NATURAL_ABUNDANCE['O18']) \
* atomic_mass(nuc) / water_am
assert np.isclose(densities[nuc][1], val, rtol=1.e-8)
if nuc == 'O17':
val = NATURAL_ABUNDANCE[nuc] * atomic_mass(nuc) / water_am
assert np.isclose(densities[nuc][1], val, rtol=1.e-8)

View file

@ -0,0 +1,33 @@
#!/usr/bin/env python
import os
import sys
import numpy as np
sys.path.insert(0, os.pardir)
sys.path.insert(0, os.path.join(os.pardir, os.pardir))
from openmc import Material
from openmc.data import NATURAL_ABUNDANCE, atomic_mass
if __name__ == '__main__':
# This test doesn't require an OpenMC run. We just need to make sure the
# element.expand() method expands Uranium to the proper enrichment.
uranium = Material()
uranium.add_element('U', 1.0, 'wo', 4.95)
densities = uranium.get_nuclide_densities()
sum_densities = 0.
for nuc in densities.keys():
assert nuc in ('U234', 'U235', 'U238')
sum_densities += densities[nuc][1]
# Compute the weight percent U235
enrichment = densities['U235'][1] / sum_densities
assert np.isclose(enrichment, 0.0495, rtol=1.e-8)
# Compute the ratio of U234/U235
u234_to_u235 = densities['U234'][1] / densities['U235'][1]
assert np.isclose(u234_to_u235, 0.008, rtol=1.e-8)

View file

@ -1 +1 @@
115218221500e60ea43145875324a9a6800366fcc97357ef4cd8182f9253e114cbe1c7481dd3bdd8d7dce5983e2cb757ae0a2e05ede236d94cba7909703ba7f7
12abd69924751d1cf2a296ce799bfb2a6a4e744ffc49eef5a5cee8b764254caa3783c406cff71238c5608b454f451953479fb4caad45460a013225ab8de2271e

View file

@ -1 +1 @@
139d760cd83eab001ed3fd52d7146fb5f30b7021b26ada6a1e425f5446185ac6fa61ac2ac58aa9e895981e10540160b7ae7428c833024679ef1ca762715e2d51
1f82e622b36562a0a14536fe24c95ee9c901c428f7f082f245afae5c699ccd647aaf31a49790822ceb7ec136bdb75f8e25c3677642f73702ca2e30b058f6b440

View file

@ -1 +1 @@
6d03b988671fe21dfe2a908685536edb3059e5bdda7974ddfa65c7f63cecb7f6b3fce49bc1533ef2787e284121779653cb14a66cfd709258e4b07d8bd7571843
ec7f0697d22668dcc4cdaf134c58b9f84137730d52cb44264ee9205369abcf995b2f66847d620715cd609bd2f5f865294374978f8fb89f182962e40801171cba

View file

@ -1 +1 @@
8c496e13f9456bedcc0789ffdca81913596cca3c7867717ced38c3063b6cdc8949bd204c98723b72c1b456e3fc85fc90e6710482b0c74e5e29283902a5d9ed50
54cd9db30bc8e671591d76e8da2b5dead54eb4cead1eef09a005e96ca2c0fd707872e0cc21f31d198915b156605de78322fbb7957698ea8febceb23f048e44ad

View file

@ -60,8 +60,8 @@ class MGXSTestHarness(PyAPITestHarness):
self._input_set.mgxs_file, self._input_set.materials, \
self._input_set.geometry = self.mgxs_lib.create_mg_mode()
# Modify settings so we can run in MG mode
self._input_set.settings.cross_sections = './mgxs.h5'
# Modify materials and settings so we can run in MG mode
self._input_set.materials.cross_sections = './mgxs.h5'
self._input_set.settings.energy_mode = 'multi-group'
# Write modified input files

View file

@ -1,94 +0,0 @@
<?xml version="1.0"?>
<geometry>
<!-- pu-met-fast-021 case 2 -->
<surface id="1" type="z-plane" coeffs="-17.51" boundary="vacuum" />
<surface id="2" type="z-plane" coeffs="-2.57" />
<!-- Bottom Plutonium Core -->
<surface id="3" type="z-plane" coeffs="-2.55" />
<surface id="4" type="z-plane" coeffs="-2.37" />
<surface id="5" type="z-plane" coeffs="-2.1" />
<surface id="6" type="z-plane" coeffs="-2.06" />
<surface id="7" type="z-plane" coeffs="-1.61" />
<surface id="8" type="z-plane" coeffs="-1.57" />
<surface id="9" type="z-plane" coeffs="-1.12" />
<surface id="10" type="z-plane" coeffs="-1.08" />
<surface id="11" type="z-plane" coeffs="-0.63" />
<surface id="12" type="z-plane" coeffs="-0.59" />
<surface id="13" type="z-plane" coeffs="-0.14" />
<!-- Middle Gap -->
<surface id="14" type="z-plane" coeffs="-0.12" />
<surface id="15" type="z-plane" coeffs="0.12" />
<!-- Top Plutonium Core -->
<surface id="16" type="z-plane" coeffs="0.14" />
<surface id="17" type="z-plane" coeffs="0.59" />
<surface id="18" type="z-plane" coeffs="0.63" />
<surface id="19" type="z-plane" coeffs="1.08" />
<surface id="20" type="z-plane" coeffs="1.12" />
<surface id="21" type="z-plane" coeffs="1.57" />
<surface id="22" type="z-plane" coeffs="1.61" />
<surface id="23" type="z-plane" coeffs="2.06" />
<surface id="24" type="z-plane" coeffs="2.1" />
<surface id="25" type="z-plane" coeffs="2.37" />
<surface id="26" type="z-plane" coeffs="2.55" />
<surface id="27" type="z-plane" coeffs="2.57" />
<!-- Top Beryllium Reflector -->
<surface id="28" type="z-plane" coeffs="2.59" />
<surface id="29" type="z-plane" coeffs="17.51" boundary="vacuum" />
<!-- Cylinders -->
<surface id="30" type="z-cylinder" coeffs="0 0 9.995" boundary="vacuum" />
<surface id="31" type="z-cylinder" coeffs="0 0 6.263" />
<surface id="32" type="z-cylinder" coeffs="0 0 6.063" />
<surface id="33" type="z-cylinder" coeffs="0 0 5.995" />
<!-- Beryllium Reflector -->
<cell id="1" material="2" region=" 1 -2 -30" />
<cell id="2" material="2" region="28 -29 -30" />
<!-- Duralumin base and top -->
<cell id="3" material="4" region=" 2 -4 -30 31" />
<cell id="4" material="4" region="25 -28 -30 31" />
<!-- Duralumin top cylindrical shell -->
<cell id="6" material="5" region="15 -28 -31 32" />
<!-- Duralumin bottom cylindrical shell -->
<cell id="7" material="6" region=" 2 -14 -31 32" />
<!-- Steel Cover -->
<cell id="8" material="3" region=" 2 -3 -33" />
<cell id="9" material="3" region=" 5 -6 -33" />
<cell id="10" material="3" region=" 7 -8 -33" />
<cell id="11" material="3" region=" 9 -10 -33" />
<cell id="12" material="3" region="11 -12 -33" />
<cell id="13" material="3" region="13 -14 -33" />
<cell id="14" material="3" region="15 -16 -33" />
<cell id="15" material="3" region="17 -18 -33" />
<cell id="16" material="3" region="19 -20 -33" />
<cell id="17" material="3" region="21 -22 -33" />
<cell id="18" material="3" region="23 -24 -33" />
<cell id="19" material="3" region="26 -27 -33" />
<cell id="20" material="3" region=" 2 -14 33 -32" />
<cell id="21" material="3" region="15 -27 33 -32" />
<!-- Plutonium -->
<cell id="22" material="1" region=" 3 -5 -33" />
<cell id="23" material="1" region=" 6 -7 -33" />
<cell id="24" material="1" region=" 8 -9 -33" />
<cell id="25" material="1" region="10 -11 -33" />
<cell id="26" material="1" region="12 -13 -33" />
<cell id="27" material="1" region="16 -17 -33" />
<cell id="28" material="1" region="18 -19 -33" />
<cell id="29" material="1" region="20 -21 -33" />
<cell id="30" material="1" region="22 -23 -33" />
<cell id="31" material="1" region="24 -26 -33" />
<!-- Void -->
<cell id="32" material="void" region="14 -15 -31" />
<cell id="33" material="void" region=" 4 -25 31 -30" />
<cell id="34" material="void" region="27 -28 -30" />
</geometry>

View file

@ -1,62 +0,0 @@
<?xml version="1.0"?>
<materials>
<!-- pu-met-fast-021 case 2 -->
<!-- Plutonium -->
<material id="1">
<density value="18.5345" units="g/cm3" />
<nuclide name="Pu239" ao="4.4422e-02" />
<nuclide name="Pu240" ao="2.1326e-03" />
<nuclide name="Pu241" ao="9.2538e-05" />
<element name="C" ao="1.9515e-04" />
<element name="Fe" ao="8.1943e-05" />
</material>
<!-- Berylium-oxide Reflector -->
<material id="2">
<density value="2.86750" units="g/cm3" />
<nuclide name="Be9" ao="6.9041e-02" />
<element name="O" ao="6.9041e-02" />
</material>
<!-- Steel Cover -->
<material id="3">
<density value="6.9323" units="g/cm3" />
<element name="Fe" ao="5.1280e-02" />
<element name="C" ao="3.4757e-04" />
<element name="Si" ao="8.9185e-04" />
<element name="Ti" ao="6.1034e-04" />
<element name="Cr" ao="1.4452e-02" />
<element name="Mn" ao="1.5198e-03" />
<element name="Ni" ao="7.1131e-03" />
</material>
<!-- Duralumin base and top -->
<material id="4">
<density value="2.78" units="g/cm3" />
<element name="Al" ao="5.8077e-02" />
<element name="Mg" ao="1.0332e-03" />
<element name="Mn" ao="1.8284e-04" />
<element name="Cu" ao="1.1329e-03" />
</material>
<!-- Duralumin top cylindrical shell -->
<material id="5">
<density value="0.417" units="g/cm3" />
<element name="Al" ao="8.7115e-03" />
<element name="Mg" ao="1.5498e-04" />
<element name="Mn" ao="2.7426e-05" />
<element name="Cu" ao="1.6993e-04" />
</material>
<!-- Duralumin bottom cylindrical shell -->
<material id="6">
<density value="1.8155" units="g/cm3" />
<element name="Al" ao="3.7928e-02" />
<element name="Mg" ao="6.7475e-04" />
<element name="Mn" ao="1.1941e-04" />
<element name="Cu" ao="7.3982e-04" />
</material>
</materials>

View file

@ -1,2 +0,0 @@
k-combined:
1.034427E+00 1.583807E-02

View file

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<settings>
<!-- pu-met-fast-021 case 2 -->
<eigenvalue>
<batches>10</batches>
<inactive>5</inactive>
<particles>400</particles>
</eigenvalue>
<natural_elements>endf/b-vii.1</natural_elements>
<source>
<space>
<type>box</type>
<parameters>0 0 0 1 1 1</parameters>
</space>
</source>
</settings>

View file

@ -1,11 +0,0 @@
#!/usr/bin/env python
import os
import sys
sys.path.insert(0, os.pardir)
from testing_harness import TestHarness
if __name__ == '__main__':
harness = TestHarness('statepoint.10.*')
harness.main()

View file

@ -122,7 +122,7 @@ class TalliesTestHarness(PyAPITestHarness):
t.filters = [cell_filter]
t.scores = ['absorption', 'delayed-nu-fission', 'events', 'fission',
'inverse-velocity', 'kappa-fission', '(n,2n)', '(n,n1)',
'(n,gamma)', 'nu-fission', 'scatter', 'elastic',
'(n,gamma)', 'nu-fission', 'scatter', 'elastic',
'total', 'prompt-nu-fission', 'fission-q-prompt',
'fission-q-recoverable']
score_tallies[0].estimator = 'tracklength'

View file

@ -1 +1 @@
b22973093e2b0690b30fb1262a11e27004555b796c446d256cb58a1d7329888ab60c1b93729b3d74bb015b98aa434416daa2dc2aee526eb8df0e9052911f94b4
3a356b5b6d0aaa3db8c601521e1837a6870c5e5f6d1068f4f3e9b896c0107517d99ff9676311221633169b4d79dc1c4076bff84130e6de16df7ace4da5481a60