2018-02-02 10:06:45 -06:00
|
|
|
from collections.abc import Iterable
|
2016-05-13 15:57:39 -05:00
|
|
|
from numbers import Real
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
import openmc.checkvalue as cv
|
2016-08-19 06:58:17 -04:00
|
|
|
from openmc.mixin import EqualityMixin
|
2016-05-13 15:57:39 -05:00
|
|
|
from .angle_energy import AngleEnergy
|
2016-02-24 11:01:12 -06:00
|
|
|
from .function import Tabulated1D, Polynomial, Function1D
|
2016-05-13 15:57:39 -05:00
|
|
|
|
|
|
|
|
|
2016-08-19 06:58:17 -04:00
|
|
|
class Product(EqualityMixin):
|
2016-05-13 15:57:39 -05:00
|
|
|
"""Secondary particle emitted in a nuclear reaction
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
particle : str, optional
|
2019-12-05 22:22:43 -06:00
|
|
|
The particle type of the reaction product. Defaults to 'neutron'.
|
2016-05-13 15:57:39 -05:00
|
|
|
|
|
|
|
|
Attributes
|
|
|
|
|
----------
|
|
|
|
|
applicability : Iterable of openmc.data.Tabulated1D
|
|
|
|
|
Probability of sampling a given distribution for this product.
|
|
|
|
|
decay_rate : float
|
|
|
|
|
Decay rate in inverse seconds
|
|
|
|
|
distribution : Iterable of openmc.data.AngleEnergy
|
|
|
|
|
Distributions of energy and angle of product.
|
|
|
|
|
emission_mode : {'prompt', 'delayed', 'total'}
|
|
|
|
|
Indicate whether the particle is emitted immediately or whether it
|
|
|
|
|
results from the decay of reaction product (e.g., neutron emitted from a
|
|
|
|
|
delayed neutron precursor). A special value of 'total' is used when the
|
|
|
|
|
yield represents particles from prompt and delayed sources.
|
|
|
|
|
particle : str
|
2020-04-15 06:49:14 -05:00
|
|
|
The particle type of the reaction product
|
2016-08-08 10:06:02 -05:00
|
|
|
yield_ : openmc.data.Function1D
|
2016-05-13 15:57:39 -05:00
|
|
|
Yield of secondary particle in the reaction.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, particle='neutron'):
|
2020-04-15 06:49:14 -05:00
|
|
|
self.applicability = []
|
2016-05-13 15:57:39 -05:00
|
|
|
self.decay_rate = 0.0
|
|
|
|
|
self.distribution = []
|
2020-04-15 06:49:14 -05:00
|
|
|
self.emission_mode = 'prompt'
|
|
|
|
|
self.particle = particle
|
|
|
|
|
self.yield_ = Polynomial((1,)) # 0-order polynomial, i.e., a constant
|
2016-05-13 15:57:39 -05:00
|
|
|
|
|
|
|
|
def __repr__(self):
|
2020-04-15 06:49:14 -05:00
|
|
|
if isinstance(self.yield_, Tabulated1D):
|
2016-05-13 15:57:39 -05:00
|
|
|
if np.all(self.yield_.y == self.yield_.y[0]):
|
|
|
|
|
return "<Product: {}, emission={}, yield={}>".format(
|
|
|
|
|
self.particle, self.emission_mode, self.yield_.y[0])
|
|
|
|
|
else:
|
|
|
|
|
return "<Product: {}, emission={}, yield=tabulated>".format(
|
|
|
|
|
self.particle, self.emission_mode)
|
|
|
|
|
else:
|
|
|
|
|
return "<Product: {}, emission={}, yield=polynomial>".format(
|
|
|
|
|
self.particle, self.emission_mode)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def applicability(self):
|
|
|
|
|
return self._applicability
|
|
|
|
|
|
|
|
|
|
@applicability.setter
|
|
|
|
|
def applicability(self, applicability):
|
|
|
|
|
cv.check_type('product distribution applicability', applicability,
|
|
|
|
|
Iterable, Tabulated1D)
|
|
|
|
|
self._applicability = applicability
|
|
|
|
|
|
2023-06-17 04:34:02 +01:00
|
|
|
@property
|
|
|
|
|
def decay_rate(self):
|
|
|
|
|
return self._decay_rate
|
|
|
|
|
|
2016-05-13 15:57:39 -05:00
|
|
|
@decay_rate.setter
|
|
|
|
|
def decay_rate(self, decay_rate):
|
|
|
|
|
cv.check_type('product decay rate', decay_rate, Real)
|
|
|
|
|
cv.check_greater_than('product decay rate', decay_rate, 0.0, True)
|
|
|
|
|
self._decay_rate = decay_rate
|
|
|
|
|
|
2023-06-17 04:34:02 +01:00
|
|
|
@property
|
|
|
|
|
def distribution(self):
|
|
|
|
|
return self._distribution
|
|
|
|
|
|
2016-05-13 15:57:39 -05:00
|
|
|
@distribution.setter
|
|
|
|
|
def distribution(self, distribution):
|
|
|
|
|
cv.check_type('product angle-energy distribution', distribution,
|
|
|
|
|
Iterable, AngleEnergy)
|
|
|
|
|
self._distribution = distribution
|
|
|
|
|
|
2023-06-17 04:34:02 +01:00
|
|
|
@property
|
|
|
|
|
def emission_mode(self):
|
|
|
|
|
return self._emission_mode
|
|
|
|
|
|
2016-05-13 15:57:39 -05:00
|
|
|
@emission_mode.setter
|
|
|
|
|
def emission_mode(self, emission_mode):
|
|
|
|
|
cv.check_value('product emission mode', emission_mode,
|
|
|
|
|
('prompt', 'delayed', 'total'))
|
|
|
|
|
self._emission_mode = emission_mode
|
|
|
|
|
|
2023-06-17 04:34:02 +01:00
|
|
|
@property
|
|
|
|
|
def particle(self):
|
|
|
|
|
return self._particle
|
|
|
|
|
|
2016-05-13 15:57:39 -05:00
|
|
|
@particle.setter
|
|
|
|
|
def particle(self, particle):
|
2017-12-24 16:06:05 +07:00
|
|
|
cv.check_type('product particle type', particle, str)
|
2016-05-13 15:57:39 -05:00
|
|
|
self._particle = particle
|
|
|
|
|
|
2023-06-17 04:34:02 +01:00
|
|
|
@property
|
|
|
|
|
def yield_(self):
|
|
|
|
|
return self._yield
|
|
|
|
|
|
2016-05-13 15:57:39 -05:00
|
|
|
@yield_.setter
|
|
|
|
|
def yield_(self, yield_):
|
2016-08-08 10:06:02 -05:00
|
|
|
cv.check_type('product yield', yield_, Function1D)
|
2016-05-13 15:57:39 -05:00
|
|
|
self._yield = yield_
|
|
|
|
|
|
|
|
|
|
def to_hdf5(self, group):
|
|
|
|
|
"""Write product to an HDF5 group
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
group : h5py.Group
|
|
|
|
|
HDF5 group to write to
|
|
|
|
|
|
|
|
|
|
"""
|
2024-03-26 11:00:06 -05:00
|
|
|
group.attrs['particle'] = np.bytes_(self.particle)
|
|
|
|
|
group.attrs['emission_mode'] = np.bytes_(self.emission_mode)
|
2016-05-13 15:57:39 -05:00
|
|
|
if self.decay_rate > 0.0:
|
|
|
|
|
group.attrs['decay_rate'] = self.decay_rate
|
|
|
|
|
|
|
|
|
|
# Write yield
|
2016-08-05 13:48:12 -05:00
|
|
|
self.yield_.to_hdf5(group, 'yield')
|
2016-05-13 15:57:39 -05:00
|
|
|
|
|
|
|
|
# Write applicability/distribution
|
|
|
|
|
group.attrs['n_distribution'] = len(self.distribution)
|
|
|
|
|
for i, d in enumerate(self.distribution):
|
2024-04-29 22:45:37 +01:00
|
|
|
dgroup = group.create_group(f'distribution_{i}')
|
2016-05-13 15:57:39 -05:00
|
|
|
if self.applicability:
|
|
|
|
|
self.applicability[i].to_hdf5(dgroup, 'applicability')
|
|
|
|
|
d.to_hdf5(dgroup)
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def from_hdf5(cls, group):
|
|
|
|
|
"""Generate reaction product from HDF5 data
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
group : h5py.Group
|
|
|
|
|
HDF5 group to read from
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
openmc.data.Product
|
|
|
|
|
Reaction product
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
particle = group.attrs['particle'].decode()
|
|
|
|
|
p = cls(particle)
|
|
|
|
|
|
|
|
|
|
p.emission_mode = group.attrs['emission_mode'].decode()
|
|
|
|
|
if 'decay_rate' in group.attrs:
|
|
|
|
|
p.decay_rate = group.attrs['decay_rate']
|
|
|
|
|
|
|
|
|
|
# Read yield
|
2016-08-05 13:48:12 -05:00
|
|
|
p.yield_ = Function1D.from_hdf5(group['yield'])
|
2016-05-13 15:57:39 -05:00
|
|
|
|
|
|
|
|
# Read applicability/distribution
|
|
|
|
|
n_distribution = group.attrs['n_distribution']
|
|
|
|
|
distribution = []
|
|
|
|
|
applicability = []
|
|
|
|
|
for i in range(n_distribution):
|
2024-04-29 22:45:37 +01:00
|
|
|
dgroup = group[f'distribution_{i}']
|
2016-05-13 15:57:39 -05:00
|
|
|
if 'applicability' in dgroup:
|
|
|
|
|
applicability.append(Tabulated1D.from_hdf5(
|
|
|
|
|
dgroup['applicability']))
|
|
|
|
|
distribution.append(AngleEnergy.from_hdf5(dgroup))
|
|
|
|
|
|
|
|
|
|
p.distribution = distribution
|
|
|
|
|
p.applicability = applicability
|
|
|
|
|
|
|
|
|
|
return p
|