"""Module for parsing and manipulating data from ENDL evaluations.
For the moment, classes and functions in this module only implement the
specifications relevant to the EEDL (Evaluated Electron Data Library) and the
EPDL (Evaluated Photon Data Library). The formats are described by the
following documents:
"ENDL type formats for the Livermore Evaluated Photon Data Library, EPDL"
https://www.oecd-nea.org/dbdata/data/manual-endf/nds_eval_epdl.pdf
"ENDL type formats for the Livermore Evaluated Electron Data Library, EEDL"
https://www.oecd-nea.org/dbdata/data/manual-endf/nds_eval_eedl.pdf
For more information, contact Davide Mancusi <davide.mancusi@cea.fr>.
"""
from __future__ import print_function, division, unicode_literals
import re
import sys
try:
from collections.abc import namedtuple, defaultdict
except ImportError:
from collections import namedtuple, defaultdict
import numpy as np
from pyne.utils import QA_warn
from pyne import rxdata
import pyne.utils as utils
from pyne import nucname
QA_warn(__name__)
if sys.version_info[0] > 2:
basestring = str
END_OF_TABLE_RE = re.compile(' {71}1')
DataTuple = namedtuple('DataTuple', ['yo', 'limits', 'x1'])
NFIELDS_RPROP = {
0: 2,
10: 2,
11: 2,
21: 3,
22: 3
}
[docs]class Library(rxdata.RxLib):
"""A class for a file which contains multiple ENDL tables."""
@staticmethod
def _structure_dict_entry():
"""Static method to generate entries for the structure dict."""
return {
'pin': set(),
'rdesc': set(),
'rprop': set(),
'pin_rdesc_rprop': defaultdict(
lambda: {'data_tuples': []}
)
}
def __init__(self, fh):
self.structure = defaultdict(Library._structure_dict_entry)
self.intdict = {
0: self._linlin,
2: self._linlin,
3: self._loglin,
4: self._linlog,
5: self._loglog,
}
self.fh = fh
# read headers for all tables
self._read_headers()
def _read_headers(self):
"""Read all the table headers from an ENDL file."""
opened_here = False
if isinstance(self.fh, basestring):
fh = open(self.fh, 'r')
opened_here = True
else:
fh = self.fh
while True:
# get header lines
line1 = fh.readline()
line2 = fh.readline()
# EOF?
if len(line2) == 0:
break
# store the start of the table
start = fh.tell()
# parse the first header line
nuc_zzzaaa = int(line1[0:6].strip())
yi = int(line1[7:9].strip() or -1)
yo = int(line1[10:12].strip() or -1)
aw_str = line1[13:24]
aw = utils.endftod(aw_str) if aw_str else np.float64(-1.)
date = line1[25:31].strip()
iflag = int(line1[31].strip() or 0)
# parse the second header line
rdesc = int(line2[0:2].strip() or -1)
rprop = int(line2[2:5].strip() or -1)
rmod = int(line2[5:8].strip() or -1)
x1_str = line2[21:32]
x1 = int(utils.endftod(x1_str or -1.))
# convert to Pyne native formats
nuc = nucname.zzzaaa_to_id(nuc_zzzaaa)
# skip to the end of the table
read_eot = False
while not read_eot:
stop = fh.tell()
line = fh.readline()
read_eot = (len(line) == 0 or END_OF_TABLE_RE.match(line))
# insert the table in the self.structure dictionary
self.structure[nuc]['pin'].add(yi)
self.structure[nuc]['rdesc'].add(rdesc)
self.structure[nuc]['rprop'].add(rprop)
pdp_dict = self.structure[nuc]['pin_rdesc_rprop']
table_dict = pdp_dict[yi, rdesc, rprop]
table_dict['rmod'] = rmod
x1_in_tuple = x1 if rmod != 0 else None
data_tuple = DataTuple(
x1=x1_in_tuple,
yo=yo,
limits=(start, stop)
)
table_dict['data_tuples'].append(data_tuple)
# close the file if it was opened here
if opened_here:
fh.close()
def _linlin(self, e_int, xs, low, high):
if low is not None or high is not None:
interp = interp1d(e_int, xs)
if low in e_int:
xs = xs[e_int >= low]
e_int = e_int[e_int >= low]
elif low is not None and low > e_int[0]:
low_xs = interp(low)
xs = np.insert(xs[e_int > low], 0, low_xs)
e_int = np.insert(e_int[e_int > low], 0, low)
if high in e_int:
xs = xs[e_int <= high]
e_int = e_int[e_int <= high]
elif high is not None:
high_xs = interp(high)
xs = np.append(xs[e_int < high], high_xs)
e_int = np.append(e_int[e_int < high], high)
de_int = float(e_int[-1]-e_int[0])
return np.nansum((e_int[1:]-e_int[:-1]) * (xs[1:]+xs[:-1])/2./de_int)
def _linlog(self, e_int, xs, low, high):
if low is not None or high is not None:
interp = interp1d(np.log(e_int), xs)
if low in e_int:
xs = xs[e_int >= low]
e_int = e_int[e_int >= low]
elif low is not None and low > e_int[0]:
low_xs = interp(np.log(low))
xs = np.insert(xs[e_int > low], 0, low_xs)
e_int = np.insert(e_int[e_int > low], 0, low)
if high in e_int:
xs = xs[e_int <= high]
e_int = e_int[e_int <= high]
elif high is not None:
high_xs = interp(np.log(high))
xs = np.append(xs[e_int < high], high_xs)
e_int = np.append(e_int[e_int < high], high)
de_int = float(e_int[-1]-e_int[0])
x1 = e_int[:-1]
x2 = e_int[1:]
y1 = xs[:-1]
y2 = xs[1:]
A = (y1-y2)/(np.log(x1/x2))
B = y1-A*np.log(x1)
return np.nansum(A*(x2*np.log(x2) -
x1*np.log(x1)-x2+x1) + B*(x2-x1))/de_int
def _loglin(self, e_int, xs, low, high):
if low is not None or high is not None:
interp = interp1d(e_int, np.log(xs))
if low in e_int:
xs = xs[e_int >= low]
e_int = e_int[e_int >= low]
elif low is not None and low > e_int[0]:
low_xs = np.e ** interp(low)
xs = np.insert(xs[e_int > low], 0, low_xs)
e_int = np.insert(e_int[e_int > low], 0, low)
if high in e_int:
xs = xs[e_int <= high]
e_int = e_int[e_int <= high]
elif high is not None:
high_xs = np.e ** interp(high)
xs = np.append(xs[e_int < high], high_xs)
e_int = np.append(e_int[e_int < high], high)
de_int = float(e_int[-1]-e_int[0])
x1 = e_int[:-1]
x2 = e_int[1:]
y1 = xs[:-1]
y2 = xs[1:]
A = (np.log(y1)-np.log(y2))/(x1-x2)
B = np.log(y1) - A*x1
return np.nansum((y2-y1)/A)/de_int
def _loglog(self, e_int, xs, low, high):
if low is not None or high is not None:
interp = interp1d(np.log(e_int), np.log(xs))
if low in e_int:
xs = xs[e_int >= low]
e_int = e_int[e_int >= low]
elif low is not None and low > e_int[0]:
low_xs = np.e ** interp(np.log(low))
xs = np.insert(xs[e_int > low], 0, low_xs)
e_int = np.insert(e_int[e_int > low], 0, low)
if high in e_int:
xs = xs[e_int <= high]
e_int = e_int[e_int <= high]
elif high is not None:
high_xs = np.e ** interp(np.log(high))
xs = np.append(xs[e_int < high], high_xs)
e_int = np.append(e_int[e_int < high], high)
de_int = float(e_int[-1]-e_int[0])
x1 = e_int[:-1]
x2 = e_int[1:]
y1 = xs[:-1]
y2 = xs[1:]
A = - np.log(y2/y1)/np.log(x1/x2)
B = - (np.log(y1)*np.log(x2) - np.log(y2)*np.log(x1))/np.log(x1/x2)
return np.nansum(np.e**B / (A+1) * (x2**(A+1) - x1**(A+1))/de_int)
[docs] def get_rx(self, nuc, p_in, rdesc, rprop, x1=None, p_out=None):
"""get_rx(nuc, p_in, rdesc, rprop, x1=None, p_out=None)
Grab the data for one reaction type.
Parameters
----------
nuc : int
id form of nucleus to read from.
p_in : int
ENDL incident particle designator
rdesc : int
ENDL reaction descriptor
rprop : int
ENDL reaction property
x1 : int or None
ENDL atomic subshell indicator (if applicable)
yo : int or None
ENDL outgoing particle designator (if applicable)
Returns
-------
data : NumPy array
Contains the reaction data in a n-by-m-dimensional array. The
values of n and m depend on the reaction property rprop.
"""
nuc = nucname.id(nuc)
if nuc in self.structure:
return self._read_nuc_pin_rdesc_rprop(nuc, p_in,
rdesc, rprop,
x1, p_out)
else:
raise ValueError('Nucleus {} does not exist.'.format(nuc))
def _read_nuc_pin_rdesc_rprop(self, nuc, p_in, rdesc, rprop, x1, yo):
"""Load in the data from one reaction into self.structure.
Parameters
----------
nuc : int
id of nuclide.
p_in : int
ENDL incident particle designator
rdesc : int
ENDL reaction descriptor
rprop : int
ENDL reaction property
x1 : int or None
ENDL atomic subshell indicator (if applicable)
yo : int or None
ENDL outgoing particle designator (if applicable)
Returns
-------
array, float64
float64 NumPy array containing the reaction data. The shape of the
array depends on the ENDL reaction property.
"""
opened_here = False
try:
pdp_dict = self.structure[nuc]['pin_rdesc_rprop']
except KeyError as e:
msg = 'Particle {0}/reaction descriptor {1}/reaction property {2}'\
' not found.'.format(p_in, rdesc, rprop)
e.args = (msg,)
raise e
data_tuples = pdp_dict[p_in, rdesc, rprop]['data_tuples']
# Select the first data_tuple matching x1 and yo, if they are provided
# (i.e. not None)
def match_x1_yo_to_data_tuple(x, y, d):
return (x is None or d.x1 == x) and (y is None or d.yo == y)
try:
index, data_tuple = next((i, d) for i, d in enumerate(data_tuples)
if match_x1_yo_to_data_tuple(x1, yo, d))
except StopIteration as e:
msg = 'Outgoing particle {0}/subshell indicator {1}'\
' not found.'.format(yo, x1)
e.args = (msg,)
raise e
start, stop = data_tuple.limits
if isinstance(self.fh, basestring):
fh = open(self.fh, 'r')
opened_here = True
else:
fh = self.fh
fh.seek(start)
s = fh.read(stop-start)
parsed_data = utils.fromendl_tok(s, NFIELDS_RPROP[rprop])
if opened_here:
fh.close()
return parsed_data