Source code for openmc.data.energy_distribution

from abc import ABC, abstractmethod
from collections.abc import Iterable
from numbers import Integral, Real
from warnings import warn

import numpy as np

import openmc.checkvalue as cv
from openmc.mixin import EqualityMixin
from openmc.stats.univariate import Univariate, Tabular, Discrete, Mixture
from .data import EV_PER_MEV
from .endf import get_tab1_record, get_tab2_record
from .function import Tabulated1D, INTERPOLATION_SCHEME


[docs]class EnergyDistribution(EqualityMixin, ABC): """Abstract superclass for all energy distributions.""" def __init__(self): pass @abstractmethod def to_hdf5(self, group): pass
[docs] @staticmethod def from_hdf5(group): """Generate energy distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.EnergyDistribution Energy distribution """ energy_type = group.attrs['type'].decode() if energy_type == 'maxwell': return MaxwellEnergy.from_hdf5(group) elif energy_type == 'evaporation': return Evaporation.from_hdf5(group) elif energy_type == 'watt': return WattEnergy.from_hdf5(group) elif energy_type == 'madland-nix': return MadlandNix.from_hdf5(group) elif energy_type == 'discrete_photon': return DiscretePhoton.from_hdf5(group) elif energy_type == 'level': return LevelInelastic.from_hdf5(group) elif energy_type == 'continuous': return ContinuousTabular.from_hdf5(group) else: raise ValueError("Unknown energy distribution type: {}" .format(energy_type))
[docs] @staticmethod def from_endf(file_obj, params): """Generate energy distribution from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.EnergyDistribution A sub-class of :class:`openmc.data.EnergyDistribution` """ lf = params[3] if lf == 1: return ArbitraryTabulated.from_endf(file_obj, params) elif lf == 5: return GeneralEvaporation.from_endf(file_obj, params) elif lf == 7: return MaxwellEnergy.from_endf(file_obj, params) elif lf == 9: return Evaporation.from_endf(file_obj, params) elif lf == 11: return WattEnergy.from_endf(file_obj, params) elif lf == 12: return MadlandNix.from_endf(file_obj, params)
[docs]class ArbitraryTabulated(EnergyDistribution): r"""Arbitrary tabulated function given in ENDF MF=5, LF=1 represented as .. math:: f(E \rightarrow E') = g(E \rightarrow E') Parameters ---------- energy : numpy.ndarray Array of incident neutron energies pdf : list of openmc.data.Tabulated1D Tabulated outgoing energy distribution probability density functions Attributes ---------- energy : numpy.ndarray Array of incident neutron energies pdf : list of openmc.data.Tabulated1D Tabulated outgoing energy distribution probability density functions """ def __init__(self, energy, pdf): super().__init__() self.energy = energy self.pdf = pdf def to_hdf5(self, group): raise NotImplementedError
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate arbitrary tabulated distribution from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.ArbitraryTabulated Arbitrary tabulated distribution """ params, tab2 = get_tab2_record(file_obj) n_energies = params[5] energy = np.zeros(n_energies) pdf = [] for j in range(n_energies): params, func = get_tab1_record(file_obj) energy[j] = params[1] pdf.append(func) return cls(energy, pdf)
[docs]class GeneralEvaporation(EnergyDistribution): r"""General evaporation spectrum given in ENDF MF=5, LF=5 represented as .. math:: f(E \rightarrow E') = g(E'/\theta(E)) Parameters ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy :math:`E` g : openmc.data.Tabulated1D Tabulated function of :math:`x = E'/\theta(E)` u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` Attributes ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy :math:`E` g : openmc.data.Tabulated1D Tabulated function of :math:`x = E'/\theta(E)` u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` """ def __init__(self, theta, g, u): super().__init__() self.theta = theta self.g = g self.u = u def to_hdf5(self, group): raise NotImplementedError @classmethod def from_ace(cls, ace, idx=0): raise NotImplementedError
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate general evaporation spectrum from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.GeneralEvaporation General evaporation spectrum """ u = params[0] params, theta = get_tab1_record(file_obj) params, g = get_tab1_record(file_obj) return cls(theta, g, u)
[docs]class MaxwellEnergy(EnergyDistribution): r"""Simple Maxwellian fission spectrum represented as .. math:: f(E \rightarrow E') = \frac{\sqrt{E'}}{I} e^{-E'/\theta(E)} Parameters ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` Attributes ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` """ def __init__(self, theta, u): super().__init__() self.theta = theta self.u = u @property def theta(self): return self._theta @property def u(self): return self._u @theta.setter def theta(self, theta): cv.check_type('Maxwell theta', theta, Tabulated1D) self._theta = theta @u.setter def u(self, u): cv.check_type('Maxwell restriction energy', u, Real) self._u = u
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('maxwell') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta')
[docs] @classmethod def from_hdf5(cls, group): """Generate Maxwell distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.MaxwellEnergy Maxwell distribution """ theta = Tabulated1D.from_hdf5(group['theta']) u = group.attrs['u'] return cls(theta, u)
[docs] @classmethod def from_ace(cls, ace, idx=0): """Create a Maxwell distribution from an ACE table Parameters ---------- ace : openmc.data.ace.Table An ACE table idx : int Offset to read from in XSS array (default of zero) Returns ------- openmc.data.MaxwellEnergy Maxwell distribution """ # Read nuclear temperature -- since units are MeV, convert to eV theta = Tabulated1D.from_ace(ace, idx) theta.y *= EV_PER_MEV # Restriction energy nr = int(ace.xss[idx]) ne = int(ace.xss[idx + 1 + 2*nr]) u = ace.xss[idx + 2 + 2*nr + 2*ne]*EV_PER_MEV return cls(theta, u)
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate Maxwell distribution from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.MaxwellEnergy Maxwell distribution """ u = params[0] params, theta = get_tab1_record(file_obj) return cls(theta, u)
[docs]class Evaporation(EnergyDistribution): r"""Evaporation spectrum represented as .. math:: f(E \rightarrow E') = \frac{E'}{I} e^{-E'/\theta(E)} Parameters ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` Attributes ---------- theta : openmc.data.Tabulated1D Tabulated function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` """ def __init__(self, theta, u): super().__init__() self.theta = theta self.u = u @property def theta(self): return self._theta @property def u(self): return self._u @theta.setter def theta(self, theta): cv.check_type('Evaporation theta', theta, Tabulated1D) self._theta = theta @u.setter def u(self, u): cv.check_type('Evaporation restriction energy', u, Real) self._u = u
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('evaporation') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta')
[docs] @classmethod def from_hdf5(cls, group): """Generate evaporation spectrum from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.Evaporation Evaporation spectrum """ theta = Tabulated1D.from_hdf5(group['theta']) u = group.attrs['u'] return cls(theta, u)
[docs] @classmethod def from_ace(cls, ace, idx=0): """Create an evaporation spectrum from an ACE table Parameters ---------- ace : openmc.data.ace.Table An ACE table idx : int Offset to read from in XSS array (default of zero) Returns ------- openmc.data.Evaporation Evaporation spectrum """ # Read nuclear temperature -- since units are MeV, convert to eV theta = Tabulated1D.from_ace(ace, idx) theta.y *= EV_PER_MEV # Restriction energy nr = int(ace.xss[idx]) ne = int(ace.xss[idx + 1 + 2*nr]) u = ace.xss[idx + 2 + 2*nr + 2*ne]*EV_PER_MEV return cls(theta, u)
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate evaporation spectrum from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.Evaporation Evaporation spectrum """ u = params[0] params, theta = get_tab1_record(file_obj) return cls(theta, u)
[docs]class WattEnergy(EnergyDistribution): r"""Energy-dependent Watt spectrum represented as .. math:: f(E \rightarrow E') = \frac{e^{-E'/a}}{I} \sinh \left ( \sqrt{bE'} \right ) Parameters ---------- a, b : openmc.data.Tabulated1D Energy-dependent parameters tabulated as function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` Attributes ---------- a, b : openmc.data.Tabulated1D Energy-dependent parameters tabulated as function of incident neutron energy u : float Constant introduced to define the proper upper limit for the final particle energy such that :math:`0 \le E' \le E - U` """ def __init__(self, a, b, u): super().__init__() self.a = a self.b = b self.u = u @property def a(self): return self._a @property def b(self): return self._b @property def u(self): return self._u @a.setter def a(self, a): cv.check_type('Watt a', a, Tabulated1D) self._a = a @b.setter def b(self, b): cv.check_type('Watt b', b, Tabulated1D) self._b = b @u.setter def u(self, u): cv.check_type('Watt restriction energy', u, Real) self._u = u
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('watt') group.attrs['u'] = self.u self.a.to_hdf5(group, 'a') self.b.to_hdf5(group, 'b')
[docs] @classmethod def from_hdf5(cls, group): """Generate Watt fission spectrum from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.WattEnergy Watt fission spectrum """ a = Tabulated1D.from_hdf5(group['a']) b = Tabulated1D.from_hdf5(group['b']) u = group.attrs['u'] return cls(a, b, u)
[docs] @classmethod def from_ace(cls, ace, idx): """Create a Watt fission spectrum from an ACE table Parameters ---------- ace : openmc.data.ace.Table An ACE table idx : int Offset to read from in XSS array (default of zero) Returns ------- openmc.data.WattEnergy Watt fission spectrum """ # Energy-dependent a parameter -- units are MeV, convert to eV a = Tabulated1D.from_ace(ace, idx) a.y *= EV_PER_MEV # Advance index nr = int(ace.xss[idx]) ne = int(ace.xss[idx + 1 + 2*nr]) idx += 2 + 2*nr + 2*ne # Energy-dependent b parameter -- units are MeV^-1 b = Tabulated1D.from_ace(ace, idx) b.y /= EV_PER_MEV # Advance index nr = int(ace.xss[idx]) ne = int(ace.xss[idx + 1 + 2*nr]) idx += 2 + 2*nr + 2*ne # Restriction energy u = ace.xss[idx]*EV_PER_MEV return cls(a, b, u)
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate Watt fission spectrum from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.WattEnergy Watt fission spectrum """ u = params[0] params, a = get_tab1_record(file_obj) params, b = get_tab1_record(file_obj) return cls(a, b, u)
[docs]class MadlandNix(EnergyDistribution): r"""Energy-dependent fission neutron spectrum (Madland and Nix) given in ENDF MF=5, LF=12 represented as .. math:: f(E \rightarrow E') = \frac{1}{2} [ g(E', E_F(L)) + g(E', E_F(H))] where .. math:: g(E',E_F) = \frac{1}{3\sqrt{E_F T_M}} \left [ u_2^{3/2} E_1 (u_2) - u_1^{3/2} E_1 (u_1) + \gamma \left ( \frac{3}{2}, u_2 \right ) - \gamma \left ( \frac{3}{2}, u_1 \right ) \right ] \\ u_1 = \left ( \sqrt{E'} - \sqrt{E_F} \right )^2 / T_M \\ u_2 = \left ( \sqrt{E'} + \sqrt{E_F} \right )^2 / T_M. Parameters ---------- efl, efh : float Constants which represent the average kinetic energy per nucleon of the fission fragment (efl = light, efh = heavy) tm : openmc.data.Tabulated1D Parameter tabulated as a function of incident neutron energy Attributes ---------- efl, efh : float Constants which represent the average kinetic energy per nucleon of the fission fragment (efl = light, efh = heavy) tm : openmc.data.Tabulated1D Parameter tabulated as a function of incident neutron energy """ def __init__(self, efl, efh, tm): super().__init__() self.efl = efl self.efh = efh self.tm = tm @property def efl(self): return self._efl @property def efh(self): return self._efh @property def tm(self): return self._tm @efl.setter def efl(self, efl): name = 'Madland-Nix light fragment energy' cv.check_type(name, efl, Real) cv.check_greater_than(name, efl, 0.) self._efl = efl @efh.setter def efh(self, efh): name = 'Madland-Nix heavy fragment energy' cv.check_type(name, efh, Real) cv.check_greater_than(name, efh, 0.) self._efh = efh @tm.setter def tm(self, tm): cv.check_type('Madland-Nix maximum temperature', tm, Tabulated1D) self._tm = tm
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('madland-nix') group.attrs['efl'] = self.efl group.attrs['efh'] = self.efh self.tm.to_hdf5(group)
[docs] @classmethod def from_hdf5(cls, group): """Generate Madland-Nix fission spectrum from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.MadlandNix Madland-Nix fission spectrum """ efl = group.attrs['efl'] efh = group.attrs['efh'] tm = Tabulated1D.from_hdf5(group['tm']) return cls(efl, efh, tm)
[docs] @classmethod def from_endf(cls, file_obj, params): """Generate Madland-Nix fission spectrum from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for an energy distribution. params : list List of parameters at the start of the energy distribution that includes the LF value indicating what type of energy distribution is present. Returns ------- openmc.data.MadlandNix Madland-Nix fission spectrum """ params, tm = get_tab1_record(file_obj) efl, efh = params[0:2] return cls(efl, efh, tm)
[docs]class DiscretePhoton(EnergyDistribution): """Discrete photon energy distribution Parameters ---------- primary_flag : int Indicator of whether the photon is a primary or non-primary photon. energy : float Photon energy (if lp==0 or lp==1) or binding energy (if lp==2). atomic_weight_ratio : float Atomic weight ratio of the target nuclide responsible for the emitted particle Attributes ---------- primary_flag : int Indicator of whether the photon is a primary or non-primary photon. energy : float Photon energy (if lp==0 or lp==1) or binding energy (if lp==2). atomic_weight_ratio : float Atomic weight ratio of the target nuclide responsible for the emitted particle """ def __init__(self, primary_flag, energy, atomic_weight_ratio): super().__init__() self.primary_flag = primary_flag self.energy = energy self.atomic_weight_ratio = atomic_weight_ratio @property def primary_flag(self): return self._primary_flag @property def energy(self): return self._energy @property def atomic_weight_ratio(self): return self._atomic_weight_ratio @primary_flag.setter def primary_flag(self, primary_flag): cv.check_type('discrete photon primary_flag', primary_flag, Integral) self._primary_flag = primary_flag @energy.setter def energy(self, energy): cv.check_type('discrete photon energy', energy, Real) self._energy = energy @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) self._atomic_weight_ratio = atomic_weight_ratio
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('discrete_photon') group.attrs['primary_flag'] = self.primary_flag group.attrs['energy'] = self.energy group.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio
[docs] @classmethod def from_hdf5(cls, group): """Generate discrete photon energy distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.DiscretePhoton Discrete photon energy distribution """ primary_flag = group.attrs['primary_flag'] energy = group.attrs['energy'] awr = group.attrs['atomic_weight_ratio'] return cls(primary_flag, energy, awr)
[docs] @classmethod def from_ace(cls, ace, idx): """Generate discrete photon energy distribution from an ACE table Parameters ---------- ace : openmc.data.ace.Table An ACE table idx : int Offset to read from in XSS array (default of zero) Returns ------- openmc.data.DiscretePhoton Discrete photon energy distribution """ primary_flag = int(ace.xss[idx]) energy = ace.xss[idx + 1]*EV_PER_MEV return cls(primary_flag, energy, ace.atomic_weight_ratio)
[docs]class LevelInelastic(EnergyDistribution): r"""Level inelastic scattering Parameters ---------- threshold : float Energy threshold in the laboratory system, :math:`(A + 1)/A * |Q|` mass_ratio : float :math:`(A/(A + 1))^2` Attributes ---------- threshold : float Energy threshold in the laboratory system, :math:`(A + 1)/A * |Q|` mass_ratio : float :math:`(A/(A + 1))^2` """ def __init__(self, threshold, mass_ratio): super().__init__() self.threshold = threshold self.mass_ratio = mass_ratio @property def threshold(self): return self._threshold @property def mass_ratio(self): return self._mass_ratio @threshold.setter def threshold(self, threshold): cv.check_type('level inelastic threhsold', threshold, Real) self._threshold = threshold @mass_ratio.setter def mass_ratio(self, mass_ratio): cv.check_type('level inelastic mass ratio', mass_ratio, Real) self._mass_ratio = mass_ratio
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('level') group.attrs['threshold'] = self.threshold group.attrs['mass_ratio'] = self.mass_ratio
[docs] @classmethod def from_hdf5(cls, group): """Generate level inelastic distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.LevelInelastic Level inelastic scattering distribution """ threshold = group.attrs['threshold'] mass_ratio = group.attrs['mass_ratio'] return cls(threshold, mass_ratio)
[docs] @classmethod def from_ace(cls, ace, idx): """Generate level inelastic distribution from an ACE table Parameters ---------- ace : openmc.data.ace.Table An ACE table idx : int Offset to read from in XSS array (default of zero) Returns ------- openmc.data.LevelInelastic Level inelastic scattering distribution """ threshold = ace.xss[idx]*EV_PER_MEV mass_ratio = ace.xss[idx + 1] return cls(threshold, mass_ratio)
[docs]class ContinuousTabular(EnergyDistribution): """Continuous tabular distribution Parameters ---------- breakpoints : Iterable of int Breakpoints defining interpolation regions interpolation : Iterable of int Interpolation codes energy : Iterable of float Incoming energies at which distributions exist energy_out : Iterable of openmc.stats.Univariate Distribution of outgoing energies corresponding to each incoming energy Attributes ---------- breakpoints : Iterable of int Breakpoints defining interpolation regions interpolation : Iterable of int Interpolation codes energy : Iterable of float Incoming energies at which distributions exist energy_out : Iterable of openmc.stats.Univariate Distribution of outgoing energies corresponding to each incoming energy """ def __init__(self, breakpoints, interpolation, energy, energy_out): super().__init__() self.breakpoints = breakpoints self.interpolation = interpolation self.energy = energy self.energy_out = energy_out @property def breakpoints(self): return self._breakpoints @property def interpolation(self): return self._interpolation @property def energy(self): return self._energy @property def energy_out(self): return self._energy_out @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('continuous tabular breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints @interpolation.setter def interpolation(self, interpolation): cv.check_type('continuous tabular interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation @energy.setter def energy(self, energy): cv.check_type('continuous tabular incoming energy', energy, Iterable, Real) self._energy = energy @energy_out.setter def energy_out(self, energy_out): cv.check_type('continuous tabular outgoing energy', energy_out, Iterable, Univariate) self._energy_out = energy_out
[docs] def to_hdf5(self, group): """Write distribution to an HDF5 group Parameters ---------- group : h5py.Group HDF5 group to write to """ group.attrs['type'] = np.string_('continuous') dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, self.interpolation)) # Determine total number of (E,p) pairs and create array n_pairs = sum(len(d) for d in self.energy_out) pairs = np.empty((3, n_pairs)) # Create array for offsets offsets = np.empty(len(self.energy_out), dtype=int) interpolation = np.empty(len(self.energy_out), dtype=int) n_discrete_lines = np.empty(len(self.energy_out), dtype=int) j = 0 # Populate offsets and pairs array for i, eout in enumerate(self.energy_out): n = len(eout) offsets[i] = j if isinstance(eout, Mixture): discrete, continuous = eout.distribution n_discrete_lines[i] = m = len(discrete) interpolation[i] = 1 if continuous.interpolation == 'histogram' else 2 pairs[0, j:j+m] = discrete.x pairs[1, j:j+m] = discrete.p pairs[2, j:j+m] = discrete.c pairs[0, j+m:j+n] = continuous.x pairs[1, j+m:j+n] = continuous.p pairs[2, j+m:j+n] = continuous.c else: if isinstance(eout, Tabular): n_discrete_lines[i] = 0 interpolation[i] = 1 if eout.interpolation == 'histogram' else 2 elif isinstance(eout, Discrete): n_discrete_lines[i] = n interpolation[i] = 1 pairs[0, j:j+n] = eout.x pairs[1, j:j+n] = eout.p pairs[2, j:j+n] = eout.c j += n # Create dataset for distributions dset = group.create_dataset('distribution', data=pairs) # Write interpolation as attribute dset.attrs['offsets'] = offsets dset.attrs['interpolation'] = interpolation dset.attrs['n_discrete_lines'] = n_discrete_lines
[docs] @classmethod def from_hdf5(cls, group): """Generate continuous tabular distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.ContinuousTabular Continuous tabular energy distribution """ interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] n_discrete_lines = data.attrs['n_discrete_lines'] energy_out = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines j = offsets[i] if i < n_energy - 1: n = offsets[i+1] - j else: n = data.shape[1] - j m = n_discrete_lines[i] # Create discrete distribution if lines are present if m > 0: eout_discrete = Discrete(data[0, j:j+m], data[1, j:j+m]) eout_discrete.c = data[2, j:j+m] p_discrete = eout_discrete.c[-1] # Create continuous distribution if m < n: interp = INTERPOLATION_SCHEME[interpolation[i]] eout_continuous = Tabular(data[0, j+m:j+n], data[1, j+m:j+n], interp) eout_continuous.c = data[2, j+m:j+n] # If both continuous and discrete are present, create a mixture # distribution if m == 0: eout_i = eout_continuous elif m == n: eout_i = eout_discrete else: eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) energy_out.append(eout_i) return cls(energy_breakpoints, energy_interpolation, energy, energy_out)
[docs] @classmethod def from_ace(cls, ace, idx, ldis): """Generate continuous tabular energy distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from idx : int Index in XSS array of the start of the energy distribution data (LDIS + LOCC - 1) ldis : int Index in XSS array of the start of the energy distribution block (e.g. JXS[11]) Returns ------- openmc.data.ContinuousTabular Continuous tabular energy distribution """ # Read number of interpolation regions and incoming energies n_regions = int(ace.xss[idx]) n_energy_in = int(ace.xss[idx + 1 + 2*n_regions]) # Get interpolation information idx += 1 if n_regions > 0: breakpoints = ace.xss[idx:idx + n_regions].astype(int) interpolation = ace.xss[idx + n_regions:idx + 2*n_regions].astype(int) else: breakpoints = np.array([n_energy_in]) interpolation = np.array([2]) # Incoming energies at which distributions exist idx += 2*n_regions + 1 energy = ace.xss[idx:idx + n_energy_in]*EV_PER_MEV # Location of distributions idx += n_energy_in loc_dist = ace.xss[idx:idx + n_energy_in].astype(int) # Initialize variables energy_out = [] # Read each outgoing energy distribution for i in range(n_energy_in): idx = ldis + loc_dist[i] - 1 # intt = interpolation scheme (1=hist, 2=lin-lin) INTTp = int(ace.xss[idx]) intt = INTTp % 10 n_discrete_lines = (INTTp - intt)//10 if intt not in (1, 2): warn("Interpolation scheme for continuous tabular distribution " "is not histogram or linear-linear.") intt = 2 n_energy_out = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 3*n_energy_out].copy() data.shape = (3, n_energy_out) data[0,:] *= EV_PER_MEV # Create continuous distribution eout_continuous = Tabular(data[0][n_discrete_lines:], data[1][n_discrete_lines:]/EV_PER_MEV, INTERPOLATION_SCHEME[intt]) eout_continuous.c = data[2][n_discrete_lines:] # If discrete lines are present, create a mixture distribution if n_discrete_lines > 0: eout_discrete = Discrete(data[0][:n_discrete_lines], data[1][:n_discrete_lines]) eout_discrete.c = data[2][:n_discrete_lines] if n_discrete_lines == n_energy_out: eout_i = eout_discrete else: p_discrete = min(sum(eout_discrete.p), 1.0) eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) else: eout_i = eout_continuous energy_out.append(eout_i) return cls(breakpoints, interpolation, energy, energy_out)