mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Merge pull request #1 from davidjohnlong/develop
Update fixed source development branch
This commit is contained in:
commit
68841672a5
14 changed files with 445 additions and 119 deletions
|
|
@ -165,7 +165,6 @@ endif()
|
|||
add_subdirectory(vendor/xtl)
|
||||
set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl)
|
||||
add_subdirectory(vendor/xtensor)
|
||||
target_link_libraries(xtensor INTERFACE xtl)
|
||||
|
||||
#===============================================================================
|
||||
# GSL header-only library
|
||||
|
|
|
|||
|
|
@ -61,6 +61,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 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%::
|
||||
|
||||
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 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',
|
||||
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
|
||||
|
|
@ -141,6 +155,33 @@ attribute, e.g.,
|
|||
:attr:`Material.temperature` or :attr:`Cell.temperature`
|
||||
attributes, respectively.
|
||||
|
||||
-----------------
|
||||
Material Mixtures
|
||||
-----------------
|
||||
|
||||
In OpenMC it is possible to mix any number of materials to create a new material
|
||||
with the correct nuclide composition and density. The
|
||||
:meth:`Material.mix_materials` method takes a list of materials and
|
||||
a list of their mixing fractions. Mixing fractions can be provided as atomic
|
||||
fractions, weight fractions, or volume fractions. The fraction type
|
||||
can be specified by passing 'ao', 'wo', or 'vo' as the third argument, respectively.
|
||||
For example, assuming the required materials have already been defined, a MOX
|
||||
material with 3% plutonium oxide by weight could be created using the following:
|
||||
|
||||
::
|
||||
|
||||
mox = openmc.Material.mix_materials([uo2, puo2], [0.97, 0.03], 'wo')
|
||||
|
||||
It should be noted that, if mixing fractions are specifed as atomic or weight
|
||||
fractions, the supplied fractions should sum to one. If the fractions are specified
|
||||
as volume fractions, and the sum of the fractions is less than one, then the remaining
|
||||
fraction is set as void material.
|
||||
|
||||
.. warning:: Materials with :math:`S(\alpha,\beta)` thermal scattering data
|
||||
cannot be used in :meth:`Material.mix_materials`. However, thermal
|
||||
scattering data can be added to a material created by
|
||||
:meth:`Material.mix_materials`.
|
||||
|
||||
--------------------
|
||||
Material Collections
|
||||
--------------------
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -86,11 +86,15 @@ void count_cell_instances(int32_t univ_indx);
|
|||
//! Recursively search through universes and count universe instances.
|
||||
//! \param search_univ The index of the universe to begin searching from.
|
||||
//! \param target_univ_id The ID of the universe to be counted.
|
||||
//! \param univ_count_memo Memoized counts that make this function faster for
|
||||
//! large systems. The first call to this function for each target_univ_id
|
||||
//! should start with an empty memo.
|
||||
//! \return The number of instances of target_univ_id in the geometry tree under
|
||||
//! search_univ.
|
||||
//==============================================================================
|
||||
|
||||
int count_universe_instances(int32_t search_univ, int32_t target_univ_id);
|
||||
int count_universe_instances(int32_t search_univ, int32_t target_univ_id,
|
||||
std::unordered_map<int32_t, int32_t>& univ_count_memo);
|
||||
|
||||
//==============================================================================
|
||||
//! Build a character array representing the path to a distribcell instance.
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ public:
|
|||
{offsets_.resize(n_maps * universes_.size(), C_NONE);}
|
||||
|
||||
//! Populate the distribcell offset tables.
|
||||
int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map);
|
||||
int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map,
|
||||
std::unordered_map<int32_t, int32_t>& univ_count_memo);
|
||||
|
||||
//! \brief Check lattice indices.
|
||||
//! \param i_xyz[3] The indices for a lattice tile.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ class Element(str):
|
|||
return self
|
||||
|
||||
def expand(self, percent, percent_type, enrichment=None,
|
||||
enrichment_target=None, enrichment_type=None,
|
||||
cross_sections=None):
|
||||
"""Expand natural element into its naturally-occurring isotopes.
|
||||
|
||||
|
|
@ -52,9 +54,15 @@ 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 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' for two-isotope enrichment; 'wo' for U enrichment
|
||||
cross_sections : str, optional
|
||||
Location of cross_sections.xml file. Default is None.
|
||||
|
||||
|
|
@ -65,16 +73,47 @@ 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 available in the cross-section data
|
||||
library and the element is not O, W, or Ta
|
||||
ValueError
|
||||
If a non-naturally-occurring isotope is requested
|
||||
ValueError
|
||||
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.
|
||||
ValueError
|
||||
Uranium enrichment is requested with enrichment_type=='ao'
|
||||
|
||||
Notes
|
||||
-----
|
||||
When the `enrichment` argument is specified, a correlation from
|
||||
`ORNL/CSD/TM-244 <https://doi.org/10.2172/5561567>`_ 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.
|
||||
|
||||
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
|
||||
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)
|
||||
cv.check_greater_than('enrichment', enrichment, 0., equality=True)
|
||||
|
||||
# Get the nuclides present in nature
|
||||
natural_nuclides = set()
|
||||
|
|
@ -110,8 +149,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 +203,20 @@ 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:
|
||||
|
||||
# Check that the element is Uranium
|
||||
if self.name != 'U':
|
||||
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%.')
|
||||
raise ValueError(msg)
|
||||
|
||||
# Calculate the mass fractions of isotopes
|
||||
abundances['U234'] = 0.0089 * enrichment
|
||||
|
|
@ -181,6 +233,73 @@ 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 not None:
|
||||
|
||||
# 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_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 {} 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:
|
||||
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 = sum(atomic_mass(nuc)*abundances[nuc] for nuc in abundances)
|
||||
|
||||
# Convert Molar Fractions to mass fractions
|
||||
for nuclide in abundances:
|
||||
abundances[nuclide] *= atomic_mass(nuclide) / element_am
|
||||
|
||||
# Normalize to one
|
||||
sum_abundances = sum(abundances.values())
|
||||
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 ratios
|
||||
# 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 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 if requested
|
||||
if enrichment_type == 'wo':
|
||||
# Convert the mass fractions to mole fractions
|
||||
for nuclide in abundances:
|
||||
abundances[nuclide] /= atomic_mass(nuclide)
|
||||
|
||||
# Normalize the mole fractions to one
|
||||
sum_abundances = sum(abundances.values())
|
||||
for nuclide in abundances:
|
||||
abundances[nuclide] /= sum_abundances
|
||||
|
||||
# Compute the ratio of the nuclide atomic masses to the element
|
||||
# atomic mass
|
||||
if percent_type == 'wo':
|
||||
|
|
|
|||
|
|
@ -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=None):
|
||||
"""Add a natural element to the material
|
||||
|
||||
Parameters
|
||||
|
|
@ -512,9 +513,22 @@ 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).
|
||||
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' for two-isotope enrichment; 'wo' for U enrichment
|
||||
|
||||
Notes
|
||||
-----
|
||||
General enrichment procedure is allowed only for elements composed of
|
||||
two isotopes. If `enrichment_target` is given without `enrichment`
|
||||
natural composition is added to the material.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -540,7 +554,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 "{}"'\
|
||||
|
|
@ -567,7 +581,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):
|
||||
|
|
@ -936,7 +954,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
|
||||
|
|
@ -1005,7 +1023,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')
|
||||
|
|
|
|||
|
|
@ -385,8 +385,10 @@ prepare_distribcell()
|
|||
}
|
||||
|
||||
// Fill the cell and lattice offset tables.
|
||||
#pragma omp parallel for
|
||||
for (int map = 0; map < target_univ_ids.size(); map++) {
|
||||
auto target_univ_id = target_univ_ids[map];
|
||||
std::unordered_map<int32_t, int32_t> univ_count_memo;
|
||||
for (const auto& univ : model::universes) {
|
||||
int32_t offset = 0;
|
||||
for (int32_t cell_indx : univ->cells_) {
|
||||
|
|
@ -395,11 +397,13 @@ prepare_distribcell()
|
|||
if (c.type_ == Fill::UNIVERSE) {
|
||||
c.offset_[map] = offset;
|
||||
int32_t search_univ = c.fill_;
|
||||
offset += count_universe_instances(search_univ, target_univ_id);
|
||||
offset += count_universe_instances(search_univ, target_univ_id,
|
||||
univ_count_memo);
|
||||
|
||||
} else if (c.type_ == Fill::LATTICE) {
|
||||
Lattice& lat = *model::lattices[c.fill_];
|
||||
offset = lat.fill_offset_table(offset, target_univ_id, map);
|
||||
offset = lat.fill_offset_table(offset, target_univ_id, map,
|
||||
univ_count_memo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -411,7 +415,6 @@ prepare_distribcell()
|
|||
void
|
||||
count_cell_instances(int32_t univ_indx)
|
||||
{
|
||||
|
||||
const auto univ_counts = model::universe_cell_counts.find(univ_indx);
|
||||
if (univ_counts != model::universe_cell_counts.end()) {
|
||||
for (const auto& it : univ_counts->second) {
|
||||
|
|
@ -442,30 +445,42 @@ count_cell_instances(int32_t univ_indx)
|
|||
//==============================================================================
|
||||
|
||||
int
|
||||
count_universe_instances(int32_t search_univ, int32_t target_univ_id)
|
||||
count_universe_instances(int32_t search_univ, int32_t target_univ_id,
|
||||
std::unordered_map<int32_t, int32_t>& univ_count_memo)
|
||||
{
|
||||
// If this is the target, it can't contain itself.
|
||||
// If this is the target, it can't contain itself.
|
||||
if (model::universes[search_univ]->id_ == target_univ_id) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we have already counted the number of instances, reuse that value.
|
||||
auto search = univ_count_memo.find(search_univ);
|
||||
if (search != univ_count_memo.end()) {
|
||||
return search->second;
|
||||
}
|
||||
|
||||
int count {0};
|
||||
for (int32_t cell_indx : model::universes[search_univ]->cells_) {
|
||||
Cell& c = *model::cells[cell_indx];
|
||||
|
||||
if (c.type_ == Fill::UNIVERSE) {
|
||||
int32_t next_univ = c.fill_;
|
||||
count += count_universe_instances(next_univ, target_univ_id);
|
||||
count += count_universe_instances(next_univ, target_univ_id,
|
||||
univ_count_memo);
|
||||
|
||||
} else if (c.type_ == Fill::LATTICE) {
|
||||
Lattice& lat = *model::lattices[c.fill_];
|
||||
for (auto it = lat.begin(); it != lat.end(); ++it) {
|
||||
int32_t next_univ = *it;
|
||||
count += count_universe_instances(next_univ, target_univ_id);
|
||||
count += count_universe_instances(next_univ, target_univ_id,
|
||||
univ_count_memo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remember the number of instances in this universe.
|
||||
univ_count_memo[search_univ] = count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,11 +93,12 @@ Lattice::adjust_indices()
|
|||
//==============================================================================
|
||||
|
||||
int32_t
|
||||
Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map)
|
||||
Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map,
|
||||
std::unordered_map<int32_t, int32_t>& univ_count_memo)
|
||||
{
|
||||
for (LatticeIter it = begin(); it != end(); ++it) {
|
||||
offsets_[map * universes_.size() + it.indx_] = offset;
|
||||
offset += count_universe_instances(*it, target_univ_id);
|
||||
offset += count_universe_instances(*it, target_univ_id, univ_count_memo);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
|
|
|||
81
tests/unit_tests/test_element.py
Normal file
81
tests/unit_tests/test_element.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import openmc
|
||||
from pytest import approx, raises
|
||||
|
||||
from openmc.data import NATURAL_ABUNDANCE, atomic_mass
|
||||
|
||||
|
||||
def test_expand_no_enrichment():
|
||||
""" Expand Li in natural compositions"""
|
||||
lithium = openmc.Element('Li')
|
||||
|
||||
# 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)
|
||||
|
||||
# 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:
|
||||
natural[key] /= li_am
|
||||
|
||||
for isotope in lithium.expand(100.0, 'wo'):
|
||||
assert isotope[1] == approx(natural[isotope[0]] * 100.0)
|
||||
|
||||
|
||||
def test_expand_enrichment():
|
||||
""" Expand and verify enrichment of 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] == 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]])
|
||||
|
||||
|
||||
def test_expand_exceptions():
|
||||
""" Test that correct exceptions are raised for invalid input """
|
||||
|
||||
# 1 Isotope Element
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('Be')
|
||||
element.expand(70.0, 'ao', 4.0, 'Be9')
|
||||
|
||||
# 3 Isotope Element
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('Cr')
|
||||
element.expand(70.0, 'ao', 4.0, 'Cr52')
|
||||
|
||||
# Non-present Enrichment Target
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('H')
|
||||
element.expand(70.0, 'ao', 4.0, 'H4')
|
||||
|
||||
# Enrichment Procedure for Uranium if not Uranium
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('Li')
|
||||
element.expand(70.0, 'ao', 4.0)
|
||||
|
||||
# Missing Enrichment Target
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('Li')
|
||||
element.expand(70.0, 'ao', 4.0, enrichment_type='ao')
|
||||
|
||||
# Invalid Enrichment Type Entry
|
||||
with raises(ValueError):
|
||||
element = openmc.Element('Li')
|
||||
element.expand(70.0, 'ao', 4.0, 'Li7', 'Grand Moff Tarkin')
|
||||
|
||||
# Trying to enrich Uranium
|
||||
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 raises(ValueError):
|
||||
element = openmc.Element('U')
|
||||
element.expand(70.0, 'ao', 4.0, enrichment_type='ao')
|
||||
|
|
@ -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_elements_by_name():
|
||||
"""Test adding elements by name"""
|
||||
|
|
|
|||
2
vendor/xtensor
vendored
2
vendor/xtensor
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit ef091807f7ed0e5ba7e251a6c46f4af7bba79e2e
|
||||
Subproject commit 31acec1e90bbea6d4bc17af0710a123bd5da6689
|
||||
2
vendor/xtl
vendored
2
vendor/xtl
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit f5d13e6c4f856becc178939365fcdcf9a657ffb5
|
||||
Subproject commit 0024346605bd92bcc4009caad7f4be88687e063a
|
||||
Loading…
Add table
Add a link
Reference in a new issue