This is related to a bug pointed out in the user's group, where
writing a ReactionTuple with a None target errors.
https://groups.google.com/forum/#!topic/openmc-users/jB_-zEKhF-k
The condition appeared when the reaction was a non-fission
(n, gamma), but the daughter isotope did not exist in the Chain,
represented by None.
This issue is resolved by skipping the target only if daughter
is None, regardless of reaction. The Nuclide.from_xml can handle
a missing target just as it handles a target of "Nothing"
[case-insensitive]
This change is more declarative and mitigates any changes
that there are errors if a target is Nothing, None, or their lower
cased varieties. This is helpful as the depletion chain gets
reduced down and we want to keep total removal rates for
isotopes that are present, but their products don't exist
in the new reduced chain.
Chain.form_matrix has been updated to handle targets that
are None for non-fission reactions and for decay reactions.
Documentation for ReactionTuple and DecayTuple have been
updated to indicate that the target attribute could be None.
Set ``__array_ufunc__`` to ``None`` to ensure that numpy floats respect
__rmul__ and __radd__ for fission yields. Allows weights to be left
or right multiplied as numpy floats, which can be computed during
fission yield weighting. A unit test has been added to ensure this
behavior is preserved
Closes#1492
Clarify that inputs to FissionYield should be sorted. Otherwise
the __contains__ and __getitem__ methods will fail.
Removed the call to FissionYield.copy() and re-structured
the final ``dict(new)`` call to work with doc testing,
as dictionaries are not guaranteed to be ordered. Also
fixed the FissionYieldDistribution example
Provide explicit __all__ lists for files in openmc/deplete
containing classes that should be brought into the "primary"
API. This prevents cluttering the openmc.deplete namespace
caused by the wildcard imports
```
from .nuclide import *
...
```
The abc, cram, and helpers modules are imported simply as
```
from . import abc
from . import cram
from . import helpers
```
Remove copy method.
__contains__ and __getitem__ now take advantage of the
ordering of products. This can improve time searching
for fission products and retrieving yields.
radd and rmul methods defer to their left counterparts, e.g.
x * fy => fy * x. Return NotImplemented types if addition is
not done with another set of fission yields and multiplication
is not done with a scalar.
Improve/expand special methods for FissionYield
Remove copy method.
__contains__ and __getitem__ now take advantage of the
ordering of products. This can improve time searching
for fission products and retrieving yields.
radd and rmul methods defer to their left counterparts, e.g.
x * fy => fy * x. Return NotImplemented types if addition is
not done with another set of fission yields and multiplication
is not done with a scalar.
Reconfigure tests/unit_tests/test_deplete_chain.py and
tests/unit_tests/test_deplete_nuclide.py to use the new
dictionary-like representation of fission yields.
Had to guard against some cases where it was assumed
that yield_data would be a dictionary. For the most part,
the fission yield helpers act on nuclides that have yield data
already.
The previous default state was to use an empty dictionary.
This has been removed. A value of None for nuclide.yield_data
indicates there is no yield data.
For consistency across the various fission yield helpers, the
Nuclide object now sets the yield data to always be a
FissionYieldDistribution or an empty dictionary.
Nuclide.yield_energies is now a property that returns the
energies from the FissionYieldDistribution.
When setting the yield_data, the Nuclide enforces the object
to be a Mapping instance. If the incoming yield_data is a
FissionYieldDistribution, no conversions are made. Otherwise,
a new distribution is created with the from_dict method.
The Chain.from_xml method now creates the yield_data for
nuclides using FissionYieldDistribution.from_dict
Changes were made to some unit tests that attempted to set
the yield_energies, which do not have a setter.
If the fission yields are a single entry, then
itertools.repeat is used to apply the fission yields to all
burnable materials. Otherwise, check that the number of
fission yield libraries is equal to the number of materials
to be burned.
Addition methods __add__ and __iadd__ expect the other
argument to a FissionYield object and will add
the yields from one to the other [in place for __iadd__].
Multiplication methods __imul__, __mul__, and __rmul__
expect the other argument to be a scalar and will scale
the fission yields by this value [in place for __imul__]
Also added a __repr__ method that returns a dictionary-like
representation
Closes#1308 by providing a way to validate the contents of
the depletion chain. This method iterates over all the nuclides
and calls their validation method with the same input arguments,
(strict, quiet, and tolerance). For the case where
strict == False, quiet == False, and a nuclide fails the validation,
the method returns early rather than continuing to iterate over all
other nuclides. Type and value checking are also done on the
tolerance argument.
Two tests were added to test_deplete_chain.py
The more interesting test works with the simple chain and various
manipulations to check the robustness of the method.
The other just checks the type and value checking on tolerance.
Method Nuclide.validate traverses over decay mode and reaction lists,
as well as all fission yield data to check for inconsistencies.
The following checks are performed:
1) For all non-fission reactions and decay modes, do the sum of
branching ratios equal about 1?
2) For fission reactions, do the sum of fission yield
fractions equal about 2?
Users are allowed to supply three control arguments:
- strict: bool that controls if errors are raised [True] or
warnings [False]
- quiet: bool that controls if warnings are printed [False] or
supressed [True]
- tolerance: float that provides some wiggle room on the comparisons
``y - tol <= x <= y + tol``
The method returns a boolean if 1) no inconsistencies were found and
strict evaluates to True, 2) strict evaluates to False regardless of
quiet. If ``strict`` evaluates to False and ``quiet``
evaluates to True, the method will return at the first inconsistency.
No type checking is done because this will potentially be called
by ``openmc.deplete.Chain`` for many nuclides as the primary
entry point. Type and value checking will be done there.
A unit test was added that creates a valid nuclide, and then
strategically invalidates it to check for the various exceptions
and error messages.
Create an empty matrix to fit energy-dependent fission
rates for [materials, energies, nuclides].
Use the nonzero method on total fission rate to find
indicies along the first and last axis for non-zero total
fission rate. Populate corresponding fractional fission
rates by dividing group fission rates by total fission rate,
using the indices for materials and nuclides with non-zero
total fission rate.
Use numpy.where to find where total fission rate is zero,
and directly set these locations to zero in the final
result matrix.
Also clean up some lint in openmc.deplete.nuclide related to
old variable names and unused imports.
Add two new classes for working with fission yield data
on the Chain. The primary class is FissionYieldDistribution.
This class stores distributions for one nuclide with
potentially many energies, with the assumption that the
products don't change __too__ much across energy.
Looking at the CASL chain and one generated by ENDF data,
this appears to be the case. Most distributions are
"full" in the sense that energies produce the same products.
There are some cases where one or two products may not
exist for a given energy.
The FissionYieldDistribution retains a dictionary-like behavior,
e.g. d[0.0253]["Xe135"] is a valid command and returns the
yield for Xe-135 at a "thermal" spectrum, due to yields provided
at 0.0253 eV. This is done with a helper class, _FissionYield,
implemented first to support this behavior, but also to
allow vector-operations in combining fission yields.
These _FissionYield objects store the same product vector and
a view into the underlying yield_matrix for a single energy.
To support simple weighting of yields, the __mull__ and
__iadd__ methods are implemented. A copy method is provided
to remove the chance of modifying the original yield data.
test_deplete_chain and test_deplete_nuclide have been modified
in order to utilize these classes, without ruining the validity
of the tests. Tests for the view / copy methods and vector
operations on _FissionYield objects are included.