Use dictionary to create FissionYieldDistribution

Removes the FissionYieldDistribution.from_dict method as the
most natural way to create such a distribution is with a dictionary.
This commit is contained in:
Andrew Johnson 2019-08-21 10:55:43 -05:00
parent f977962113
commit 60f89794f6
No known key found for this signature in database
GPG key ID: 253418E91B7F6FEB
5 changed files with 38 additions and 66 deletions

View file

@ -10,7 +10,6 @@ import math
import re
from collections import OrderedDict, defaultdict
from collections.abc import Mapping, Iterable
from numbers import Real
from warnings import warn
from openmc.checkvalue import check_type, check_less_than
@ -127,8 +126,8 @@ class Chain(object):
fission_yields : None or iterable of dict
List of effective fission yields for materials. Each dictionary
should be of the form ``{parent: {product: yield}}`` with
types ``{str: {str: float}}``, where ``yield`` is the fission product yield
for isotope ``parent`` producing isotope ``product``.
types ``{str: {str: float}}``, where ``yield`` is the fission product
yield for isotope ``parent`` producing isotope ``product``.
A single entry indicates yields are constant across all materials.
Otherwise, an entry can be added for each material to be burned.
Ordering should be identical to how the operator orders reaction
@ -222,7 +221,8 @@ class Chain(object):
if mode.daughter in decay_data:
target = mode.daughter
else:
print('missing {} {} {}'.format(parent, ','.join(mode.modes), mode.daughter))
print('missing {} {} {}'.format(
parent, ','.join(mode.modes), mode.daughter))
target = replace_missing(mode.daughter, decay_data)
# Write branching ratio, taking care to ensure sum is unity
@ -285,7 +285,7 @@ class Chain(object):
yield_replace = 0.0
yields = defaultdict(float)
for product, y in table.items():
# Handle fission products that have no decay data available
# Handle fission products that have no decay data
if product not in decay_data:
daughter = replace_missing(product, decay_data)
product = daughter
@ -297,8 +297,7 @@ class Chain(object):
missing_fp.append((parent, E, yield_replace))
yield_data[E] = yields
nuclide.yield_data = (
FissionYieldDistribution.from_dict(yield_data))
nuclide.yield_data = FissionYieldDistribution(yield_data)
# Display warnings
if missing_daughter:

View file

