mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 21:55:41 -04:00
Add useful warnings for add_nuclide/add_element
This commit is contained in:
parent
395a5a53d0
commit
0508274a3d
6 changed files with 38 additions and 42 deletions
|
|
@ -43,14 +43,22 @@ of an element, you specify the element itself. For example,
|
|||
Internally, OpenMC stores data on the atomic masses and natural abundances of
|
||||
all known isotopes and then uses this data to determine what isotopes should be
|
||||
added to the material. When the material is later exported to XML for use by the
|
||||
:ref:`scripts_openmc` executable, you'll see that any natural elements are
|
||||
:ref:`scripts_openmc` executable, you'll see that any natural elements were
|
||||
expanded to the naturally-occurring isotopes.
|
||||
|
||||
The :meth:`Material.add_element` method can also be used to add uranium at a
|
||||
specified enrichment through the `enrichment` argument. For example, the
|
||||
following would add 3.2% enriched uranium to a material::
|
||||
|
||||
mat.add_element('U', 1.0, enrichment=3.2)
|
||||
|
||||
In addition to U235 and U238, concentrations of U234 and U236 will be present
|
||||
and are determined through a correlation based on measured data.
|
||||
|
||||
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
|
||||
what cross sections you will be using (either through the
|
||||
:attr:`Materials.cross_sections` attribute or the
|
||||
what cross sections you will be using (through the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable), it will attempt to only
|
||||
put isotopes in your model for which you have cross section data. In the case of
|
||||
oxygen in ENDF/B-VII.1, the abundance of O18 would end up being lumped with O16.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import sys
|
|||
import numpy as np
|
||||
|
||||
from openmc.mixin import EqualityMixin
|
||||
from openmc.data.endf import ENDF_FLOAT_RE
|
||||
from openmc.data.endf import _ENDF_FLOAT_RE
|
||||
|
||||
def ascii_to_binary(ascii_file, binary_file):
|
||||
"""Convert an ACE file in ASCII format (type 1) to binary format (type 2).
|
||||
|
|
@ -349,7 +349,7 @@ class Library(EqualityMixin):
|
|||
# after it). If it's too short, then we apply the ENDF float regular
|
||||
# expression. We don't do this by default because it's expensive!
|
||||
if xss.size != nxs[1] + 1:
|
||||
datastr = ENDF_FLOAT_RE.sub(r'\1e\2', datastr)
|
||||
datastr = _ENDF_FLOAT_RE.sub(r'\1e\2', datastr)
|
||||
xss = np.fromstring(datastr, sep=' ')
|
||||
assert xss.size == nxs[1] + 1
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()}
|
|||
|
||||
_ATOMIC_MASS = {}
|
||||
|
||||
_GND_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)')
|
||||
|
||||
|
||||
def atomic_mass(isotope):
|
||||
"""Return atomic mass of isotope in atomic mass units.
|
||||
|
|
@ -352,8 +354,7 @@ def zam(name):
|
|||
|
||||
"""
|
||||
try:
|
||||
symbol, A, state = re.match(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)',
|
||||
name).groups()
|
||||
symbol, A, state = _GND_NAME_RE.match(name).groups()
|
||||
except AttributeError:
|
||||
raise ValueError("'{}' does not appear to be a nuclide name in GND "
|
||||
"format.".format(name))
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ SUM_RULES = {1: [2, 3],
|
|||
106: list(range(750, 800)),
|
||||
107: list(range(800, 850))}
|
||||
|
||||
ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]\d+)')
|
||||
_ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]\d+)')
|
||||
|
||||
|
||||
def float_endf(s):
|
||||
|
|
@ -68,7 +68,7 @@ def float_endf(s):
|
|||
The number
|
||||
|
||||
"""
|
||||
return float(ENDF_FLOAT_RE.sub(r'\1e\2', s))
|
||||
return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s))
|
||||
|
||||
|
||||
def get_text_record(file_obj):
|
||||
|
|
|
|||
|
|
@ -379,33 +379,27 @@ class Material(IDManagerMixin):
|
|||
Parameters
|
||||
----------
|
||||
nuclide : str
|
||||
Nuclide to add
|
||||
Nuclide to add, e.g., 'Mo95'
|
||||
percent : float
|
||||
Atom or weight percent
|
||||
percent_type : {'ao', 'wo'}
|
||||
'ao' for atom percent and 'wo' for weight percent
|
||||
|
||||
"""
|
||||
cv.check_type('nuclide', nuclide, str)
|
||||
cv.check_type('percent', percent, Real)
|
||||
cv.check_value('percent type', percent_type, {'ao', 'wo'})
|
||||
|
||||
if self._macroscopic is not None:
|
||||
msg = 'Unable to add a Nuclide to Material ID="{}" as a ' \
|
||||
'macroscopic data-set has already been added'.format(self._id)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(nuclide, str):
|
||||
msg = 'Unable to add a Nuclide to Material ID="{}" with a ' \
|
||||
'non-string value "{}"'.format(self._id, nuclide)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not isinstance(percent, Real):
|
||||
msg = 'Unable to add a Nuclide to Material ID="{}" with a ' \
|
||||
'non-floating point value "{}"'.format(self._id, percent)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif percent_type not in ('ao', 'wo'):
|
||||
msg = 'Unable to add a Nuclide to Material ID="{}" with a ' \
|
||||
'percent type "{}"'.format(self._id, percent_type)
|
||||
raise ValueError(msg)
|
||||
# If nuclide name doesn't look valid, give a warning
|
||||
try:
|
||||
openmc.data.zam(nuclide)
|
||||
except ValueError as e:
|
||||
warnings.warn(str(e))
|
||||
|
||||
self._nuclides.append((nuclide, percent, percent_type))
|
||||
|
||||
|
|
@ -493,7 +487,7 @@ class Material(IDManagerMixin):
|
|||
Parameters
|
||||
----------
|
||||
element : str
|
||||
Element to add
|
||||
Element to add, e.g., 'Zr'
|
||||
percent : float
|
||||
Atom or weight percent
|
||||
percent_type : {'ao', 'wo'}, optional
|
||||
|
|
@ -505,27 +499,15 @@ class Material(IDManagerMixin):
|
|||
(natural composition).
|
||||
|
||||
"""
|
||||
cv.check_type('nuclide', element, str)
|
||||
cv.check_type('percent', percent, Real)
|
||||
cv.check_value('percent type', percent_type, {'ao', 'wo'})
|
||||
|
||||
if self._macroscopic is not None:
|
||||
msg = 'Unable to add an Element to Material ID="{}" as a ' \
|
||||
'macroscopic data-set has already been added'.format(self._id)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(element, str):
|
||||
msg = 'Unable to add an Element to Material ID="{}" with a ' \
|
||||
'non-string value "{}"'.format(self._id, element)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(percent, Real):
|
||||
msg = 'Unable to add an Element to Material ID="{}" with a ' \
|
||||
'non-floating point value "{}"'.format(self._id, percent)
|
||||
raise ValueError(msg)
|
||||
|
||||
if percent_type not in ['ao', 'wo']:
|
||||
msg = 'Unable to add an Element to Material ID="{}" with a ' \
|
||||
'percent type "{}"'.format(self._id, percent_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
if enrichment is not None:
|
||||
if not isinstance(enrichment, Real):
|
||||
msg = 'Unable to add an Element to Material ID="{}" with a ' \
|
||||
|
|
@ -551,6 +533,11 @@ class Material(IDManagerMixin):
|
|||
format(enrichment, self._id)
|
||||
warnings.warn(msg)
|
||||
|
||||
# Make sure element name is just that
|
||||
if not element.isalpha():
|
||||
raise ValueError("Element name should be given by the "
|
||||
"element's symbol, e.g., 'Zr'")
|
||||
|
||||
# Add naturally-occuring isotopes
|
||||
element = openmc.Element(element)
|
||||
for nuclide in element.expand(percent, percent_type, enrichment):
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ def test_nuclides(uo2):
|
|||
"""Test adding/removing nuclides."""
|
||||
m = openmc.Material()
|
||||
m.add_nuclide('U235', 1.0)
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(TypeError):
|
||||
m.add_nuclide('H1', '1.0')
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(TypeError):
|
||||
m.add_nuclide(1.0, 'H1')
|
||||
with pytest.raises(ValueError):
|
||||
m.add_nuclide('H1', 1.0, 'oa')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue