Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion openmc/data/ace.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import openmc.checkvalue as cv
from openmc.mixin import EqualityMixin
from .data import ATOMIC_SYMBOL, gnds_name, EV_PER_MEV, K_BOLTZMANN
from .endf import ENDF_FLOAT_RE
from endf.records import ENDF_FLOAT_RE


def get_metadata(zaid, metastable_scheme='nndc'):
Expand Down
294 changes: 23 additions & 271 deletions openmc/data/endf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,31 @@
from pathlib import PurePath
import re

import numpy as np

from .data import gnds_name
from .function import Tabulated1D
from endf.records import float_endf
from endf.records import (
float_endf,
py_float_endf,
int_endf,
get_text_record,
get_cont_record,
get_head_record,
get_list_record,
get_tab1_record as _get_tab1_record,
get_tab2_record,
get_intg_record,
)


def get_tab1_record(file_obj):
"""Return data from a TAB1 record in an ENDF-6 file.

This wraps the endf package's get_tab1_record to return an
openmc.data.Tabulated1D (which has HDF5 support and is a Function1D)
instead of endf.Tabulated1D.
"""
params, tab = _get_tab1_record(file_obj)
return params, Tabulated1D(tab.x, tab.y, tab.breakpoints, tab.interpolation)


_LIBRARY = {0: 'ENDF/B', 1: 'ENDF/A', 2: 'JEFF', 3: 'EFF',
Expand Down Expand Up @@ -61,274 +81,6 @@
106: list(range(750, 800)),
107: list(range(800, 850))}

ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]) ?(\d+)')


def py_float_endf(s):
"""Convert string of floating point number in ENDF to float.

The ENDF-6 format uses an 'e-less' floating point number format,
e.g. -1.23481+10. Trying to convert using the float built-in won't work
because of the lack of an 'e'. This function allows such strings to be
converted while still allowing numbers that are not in exponential notation
to be converted as well.

Parameters
----------
s : str
Floating-point number from an ENDF file

Returns
-------
float
The number

"""
return float(ENDF_FLOAT_RE.sub(r'\1e\2\3', s))


def int_endf(s):
"""Convert string of integer number in ENDF to int.

The ENDF-6 format technically allows integers to be represented by a field
of all blanks. This function acts like int(s) except when s is a string of
all whitespace, in which case zero is returned.

Parameters
----------
s : str
Integer or spaces

Returns
-------
integer
The number or 0
"""
return 0 if s.isspace() else int(s)


def get_text_record(file_obj):
"""Return data from a TEXT record in an ENDF-6 file.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from

Returns
-------
str
Text within the TEXT record

"""
return file_obj.readline()[:66]


def get_cont_record(file_obj, skip_c=False):
"""Return data from a CONT record in an ENDF-6 file.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from
skip_c : bool
Determine whether to skip the first two quantities (C1, C2) of the CONT
record.

Returns
-------
tuple
The six items within the CONT record

"""
line = file_obj.readline()
if skip_c:
C1 = None
C2 = None
else:
C1 = float_endf(line[:11])
C2 = float_endf(line[11:22])
L1 = int_endf(line[22:33])
L2 = int_endf(line[33:44])
N1 = int_endf(line[44:55])
N2 = int_endf(line[55:66])
return (C1, C2, L1, L2, N1, N2)


def get_head_record(file_obj):
"""Return data from a HEAD record in an ENDF-6 file.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from

Returns
-------
tuple
The six items within the HEAD record

"""
line = file_obj.readline()
ZA = int(float_endf(line[:11]))
AWR = float_endf(line[11:22])
L1 = int_endf(line[22:33])
L2 = int_endf(line[33:44])
N1 = int_endf(line[44:55])
N2 = int_endf(line[55:66])
return (ZA, AWR, L1, L2, N1, N2)


def get_list_record(file_obj):
"""Return data from a LIST record in an ENDF-6 file.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from

Returns
-------
list
The six items within the header
list
The values within the list

"""
# determine how many items are in list
items = get_cont_record(file_obj)
NPL = items[4]

# read items
b = []
for i in range((NPL - 1)//6 + 1):
line = file_obj.readline()
n = min(6, NPL - 6*i)
for j in range(n):
b.append(float_endf(line[11*j:11*(j + 1)]))

return (items, b)


def get_tab1_record(file_obj):
"""Return data from a TAB1 record in an ENDF-6 file.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from

Returns
-------
list
The six items within the header
openmc.data.Tabulated1D
The tabulated function

"""
# Determine how many interpolation regions and total points there are
line = file_obj.readline()
C1 = float_endf(line[:11])
C2 = float_endf(line[11:22])
L1 = int_endf(line[22:33])
L2 = int_endf(line[33:44])
n_regions = int_endf(line[44:55])
n_pairs = int_endf(line[55:66])
params = [C1, C2, L1, L2]

# Read the interpolation region data, namely NBT and INT
breakpoints = np.zeros(n_regions, dtype=int)
interpolation = np.zeros(n_regions, dtype=int)
m = 0
for i in range((n_regions - 1)//3 + 1):
line = file_obj.readline()
to_read = min(3, n_regions - m)
for j in range(to_read):
breakpoints[m] = int_endf(line[0:11])
interpolation[m] = int_endf(line[11:22])
line = line[22:]
m += 1

# Read tabulated pairs x(n) and y(n)
x = np.zeros(n_pairs)
y = np.zeros(n_pairs)
m = 0
for i in range((n_pairs - 1)//3 + 1):
line = file_obj.readline()
to_read = min(3, n_pairs - m)
for j in range(to_read):
x[m] = float_endf(line[:11])
y[m] = float_endf(line[11:22])
line = line[22:]
m += 1

return params, Tabulated1D(x, y, breakpoints, interpolation)


def get_tab2_record(file_obj):
# Determine how many interpolation regions and total points there are
params = get_cont_record(file_obj)
n_regions = params[4]

# Read the interpolation region data, namely NBT and INT
breakpoints = np.zeros(n_regions, dtype=int)
interpolation = np.zeros(n_regions, dtype=int)
m = 0
for i in range((n_regions - 1)//3 + 1):
line = file_obj.readline()
to_read = min(3, n_regions - m)
for j in range(to_read):
breakpoints[m] = int(line[0:11])
interpolation[m] = int(line[11:22])
line = line[22:]
m += 1

return params, Tabulated2D(breakpoints, interpolation)


def get_intg_record(file_obj):
"""
Return data from an INTG record in an ENDF-6 file. Used to store the
covariance matrix in a compact format.

Parameters
----------
file_obj : file-like object
ENDF-6 file to read from

Returns
-------
numpy.ndarray
The correlation matrix described in the INTG record
"""
# determine how many items are in list and NDIGIT
items = get_cont_record(file_obj)
ndigit = items[2]
npar = items[3] # Number of parameters
nlines = items[4] # Lines to read
NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8}
nrow = NROW_RULES[ndigit]

# read lines and build correlation matrix
corr = np.identity(npar)
for i in range(nlines):
line = file_obj.readline()
ii = int_endf(line[:5]) - 1 # -1 to account for 0 indexing
jj = int_endf(line[5:10]) - 1
factor = 10**ndigit
for j in range(nrow):
if jj+j >= ii:
break
element = int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)])
if element > 0:
corr[ii, jj] = (element+0.5)/factor
elif element < 0:
corr[ii, jj] = (element-0.5)/factor

# Symmetrize the correlation matrix
corr = corr + corr.T - np.diag(corr.diagonal())
return corr


def get_evaluations(filename):
"""Return a list of all evaluations within an ENDF file.
Expand Down
Loading