Source code for pyne.dbgen.cinder

"""This module provides a way to locate, parse, and store CINDER cross
sections."""
from __future__ import print_function
import os
import io
import re
import sys
import shutil
from glob import glob
from warnings import warn
from pyne.utils import QAWarning

import numpy as np
import tables as tb

from .. import nucname
from ..utils import warning
from .api import BASIC_FILTERS

if sys.version_info[0] > 2:
    basestring = str

warn(__name__ + " is not yet QA compliant.", QAWarning)


[docs]def grab_cinder_dat(build_dir="", datapath=''): """Grabs the cinder.dat file from the DATAPATH directory if not already present.""" build_filename = os.path.join(build_dir, 'cinder.dat') if os.path.exists(build_filename): return True if isinstance(datapath, basestring) and 0 < len(datapath): pass elif 'DATAPATH' in os.environ: datapath = os.environ['DATAPATH'] else: print(warning("DATAPATH not defined in environment; cinder.dat not " "found - skipping.")) return False local_filename = os.path.join(datapath, "[Cc][Ii][Nn][Dd][Ee][Rr]." "[Dd][Aa][Tt]") local_filename = glob(local_filename) if 0 < len(local_filename): print("Grabbing cinder.dat from " + datapath) print(warning("cinder.dat contains export controlled information " "nuc_data.h5 is now export controlled!")) shutil.copy(local_filename[0], build_filename) rtn = True else: print(warning("cinder.dat file not found in DATAPATH dir - skipping.")) rtn = False return rtn
# These read in cinder.dat cinder_float = "[\d.+-Ee]+" def _init_cinder(db): """Initializes a multigroup cross-section part of the database. Parameters ---------- db : tables.File A nuclear data hdf5 file. """ # Create neutron and photon groups if not hasattr(db.root, 'neutron'): neutron_group = db.create_group('/', 'neutron', 'Neutron Interaction Data') if not hasattr(db.root, 'photon'): photon_group = db.create_group('/', 'photon', 'Photon Interaction Data') # Create xs group if not hasattr(db.root.neutron, 'cinder_xs'): nxs_mg_group = db.create_group("/neutron", "cinder_xs", "CINDER Multi-Group Neutron Cross " "Section Data") # Create source groups if not hasattr(db.root.photon, 'cinder_source'): gxs_mg_group = db.create_group("/photon", "cinder_source", "CINDER Multi-Group Photon Source Data") # Create fission_yield groups if not hasattr(db.root.neutron, 'cinder_fission_products'): nxs_mg_group = db.create_group("/neutron", "cinder_fission_products", "CINDER Neutron Fission Product " "Yield Data") if not hasattr(db.root.photon, 'cinder_fission_products'): nxs_mg_group = db.create_group("/photon", "cinder_fission_products", "CINDER Photofission Product Yield Data")
[docs]def get_group_sizes(raw_data): """Gets the number of nuclides and groups in this data file. Parameters ---------- raw_data : str Input cinder.dat data file as a string. Returns ------- nuclides : int The number of nuclides in the dataset G_n : int The number of neutron energy groups in the dataset G_p : int The number of proton energy groups in the dataset G_g : int The number of photon energy groups in the dataset """ # Search for the group pattern G_pattern = ("(\d+) nuclides,\s+(\d+) neutron groups,\s+(\d+) proton " "groups,\s+(\d+) photon groups") m = re.search(G_pattern, raw_data) g = m.groups() # Convert to ints nuclides = int(g[0]) G_n = int(g[1]) G_p = int(g[2]) G_g = int(g[3]) return nuclides, G_n, G_p, G_g
[docs]def safe_decode(b, encs=(None, 'utf-8', 'latin-1')): """Tries to decode a bytes array in a few different ways.""" enc, encs = encs[0], encs[1:] try: s = b.decode() if enc is None else b.decode(enc) except UnicodeDecodeError: if len(encs) == 0: raise s = safe_decode(b, encs) return s
[docs]def make_mg_group_structure(nuc_data, build_dir=""): """Add the energy group bounds arrays to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes nuclides, G_n, G_p, G_g = get_group_sizes(raw_data) # Find & write neutron group structure n_E_g_pattern = "Neutron group .*, MeV" + ("\s+("+cinder_float+")")*(G_n + 1) m = re.search(n_E_g_pattern, raw_data) g = m.groups() n_E_g = np.array(g[::-1], dtype=float) db.create_array('/neutron/cinder_xs', 'E_g', n_E_g, 'Neutron energy group bounds [MeV]') # Find & write photon group structure g_E_g_pattern = "Gamma structure, MeV" + ("\s+("+cinder_float+")")*(G_g + 1) m = re.search(g_E_g_pattern, raw_data) g = m.groups() g_E_g = np.array(g[::-1], dtype=float) db.create_array('/photon/cinder_source', 'E_g', g_E_g, 'Photon energy group bounds [MeV]') # Close the hdf5 file db.close()
# Helpful patterns from_nuc_pattern = "\n#[\s\d]{4}:\s+(\d+).*?\n(_______________________| [\w/-]+ Fission Yield Data)" to_nuc_base = "#[\s\d]{4}:\s+(\d+) produced by the following C-X \((.{4})\) REF:.*?\n" absorption_dtype_tuple = [ ('from_nuc', int), ('to_nuc', int), ('reaction_type', 'S4'), # Extra 'xs' entry should be appended with value ('xs', float, G_n) ]
[docs]def make_mg_absorption(nuc_data, build_dir=""): """Adds the absorption reaction rate cross sections to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes nuclides, G_n, G_p, G_g = get_group_sizes(raw_data) # Init the neutron absorption table absorption_dtype = np.dtype(absorption_dtype_tuple + [('xs', float, G_n)]) absorption_table = db.create_table('/neutron/cinder_xs/', 'absorption', np.empty(0, dtype=absorption_dtype), 'Neutron absorption reaction cross sections [barns]') abrow = absorption_table.row # Init to_nuc_pattern to_nuc_pattern = to_nuc_base + ("\s+("+cinder_float+")")*G_n # Iterate through all from nuctopes. for m_from in re.finditer(from_nuc_pattern, raw_data, re.DOTALL): from_nuc = nucname.id(m_from.group(1)) # Check matestable state if 1 < from_nuc % 10: # Metastable state too high! continue # Grab the string for this from_nuc in order to get all of the to_nucs from_nuc_part = m_from.group(0) # Iterate over all to_nucs for m_to in re.finditer(to_nuc_pattern, from_nuc_part): to_nuc = nucname.id(m_to.group(1)) # Check matestable state if 1 < to_nuc % 10: # Metastable state too high! continue # Munge reaction type rx_type = m_to.group(2) rx_type = rx_type.strip() # Setup XS array xs = np.array(m_to.groups()[-1:1:-1], dtype=float) assert xs.shape == (G_n, ) # Write this row to the absorption table abrow['from_nuc'] = from_nuc abrow['to_nuc'] = to_nuc abrow['reaction_type'] = rx_type abrow['xs'] = xs abrow.append() # Flush this from nuc absorption_table.flush() # Close the hdf5 file db.close()
fission_base = "\n([\s\d]+),([\s\d]+),([\s\d]+)=\(n,f\) yield sets\. If > 0,[\s\d]{4}-gp fisn CX follows\..*?\n" fission_dtype_tuple = [ ('nuc', int), ('thermal_yield', np.int8), ('fast_yield', np.int8), ('high_energy_yield', np.int8), # Extra 'xs' entry should be appended with value ('xs', float, G_n) ]
[docs]def make_mg_fission(nuc_data, build_dir=""): """Adds the fission reaction rate cross sections to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes nuclides, G_n, G_p, G_g = get_group_sizes(raw_data) # Init the neutron absorption table fission_dtype = np.dtype(fission_dtype_tuple + [('xs', float, G_n)]) fission_table = db.create_table('/neutron/cinder_xs/', 'fission', np.empty(0, dtype=fission_dtype), 'Neutron fission reaction cross sections [barns]') frow = fission_table.row # Init to_nuc_pattern fission_pattern = fission_base + ("\s+("+cinder_float+")")*G_n # Iterate through all from nuctopes. for m_from in re.finditer(from_nuc_pattern, raw_data, re.DOTALL): from_nuc = nucname.id(m_from.group(1)) # Check matestable state if 1 < from_nuc % 10: # Metastable state too high! continue # Grab the string for this from_nuc in order to get all of the to_nucs from_nuc_part = m_from.group(0) # Grab the fission part m_fission = re.search(fission_pattern, from_nuc_part) if m_fission is None: continue # Grab yield indexes yield_t = int(m_fission.group(1)) yield_f = int(m_fission.group(2)) yield_h = int(m_fission.group(3)) # Grab XS array xs = np.array(m_fission.groups()[-1:2:-1], dtype=float) assert xs.shape == (G_n, ) # Write fission table row frow['nuc'] = from_nuc frow['thermal_yield'] = yield_t frow['fast_yield'] = yield_f frow['high_energy_yield'] = yield_h frow['xs'] = xs # Write out this row frow.append() fission_table.flush() # Close the hdf5 file db.close()
gamma_decay_base = "gamma spectra from .{3} multiplied by\s+(" + cinder_float + ")\s+to agree w/ Eg=\s*(" +\ cinder_float + ")\n" gamma_decay_dtype_tuple = [ ('nuc', int), ('energy', float), ('scaling_factor', float), # Extra 'spectrum' entry should be appended with value ('spectrum', float, G_g) ]
[docs]def make_mg_gamma_decay(nuc_data, build_dir=""): """Adds the gamma decay spectrum information to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes nuclides, G_n, G_p, G_g = get_group_sizes(raw_data) # Init the gamma absorption table gamma_decay_dtype = np.dtype(gamma_decay_dtype_tuple + [('spectrum', float, G_g)]) gamma_decay_table = db.create_table('/photon/cinder_source/', 'decay_spectra', np.empty(0, dtype=gamma_decay_dtype), 'Gamma decay spectrum [MeV]') gdrow = gamma_decay_table.row # Init to_nuc_pattern gamma_decay_pattern = gamma_decay_base + ("\s+("+cinder_float+")")*G_g # Iterate through all from nuctopes. for m_from in re.finditer(from_nuc_pattern, raw_data, re.DOTALL): from_nuc = nucname.id(m_from.group(1)) # Check matestable state if 1 < from_nuc % 10: # Metastable state too high! continue # Grab the string for this from_nuc in order to get all of the to_nucs from_nuc_part = m_from.group(0) # Grab the fission part m_gd = re.search(gamma_decay_pattern, from_nuc_part) if m_gd is None: continue # Grab base data scale = float(m_gd.group(1)) energy = float(m_gd.group(2)) # Grab spectrum spectrum = np.array(m_gd.groups()[-1:1:-1], dtype=float) assert spectrum.shape == (G_g, ) # Prepare the row gdrow['nuc'] = from_nuc gdrow['energy'] = energy gdrow['scaling_factor'] = scale gdrow['spectrum'] = spectrum # Write out the row gdrow.append() gamma_decay_table.flush() # Close the hdf5 file db.close()
[docs]def get_fp_sizes(raw_data): """Gets the number of fission product yield data sets in this file. Parameters ---------- data : str Input cinder.dat data file as a string. Returns ------- N_n : int The number of neutron fission product yield datasets in the file. N_g int The number of photon fission product yield datasets in the file. """ # Search for the neutron pattern N_n_pattern = "Fission Yield Data.*?\n\s*(\d+)\s+yield sets" m_n = re.search(N_n_pattern, raw_data) N_n = int(m_n.group(1)) # Search for the photon pattern N_g_pattern = "Photofission Yield Data.*?\n\s*(\d+)\s+yield sets" m_g = re.search(N_g_pattern, raw_data) N_g = int(m_g.group(1)) return N_n, N_g
fp_info_dtype = np.dtype([ ('index', np.int16), ('nuc', int), ('type', 'S11'), ('mass', float), ]) fp_type_flag = { 't': 'thermal', 'f': 'fast', 'h': 'high_energy', 's': 'spontaneous', } iit_pattern = "(\d{1,3})\s+\d{2,3}-\s?([A-Z]{1,2}-[ Mm\d]{3})([tfhs])" mass_pattern = "\d{1,3}\.\d{1,4}" nfp_info_pattern = "Fission Yield Data.*?fission products"
[docs]def parse_neutron_fp_info(raw_data): """Grabs the neutron fission product info. Parameters ---------- raw_data : str string of the cinder.dat data file. Returns ------- info_table : array Structured array with the form "(index, nuc, type, mass)". """ # Get group sizes N_n, N_g = get_fp_sizes(raw_data) # Grab the part of the file that is a neutron fission product yield info m_info = re.search(nfp_info_pattern, raw_data, re.DOTALL) nfp_info_raw = m_info.group(0) # Grab the index, nuctope, and type iits = re.findall(iit_pattern, nfp_info_raw) # Grab the masses masses = re.findall(mass_pattern, nfp_info_raw) # Make sure data is the right size assert N_n == len(iits) assert N_n == len(masses) # Make info table rows info_table = [] for m in range(N_n): iit = iits[m] index = int(iit[0]) nuc = nucname.id(iit[1]) # Correct for metastable flag if 0 != nuc % 10: nuc = nuc + 2000 type = fp_type_flag[iit[2]] mass = float(masses[m]) info_row = (index, nuc, type, mass) info_table.append(info_row) info_table = np.array(info_table, dtype=fp_info_dtype) return info_table
[docs]def make_neutron_fp_info(nuc_data, build_dir=""): """Adds the neutron fission product yield info to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # get the info table info_table = parse_neutron_fp_info(raw_data) # Init the neutron fission product info table nfp_table = db.create_table('/neutron/cinder_fission_products/', 'info', np.empty(0, dtype=fp_info_dtype), 'CINDER Neutron Fission Product Yield Information') # Append Rows nfp_table.append(info_table) # Close the hdf5 file db.close()
gfp_info_pattern = "Photofission Yield Data.*?fission products"
[docs]def grab_photon_fp_info(raw_data): """Grabs the photon fission product info. Parameters ---------- raw_data : str string of the cinder.dat data file. Returns ------- info_table : array Structured array with the form "(index, nuc, type, mass)". """ # Get group sizes N_n, N_g = get_fp_sizes(raw_data) # Grab the part of the file that is a neutron fission product yield info m_info = re.search(gfp_info_pattern, raw_data, re.DOTALL) gfp_info_raw = m_info.group(0) # Grab the index, nuctope, and type iits = re.findall(iit_pattern, gfp_info_raw) # Grab the masses masses = re.findall(mass_pattern, gfp_info_raw) # Make sure data is the right size assert N_g == len(iits) assert N_g == len(masses) # Make info table rows info_table = [] for m in range(N_g): iit = iits[m] index = int(iit[0]) nuc = nucname.id(iit[1]) # Correct for metastable flag if 0 != nuc % 10: nuc = nuc + 2000 type = fp_type_flag[iit[2]] mass = float(masses[m]) info_row = (index, nuc, type, mass) info_table.append(info_row) info_table = np.array(info_table, dtype=fp_info_dtype) return info_table
[docs]def make_photon_fp_info(nuc_data, build_dir=""): """Adds the photofission product yield info to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Grab photon info table info_table = grab_photon_fp_info(raw_data) # Init the neutron fission product info table gfp_table = db.create_table('/photon/cinder_fission_products/', 'info', np.empty(0, dtype=fp_info_dtype), 'CINDER Photofission Product Yield Information') gfp_table.append(info_table) # Close the hdf5 file db.close()
fp_yields_dtype = np.dtype([ ('index', np.int16), ('from_nuc', int), ('to_nuc', int), ('mass_frac', float), ]) fp_to_nuc_insert = "\s{1,3}" + cinder_float fp_to_nuc_base = " ([ \d]{4}) ([ \d]{7})\n(" nfp_yields_pattern = "Fission Yield Data.*Photofission Yield Data"
[docs]def make_neutron_fp_yields(nuc_data, build_dir=""): """Adds the neutron fission product yields to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes N_n, N_g = get_fp_sizes(raw_data) # get the info table info_table = parse_neutron_fp_info(raw_data) # Grab the part of the file that is a neutron fission product yields m_yields = re.search(nfp_yields_pattern, raw_data, re.DOTALL) nfp_yields_raw = m_yields.group(0) # Init the neutron fission product info table nfp_table = db.create_table('/neutron/cinder_fission_products/', 'yields', np.empty(0, dtype=fp_yields_dtype), 'CINDER Neutron Fission Product Yields') nfprow = nfp_table.row # Iterate over all to-nucs fp_to_nuc_pattern = fp_to_nuc_base + N_n*fp_to_nuc_insert + ")" for m_to in re.finditer(fp_to_nuc_pattern, nfp_yields_raw): to_nuc = nucname.id(m_to.group(2).strip()) # Check matestable state if 1 < to_nuc % 10: # Metastable state too high! continue # Get the array of yield data yields = np.array(m_to.group(3).split(), dtype=float) assert len(yields) == N_n # Prep rows to the table for n in range(N_n): info = info_table[n] nfprow['index'] = info[0] nfprow['from_nuc'] = info[1] nfprow['to_nuc'] = to_nuc nfprow['mass_frac'] = yields[n] nfprow.append() # Write the table nfp_table.flush() # Close the hdf5 file db.close()
gfp_yields_pattern = "Photofission Yield Data.*"
[docs]def make_photon_fp_yields(nuc_data, build_dir): """Adds the photofission product yields to the hdf5 library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory with cinder.dat file. """ # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Ensure that the appropriate file structure is present _init_cinder(db) # Read in cinder data file cinder_dat = os.path.join(build_dir, 'cinder.dat') with io.open(cinder_dat, 'rb') as f: raw_data = f.read() raw_data = safe_decode(raw_data) # Get group sizes N_n, N_g = get_fp_sizes(raw_data) # get the info table info_table = grab_photon_fp_info(raw_data) # Grab the part of the file that is a neutron fission product yields m_yields = re.search(gfp_yields_pattern, raw_data, re.DOTALL) gfp_yields_raw = m_yields.group(0) # Init the neutron fission product info table gfp_table = db.create_table('/photon/cinder_fission_products/', 'yields', np.empty(0, dtype=fp_yields_dtype), 'CINDER Photofission Product Yields') gfprow = gfp_table.row # Iterate over all to-nucs fp_to_nuc_pattern = fp_to_nuc_base + N_g*fp_to_nuc_insert + ")" for m_to in re.finditer(fp_to_nuc_pattern, gfp_yields_raw): to_nuc = nucname.id(m_to.group(2).strip()) # Check matestable state if 1 < to_nuc % 10: # Metastable state too high! continue # Get the array of yield data yields = np.array(m_to.group(3).split(), dtype=float) assert len(yields) == N_g # Prep rows to the table for n in range(N_g): info = info_table[n] gfprow['index'] = info[0] gfprow['from_nuc'] = info[1] gfprow['to_nuc'] = to_nuc gfprow['mass_frac'] = yields[n] gfprow.append() # Write the table gfp_table.flush() # Close the hdf5 file db.close()
[docs]def make_cinder(args): """Controller function for adding cinder data.""" nuc_data, build_dir, datapath = args.nuc_data, args.build_dir, args.datapath with tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) as f: if hasattr(f.root, 'neutron') and hasattr(f.root.neutron, 'cinder_xs') and hasattr(f.root.neutron, 'cinder_fission_products'): print("skipping Cinder XS data table creation; already exists.") return # First grab the atomic abundance data grabbed = grab_cinder_dat(build_dir, datapath) if not grabbed: return # Add energy groups to file print("Adding cinder data...") print(" energy group boundaries.") make_mg_group_structure(nuc_data, build_dir) # Add neutron absorption to file print(" neutron absorption cross sections.") make_mg_absorption(nuc_data, build_dir) # Add fission to file print(" neutron fission cross sections.") make_mg_fission(nuc_data, build_dir) # Add gamma decay spectrum to file print(" gamma decay spectra.") make_mg_gamma_decay(nuc_data, build_dir) # Add neutron info table print(" neutron fission product info.") make_neutron_fp_info(nuc_data, build_dir) # Add neutron yield table print(" neutron fission product yields.") make_neutron_fp_yields(nuc_data, build_dir) # Add photon info table print(" photofission product info.") make_photon_fp_info(nuc_data, build_dir) # Add neutron yield table print(" photofission product yields.") make_photon_fp_yields(nuc_data, build_dir) print("...finished with cinder.")