@ -3,16 +3,15 @@
Contains the per-nuclide components of a depletion chain.
"""
from numbers import Real
from collections import namedtuple
from collections.abc import Iterable, Mapping
from collections.abc import Mapping
try:
import lxml.etree as ET
except ImportError:
import xml.etree.ElementTree as ET
from numpy import asarray, empty
from numpy import empty
from openmc.checkvalue import check_type
@ -132,7 +131,7 @@ class Nuclide(object):
check_type("fission_yields", fission_yields, Mapping)
if isinstance(fission_yields, FissionYieldDistribution):
self._yield_data = fission_yields
self._yield_data = FissionYieldDistribution.from_dict(fission_yields)
self._yield_data = FissionYieldDistribution(fission_yields)
@property
def yield_energies(self):
@ -245,7 +244,7 @@ class FissionYieldDistribution(Mapping):
Can be used as a dictionary mapping energies and products to fission
yields::
>>> fydist = FissionYieldDistribution.from_dict({
>>> fydist = FissionYieldDistribution{
... {0.0253: {"Xe135": 0.021}})
>>> fydist[0.0253]["Xe135"]
0.021
@ -266,11 +265,10 @@ class FissionYieldDistribution(Mapping):
Attributes
----------
energies : tuple
Energies for which fission yields exist. Converted for
indexing
Energies for which fission yields exist. Sorted by
increasing energy
products : tuple
Fission products produced at all energies. Converted
for indexing
Fission products produced at all energies. Sorted by name.
yield_matrix : numpy.ndarray
Array ``(n_energy, n_products)`` where
``yield_matrix[g, j]`` is the fission yield of product
@ -278,22 +276,28 @@ class FissionYieldDistribution(Mapping):
See Also
--------
* :meth:`from_xml_element`, :meth:`from_dict` - Construction methods
* :meth:`from_xml_element` - Construction methods
* :class:`FissionYield` - Class used for storing yields at a given energy
"""
def __init__(self, energies, products, yield_matrix):
check_type("energies", energies, Iterable, Real)
def __init__(self, fission_yields):
# mapping {energy: {product: value}}
energies = sorted(fission_yields)
# Get a consistent set of products to produce a matrix of yields
shared_prod = set.union(*(set(x) for x in fission_yields.values()))
ordered_prod = sorted(shared_prod)
yield_matrix = empty((len(energies), len(shared_prod)))
for g_index, energy in enumerate(energies):
prod_map = fission_yields[energy]
for prod_ix, product in enumerate(ordered_prod):
yield_val = prod_map.get(product)
yield_matrix[g_index, prod_ix] = (
0.0 if yield_val is None else yield_val)
self.energies = tuple(energies)
check_type("products", products, Iterable, str)
self.products = tuple(products)
yield_matrix = asarray(yield_matrix, dtype=float)
if yield_matrix.shape != (len(self.energies), len(self.products)):
raise ValueError(
"Shape of yield matrix inconsistent. "
"Should be ({}, {}), is {}".format(
len(energies), len(products),
yield_matrix.shape))
self.products = tuple(ordered_prod)
self.yield_matrix = yield_matrix
def __len__(self):
@ -329,38 +333,7 @@ class FissionYieldDistribution(Mapping):
# Get a map of products to their corresponding yield
all_yields[energy] = dict(zip(products, yields))
return cls.from_dict(all_yields)
@classmethod
def from_dict(cls, fission_yields):
"""Construct a distribution from a dictionary of yields
Parameters
-----------
fission_yields : dict
Dictionary ``{energy: {product: yield}}``
Returns
-------
FissionYieldDistribution
"""
# mapping {energy: {product: value}}
energies = sorted(fission_yields)
# Get a consistent set of products to produce a matrix of yields
shared_prod = set.union(*(set(x) for x in fission_yields.values()))
ordered_prod = sorted(shared_prod)
yield_matrix = empty((len(energies), len(shared_prod)))
for g_index, energy in enumerate(energies):
prod_map = fission_yields[energy]
for prod_ix, product in enumerate(ordered_prod):
yield_val = prod_map.get(product)
yield_matrix[g_index, prod_ix] = (
0.0 if yield_val is None else yield_val)
return cls(energies, ordered_prod, yield_matrix)
return cls(all_yields)
def to_xml_element(self, root):
"""Write fission yield data to an xml element

View file

@ -160,7 +160,7 @@ def test_export_to_xml(run_in_tmpdir):
nuclide.ReactionTuple("(n,gamma)", "A", 0.0, 0.7),
nuclide.ReactionTuple("(n,gamma)", "B", 0.0, 0.3)
]
C.yield_data = nuclide.FissionYieldDistribution.from_dict({
C.yield_data = nuclide.FissionYieldDistribution({
0.0253: {"A": 0.0292737, "B": 0.002566345}})
chain = Chain()

View file

@ -21,11 +21,11 @@ def nuclide_bundle():
5.0e5: {"Xe135": 7.85e-4, "Sm149": 1.71e-12},
1.40e7: {"Xe135": 4.54e-3, "Gd155": 5.83e-8}}
u235 = Nuclide("U235")
u235.yield_data = FissionYieldDistribution.from_dict(u5yield_dict)
u235.yield_data = FissionYieldDistribution(u5yield_dict)
u8yield_dict = {5.00e5: {"Xe135": 1.12e-3, "Gd155": 1.32e-12}}
u238 = Nuclide("U238")
u238.yield_data = FissionYieldDistribution.from_dict(u8yield_dict)
u238.yield_data = FissionYieldDistribution(u8yield_dict)
xe135 = Nuclide("Xe135")

View file

@ -71,7 +71,7 @@ def test_from_xml():
nuclide.ReactionTuple('(n,gamma)', 'U236', 6545200.0, 1.0),
nuclide.ReactionTuple('fission', None, 193405400.0, 1.0),
]
expected_yield_data = nuclide.FissionYieldDistribution.from_dict({
expected_yield_data = nuclide.FissionYieldDistribution({
0.0253: {"Xe138": 0.0481413, "Zr100": 0.0497641, "Te134": 0.062155}})
assert u235.yield_data == expected_yield_data
# test accessing the yield energies through the FissionYieldDistribution
@ -94,7 +94,7 @@ def test_to_xml_element():
nuclide.ReactionTuple('fission', None, 2.0e8, 1.0),
nuclide.ReactionTuple('(n,gamma)', 'A', 0.0, 1.0)
]
C.yield_data = nuclide.FissionYieldDistribution.from_dict(
C.yield_data = nuclide.FissionYieldDistribution(
{0.0253: {"A": 0.0292737, "B": 0.002566345}})
element = C.to_xml_element()
@ -127,7 +127,7 @@ def test_fission_yield_distribution():
1.40e7: {"Xe135": 4.54e-3, "Gd155": 5.83e-8, "Sm149": 2.69e-8},
5.00e5: {"Xe135": 1.12e-3, "Gd155": 1.32e-12}, # drop Sm149
}
yield_dist = nuclide.FissionYieldDistribution.from_dict(yield_dict)
yield_dist = nuclide.FissionYieldDistribution(yield_dict)
assert len(yield_dist) == len(yield_dict)
assert yield_dist.energies == tuple(sorted(yield_dict.keys()))
for exp_ene, exp_dist in yield_dict.items():