import re
import sys
import numpy as np
import pdb
from pyne.utils import QA_warn
if sys.version_info[0] > 2:
basestring = str
QA_warn(__name__)
_if_idx_str_serpent1 = (
'if (exist("idx", "var"));\n'
' idx = idx + 1;\n'
'else;\n'
' idx = 1;\n'
'end;'
)
_if_idx_str_serpent2 = (
"if (exist('idx', 'var'));\n"
' idx = idx + 1;\n'
'else;\n'
' idx = 1;\n'
'end;'
)
_num_pattern = "([0-9]+[.]?[0-9]*[Ee]?[+-]?[0-9]*)"
_numpy_array_pattern = r"\[[0-9\sEe+-.,%]*\]"
_matlab_array_pattern = r"\[[0-9\sEe+-.%]*\]"
_comment_array_pattern = r"\[([\d\sEe+-.,]*\s*[%#]+\s*[%#\w\s.,+-]*)\]"
_comment_line_pattern = r"([\d\s\tEe+-.]*)\s*([%#]*)\s*([#\w\s]*\n)"
_lhs_variable_pattern = r"(\w+)\s*(\(idx.*?\))"
_rhs_variable_pattern = r"(\w+)\s*\(idx.*?\)\s*=\s*(.*)"
_zeros_pattern = r"(zeros)\((.*)\)"
_detector_pattern = r"(DET\w+)\s*=\s*np.array\("
_detector_pattern_all = r"(DET\w+)\s*=\s*"
_imaterial_line_pattern = r"(i[a-zA-Z]\w+)\s*=\s*\d*;"
def _delete_imaterial(s):
""""Remove imaterial information from the top of Serpent2 *_dep.m file started from 'i' with nothing."""
s = re.sub(_imaterial_line_pattern,
'', s)
return s
def _replace_comments(s):
"""Replaces matlab comments with python arrays in string s."""
s = s.replace('%', '#')
return s
def _replace_semicolons(s):
"""Replaces matlab semicolons with nothing in string s."""
s = s.replace(';', '')
return s
def _replace_arrays(s):
"""Replaces matlab arrays with numpy arrays in string s."""
# Replace matlab arrays with python lists
arrays = re.findall(_matlab_array_pattern, s)
for a in arrays:
new_a = re.sub(_num_pattern, lambda mo: mo.group(0) + ',', a)
s = s.replace(a, new_a)
# Encapsulate python lists in numpy arrays
s = re.sub(_numpy_array_pattern,
lambda mo: 'np.array(' + mo.group(0) + ')', s)
return s
[docs]def parse_res(resfile, write_py=False):
"""Converts a serpent results ``*_res.m`` output file to a dictionary (and
optionally to a ``*_res.py`` file).
Parameters
----------
resfile : str or file-like object
Path to results file or a res file handle.
write_py : bool, optional
Flag for whether to write the res file to an analogous python file.
Returns
-------
res : dict
Dictionary of the parsed results. Please see the Serpent manual for
a complete description of contents.
"""
if isinstance(resfile, basestring):
with open(resfile, 'r') as mfile:
f = mfile.read()
else:
f = resfile.read()
# Keep comments around
f = _replace_comments(f)
# Grab the number of 'if' statements
if_idx_str = _if_idx_str_serpent1
IDX = f.count(if_idx_str)
if IDX == 0:
if_idx_str = _if_idx_str_serpent2
IDX = f.count(if_idx_str)
# Replace if statements with something more meaningful
fpart = f.partition(if_idx_str)
f = fpart[0] + "idx = 0" + fpart[2]
f = f.replace(if_idx_str, 'idx += 1')
# Replace matlab Arrays
f = _replace_arrays(f)
# Add imports to header
header = "import numpy as np\n\n"
# Find all variables and shape
vars_shape = np.array(list(set(re.findall(_lhs_variable_pattern, f))))
vars_dtype = dict(re.findall(_rhs_variable_pattern, f))
# Initialize variables to zero
header = header + "# Initialize variables\n"
for vs in vars_shape:
# Determine shape
s = re.search(r'\[.*?:(.*?)\]', vs[1])
if s is None:
vs_shape = ""
else:
vs_shape = s.group(1)
vs_shape = vs_shape.split()
vs_shape = ", ".join(vs_shape)
# Determine Data type
rhs = vars_dtype[vs[0]]
if ("\'" in rhs) or ("\"" in rhs):
dt = "'S{0}'".format(int(s.group(1)))
vs_shape = ""
elif ('.' in rhs) or ('E' in rhs) or ('e' in rhs):
dt = "float"
else:
dt = "int"
zero_line = "{0} = np.zeros([{1}, {2}], dtype={3})\n".format(
vs[0], IDX, vs_shape, dt)
header = header + zero_line
# Add IDx to file
if 0 < IDX:
header = header + "\n\n# Maximum Index\n\nIDX = {0}\n\n".format(IDX)
# Add header to file
f = header + f
# Replace variable overrides
vars = np.array(
list(set(re.findall("(" + _lhs_variable_pattern + ")", f))))
for v in vars:
f = f.replace(v[0], "{0}[idx] ".format(v[1]))
# Remove semicolons if serp2:
mat_gen_line = ('{name}MATERIAL = [{name}vol[col] *'
'Material(dict(zip(zai[:-2], {name}MDENS[:-2, col])))'
' for col in cols]\n')
else:
mat_gen_line = ('{name}MATERIAL = [{name}VOLUME *'
'Material(dict(zip(zai[:-2], {name}MDENS[:-2, col])))'
' for col in cols]\n')
f = _replace_semicolons(f)
# Write the file out
if write_py:
if isinstance(resfile, basestring):
new_filename = resfile.rpartition('.')[0] + '.py'
else:
new_filename = resfile.name.rpartition('.')[0] + '.py'
with open(new_filename, 'w') as pyfile:
pyfile.write(f)
# Execute the adjusted file
res = {}
exec(f, res, res)
if '__builtins__' in res:
del res['__builtins__']
return res
[docs]def parse_dep(depfile, write_py=False, make_mats=True):
"""Converts a serpent depletion ``*_dep.m`` output file to a dictionary (and
optionally to a ``*_dep.py`` file).
Parameters
----------
depfile : str or file-like object
Path to depletion file or a dep file handle.
write_py : bool, optional
Flag for whether to write the dep file to an analogous python file.
make_mats : bool, optional
Flag for whether or not to build Materials out of mass data and add
these to the return dictionary. Materials so added have names which
end in '_MATERIAL'.
Returns
-------
dep : dict
Dictionary of the parsed depletion information. Please see the Serpent
manual for a complete description of contents.
"""
if isinstance(depfile, basestring):
with open(depfile, 'r') as mfile:
f = mfile.read()
else:
f = depfile.read()
# Remove imaterial information from the top of Serpent2 *_dep.m file
f = _delete_imaterial(f)
# Keep comments around
f = _replace_comments(f)
# Replace matlab Arrays
f = _replace_arrays(f)
# Now to find and convert arrays that have comments in them
comment_arrays = re.findall("(" + _comment_array_pattern + ")", f)
for ca in comment_arrays:
new_ca = ca[0]
comment_lines = re.findall("(" + _comment_line_pattern + ")", ca[1])
for cl in comment_lines:
new_cl = re.sub(_num_pattern, lambda mo: mo.group(0) + ',', cl[1])
if new_cl[0] == '\n':
new_cl = "\n [" + new_cl.strip() + "], "
else:
new_cl = " [" + new_cl.strip() + "], "
new_ca = new_ca.replace(cl[1], new_cl)
new_ca = 'np.array( ' + new_ca + ' )'
f = f.replace(ca[0], new_ca)
# Indent close of array
f = f.replace("\n] )", "\n ] )")
# Replace MatLab zeros with numpy zeros
f = re.sub(_zeros_pattern, lambda mo: "np.zeros((" + mo.group(2) + "))", f)
# Replace some math operators
f = f.replace('.*', "*")
f = f.replace('./', "/")
# Remove semicolons
f = _replace_semicolons(f)
# Add imports to header
header = "import numpy as np\n"
if make_mats:
header += "from pyne.material import Material\n"
header += "\n"
# Add materials
footer = ""
if make_mats:
footer = form_footer(f)
# Add header & footer to file
full_f = header + f + footer
# Write the file out
if write_py:
if isinstance(depfile, basestring):
new_filename = depfile.rpartition('.')[0] + '.py'
else:
new_filename = depfile.name.rpartition('.')[0] + '.py'
with open(new_filename, 'w') as pyfile:
pyfile.write(full_f)
# Execute the adjusted file
dep = {}
try:
exec(full_f, dep, dep)
except ValueError:
#if the first attempt fails, it may be due to the VOLUME
#variable being an array. Below changes mat_gen_line to
#work with an array
correct_footer = form_footer(f, serp2=True)
full_f = header + f + correct_footer
# Overwrite the file made before to reflect changes
if write_py:
with open(new_filename, 'w') as pyfile:
pyfile.write(full_f)
exec(full_f, dep, dep)
if '__builtins__' in dep:
del dep['__builtins__']
return dep
[docs]def parse_det(detfile, write_py=False):
"""Converts a serpent detector ``*_det.m`` output file to a dictionary (and
optionally to a ``*_det.py`` file).
Parameters
----------
detfile : str or file-like object
Path to detector file or a det file handle.
write_py : bool, optional
Flag for whether to write the det file to an analogous python file.
Returns
-------
det : dict
Dictionary of the parsed detector. Please see the Serpent manual for
a complete description of contents.
"""
if isinstance(detfile, basestring):
with open(detfile, 'r') as mfile:
f = mfile.read()
else:
f = detfile.read()
# Keep comments around
f = _replace_comments(f)
# Replace matlab Arrays
f = _replace_arrays(f)
# Find detector variable names
det_names = re.findall(_detector_pattern, f)
det_names = np.unique(det_names)
all_det_names = re.findall(_detector_pattern_all, f)
all_det_names = np.unique(all_det_names)
is_serpent_1 = any([(dn.endswith('_VALS') and dn[:-5] in det_names) or
(dn.endswith('_EBINS') and dn[:-6] in det_names)
for dn in all_det_names])
# Append detector reshaping
f += '\n\n# Reshape detectors\n'
for dn in det_names:
if is_serpent_1:
if dn + 'E' in det_names:
f += '{name}.shape = ({name}_VALS, 13)\n'.format(name=dn)
else:
f += '{name}.shape = ({name_min_E}_EBINS, 3)\n'.format(name=dn,
name_min_E=dn[:-1])
else:
if (dn + 'T' in det_names):
f += '{name}.shape = (len({name})//13, 13)\n'.format(name=dn)
elif (dn + 'E' in det_names):
f += '{name}.shape = (len({name})//12, 12)\n'.format(name=dn)
else:
f += '{name}.shape = (len({name})//3, 3)\n'.format(name=dn)
# Add imports to header
header = "import numpy as np\n\n"
# Add header to file
f = header + f
# Remove semicolons
f = _replace_semicolons(f)
# Write the file out
if write_py:
if isinstance(detfile, basestring):
new_filename = detfile.rpartition('.')[0] + '.py'
else:
new_filename = detfile.name.rpartition('.')[0] + '.py'
with open(new_filename, 'w') as pyfile:
pyfile.write(f)
# Execute the adjusted file
det = {}
exec(f, {}, det)
return det