Source code for pyne.dbgen.decay

"""This module provides a way to grab and store raw data for radioactive decay."""
from __future__ import print_function, division
import os
import glob
import shutil
from zipfile import ZipFile
from pyne.utils import QA_warn

try:
    import urllib.request as urllib
except ImportError:
    import urllib2 as urllib


import numpy as np
import tables as tb

from pyne import ensdf
from pyne.dbgen.api import BASIC_FILTERS

QA_warn(__name__)


def _readpoint(line, dstart, dlen):
    data = ensdf._getvalue(line[dstart:dstart + dlen])
    error = ensdf._getvalue(line[dstart + dlen:dstart + dlen + 2])
    return data, error


def _read_variablepoint(line, dstart, dlen):
    sub = line[dstart:dstart + dlen + 2].split()
    data = None
    error = None
    if len(sub) == 2:
        data = ensdf._getvalue(sub[0])
        error = ensdf._getvalue(sub[1])
    return data, error


def grab_atomic_data(build_dir=""):
    medfile = os.path.join(build_dir, 'mednew.dat')
    local = os.path.join(os.path.dirname(__file__), 'mednew.dat')
    if os.path.isfile(medfile):
        return
    # try to download first
    # nndc url seems to be down
    #url = 'http://www.nndc.bnl.gov/nndcscr/ensdf_pgm/analysis/radlst/mednew.dat'
    url = 'https://www-nds.iaea.org/workshops/smr1939/Codes/ENSDF_Codes/mswindows/radlst/mednew.dat'
    try:
        conn = urllib.urlopen(url)
        with open(medfile, 'wb') as f:
            f.write(conn.read())
        return
    except Exception:
        pass
    # use local copy if we can't download
    shutil.copy(local, medfile)


def parse_atomic_data(build_dir=""):
    i = 0
    j = 0
    medfile = os.path.join(build_dir, 'mednew.dat')
    dat = np.zeros((103,), atomic_dtype)
    with open(medfile, 'r') as f:
        lines = f.readlines()
    for line in lines:
        if (-1) ** i == 1:
            Z = int(line[0:3])
            k_shell_fluor, k_shell_fluor_error = _readpoint(line, 9, 6)
            l_shell_fluor, l_shell_fluor_error = _readpoint(line, 18, 6)
            # Probability of creating L-shell vacancy by filling K-shell
            prob, prob_error = _readpoint(line, 27, 6)
            k_shell_be, k_shell_be_err = _readpoint(line, 36, 8)
            li_shell_be, li_shell_be_err = _readpoint(line, 47, 8)
            mi_shell_be, mi_shell_be_err = _readpoint(line, 58, 8)
            ni_shell_be, ni_shell_be_err = _readpoint(line, 69, 8)
        else:
            Kb_to_Ka, Kb_to_Ka_err = _read_variablepoint(line, 9, 7)
            Ka2_to_Ka1, Ka2_to_Ka1_err = _read_variablepoint(line, 19, 7)
            L_auger = ensdf._getvalue(line[29:36])
            K_auger = ensdf._getvalue(line[36:42])
            Ka1_X_ray_en, Ka1_X_ray_en_err = _readpoint(line, 43, 8)
            Ka2_X_ray_en, Ka2_X_ray_en_err = _readpoint(line, 54, 7)
            Kb_X_ray_en = ensdf._getvalue(line[65:69])
            L_X_ray_en = ensdf._getvalue(line[70:76])
            dat[j] = Z, k_shell_fluor, k_shell_fluor_error, l_shell_fluor, \
                     l_shell_fluor_error, prob, k_shell_be, k_shell_be_err, \
                     li_shell_be, li_shell_be_err, mi_shell_be, \
                     mi_shell_be_err, ni_shell_be, ni_shell_be_err, \
                     Kb_to_Ka, Kb_to_Ka_err, Ka2_to_Ka1, Ka2_to_Ka1_err, \
                     L_auger, K_auger, Ka1_X_ray_en, Ka1_X_ray_en_err, \
                     Ka2_X_ray_en, Ka2_X_ray_en_err, Kb_X_ray_en, L_X_ray_en
            j += 1
        i += 1
    return dat


[docs]def grab_ensdf_decay(build_dir=""): """ Grabs the ENSDF decay data files if not already present. Parameters ---------- build_dir : str Major directory to place html files in. 'ENSDF/' will be appended. """ # Add ENSDF to build_dir build_dir = os.path.join(build_dir, 'ENSDF') try: os.makedirs(build_dir) except OSError: pass # Grab ENSDF files and unzip them. iaea_base_url = 'http://www.nndc.bnl.gov/ensarchivals/distributions/dist19/' cf_base_url = 'https://github.com/pyne/data/raw/master/' ensdf_zip = ['ensdf_191004_099.zip', 'ensdf_191004_199.zip', 'ensdf_191004_300.zip', ] for f in ensdf_zip: fpath = os.path.join(build_dir, f) if f not in os.listdir(build_dir): print(" grabbing {0} and placing it in {1}".format(f, fpath)) conn = urllib.urlopen(iaea_base_url + f) with open(fpath, 'wb') as f: f.write(conn.read()) if os.path.getsize(fpath) < 1048576: print(" could not get {0} from NNDC; trying mirror".format(f)) os.remove(fpath) conn = urllib.urlopen(cf_base_url + f) with open(fpath, 'wb') as f: f.write(conn.read()) # not using ZipFile context manager (with statement for Python 2.6) try: zf = ZipFile(fpath) for name in zf.namelist(): if not os.path.exists(os.path.join(build_dir, name)): print(" extracting {0} from {1}".format(name, fpath)) zf.extract(name, build_dir) finally: zf.close()
level_dtype = np.dtype([ ('nuc_id', int), ('rx_id', np.uint32), ('half_life', float), ('level', float), ('branch_ratio', float), ('metastable', int), ('special', 'S1'), ]) decay_dtype = np.dtype([ ('parent', int), ('child', int), ('decay', np.uint32), ('half_life', float), ('half_life_error', float), ('branch_ratio', float), ('branch_ratio_error', float), ('photon_branch_ratio', float), ('photon_branch_ratio_err', float), ('beta_branch_ratio', float), ('beta_branch_ratio_err', float), ]) gammas_dtype = np.dtype([ ('from_nuc', int), ('to_nuc', int), ('parent_nuc', int), ('child_nuc', int), ('energy', float), ('energy_err', float), ('photon_intensity', float), ('photon_intensity_err', float), ('conv_intensity', float), ('conv_intensity_err', float), ('total_intensity', float), ('total_intensity_err', float), ('k_conv_e', float), ('l_conv_e', float), ('m_conv_e', float), ]) alphas_dtype = np.dtype([ ('from_nuc', int), ('to_nuc', int), ('energy', float), ('intensity', float), ]) betas_dtype = np.dtype([ ('from_nuc', int), ('to_nuc', int), ('endpoint_energy', float), ('avg_energy', float), ('intensity', float), ]) ecbp_dtype = np.dtype([ ('from_nuc', int), ('to_nuc', int), ('endpoint_energy', float), ('avg_energy', float), ('beta_plus_intensity', float), ('ec_intensity', float), ('k_conv_e', float), ('l_conv_e', float), ('m_conv_e', float), ]) atomic_dtype = np.dtype([ ('z', int), ('k_shell_fluor', float), ('k_shell_fluor_error', float), ('l_shell_fluor', float), ('l_shell_fluor_error', float), ('prob', float), ('k_shell_be', float), ('k_shell_be_err', float), ('li_shell_be', float), ('li_shell_be_err', float), ('mi_shell_be', float), ('mi_shell_be_err', float), ('ni_shell_be', float), ('ni_shell_be_err', float), ('kb_to_ka', float), ('kb_to_ka_err', float), ('ka2_to_ka1', float), ('ka2_to_ka1_err', float), ('l_auger', float), ('k_auger', float), ('ka1_x_ray_en', float), ('ka1_x_ray_en_err', float), ('ka2_x_ray_en', float), ('ka2_x_ray_en_err', float), ('kb_x_ray_en', float), ('l_x_ray_en', float), ])
[docs]def parse_level_data(build_dir=""): """ Builds and returns a list of nuclide decay data. Parameters ---------- build_dir : str build_nuc_data directory containing ENSDF folder Returns ------- level_list_array : np.ndarray array of level data """ build_dir = os.path.join(build_dir, 'ENSDF') level_list = [] files = sorted([f for f in glob.glob(os.path.join(build_dir, 'ensdf.*'))]) for f in files: print(" building level data from {0}".format(f)) level_list = ensdf.levels(f, level_list) level_list_array = np.array(level_list, dtype=level_dtype) return level_list_array
[docs]def parse_decay_data(build_dir=""): """ Builds and returns a list of nuclide decay data. Parameters ---------- build_dir : str build_nuc_data directory containing ENSDF folder Returns ------- all_decay_array : np.ndarray array of decay data all_gammas_array : np.ndarray array of gamma ray data all_alphas_array : np.ndarray array of alpha decay data all_betas_array : np.ndarray array of beta decay data all_ecbp_array : np.ndarray array of electron capture and beta plus decay data """ build_dir = os.path.join(build_dir, 'ENSDF') decay_data = [] files = sorted([f for f in glob.glob(os.path.join(build_dir, 'ensdf.*'))]) for f in files: print(" parsing decay data from {0}".format(f)) decay_data = ensdf.decays(f, decay_data) all_decays = [] all_gammas = [] all_alphas = [] all_betas = [] all_ecbp = [] for item in decay_data: all_decays.append(item[:11]) if len(item[11]) > 0: for subitem in item[11]: all_gammas.append(tuple(subitem)) if len(item[12]) > 0: for subitem in item[12]: all_alphas.append(tuple(subitem)) if len(item[13]) > 0: for subitem in item[13]: all_betas.append(tuple(subitem)) if len(item[14]) > 0: for subitem in item[14]: all_ecbp.append(tuple(subitem)) all_decay_array = np.array(all_decays, dtype=decay_dtype) all_gammas_array = np.array(all_gammas, dtype=gammas_dtype) all_alphas_array = np.array(all_alphas, dtype=alphas_dtype) all_betas_array = np.array(all_betas, dtype=betas_dtype) all_ecbp_array = np.array(all_ecbp, dtype=ecbp_dtype) return all_decay_array, all_gammas_array, all_alphas_array, \ all_betas_array, all_ecbp_array
[docs]def make_atomic_decay_table(nuc_data, build_dir=""): """Makes atomic decay table in the nuc_data library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory to place xray data file in. """ xrd = parse_atomic_data(build_dir) db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Make a new the table if not hasattr(db.root, 'decay'): db.create_group('/', 'decay', 'ENSDF Decay data') atomic_table = db.create_table('/decay/', 'atomic', xrd, 'z' 'k_shell_fluor' 'k_shell_fluor_error' 'l_shell_fluor' 'l_shell_fluor_error' 'prob' 'k_shell_be' 'k_shell_be_err' 'li_shell_be' 'li_shell_be_err' 'mi_shell_be' 'mi_shell_be_err' 'ni_shell_be' 'ni_shell_be_err' 'kb_to_ka' 'kb_to_ka_err' 'ka2_to_ka1' 'ka2_to_ka1_err' 'k_auger' 'k_auger' 'ka1_x_ray_en' 'ka1_x_ray_en_err' 'ka2_x_ray_en' 'ka2_x_ray_en_err' 'kb_x_ray_en' 'l_x_ray_en', expectedrows=103) atomic_table.flush() db.close()
[docs]def make_decay_half_life_table(nuc_data, build_dir=""): """Makes a decay table in the nuc_data library. Parameters ---------- nuc_data : str Path to nuclide data file. build_dir : str Directory to place ensdf files in. """ # Grab raw level data level_list = parse_level_data(build_dir) # Open the HDF5 File db = tb.open_file(nuc_data, 'a', filters=BASIC_FILTERS) # Make a new the table if not hasattr(db.root, 'decay'): db.create_group('/', 'decay', 'ENSDF Decay data') ll_table = db.create_table('/decay/', 'level_list', level_list, 'nuclide [nuc_id], level [keV], half life [s],' 'metastable [int]', expectedrows=len(level_list)) ll_table.flush() # now that the level data is in nuc_data we can build the decay data fast decay, gammas, alphas, betas, ecbp = parse_decay_data(build_dir) decay_table = db.create_table('/decay/', 'decays', decay, 'parent nuclide [nuc_id], daughter nuclide ' '[nuc_id], decay [string], half life [s],' 'half life error [s], branch ratio [frac],' 'branch ratio error [frac],' 'photon branch ratio [ratio],' 'photon branch ratio error [ratio],' 'beta branch ratio [ratio],' 'beta branch ratio error [ratio]', expectedrows=len(decay)) decay_table.flush() gamma_table = db.create_table('/decay/', 'gammas', gammas, 'from_nuc [int], to_nuc [int], primary parent' 'nuc_id [int], child nuc_id [int]' 'Energy [keV], Energy error [keV], ' 'photon intensity [ratio], ' 'photon intensity error [ratio],' 'conversion e intensity [ratio],' 'conversion e intensity error [ratio],' 'total intensity [ratio],' 'total intensity error [ratio], ' 'K conversion electron' 'intensity [ratio], L conversion electron' 'intensity [ratio], M conversion electron' 'intensity [ratio]', expectedrows=len(gammas)) gamma_table.flush() alphas_table = db.create_table('/decay/', 'alphas', alphas, 'from_nuc [int], to_nuc [int]' 'Energy [keV], Intensity [ratio],', expectedrows=len(alphas)) alphas_table.flush() betas_table = db.create_table('/decay/', 'betas', betas, 'from_nuc [int], to_nuc [int],' 'Endpoint Energy [keV], Average Energy [keV],' 'Intensity [ratio]', expectedrows=len(betas)) betas_table.flush() ecbp_table = db.create_table('/decay/', 'ecbp', ecbp, 'from_nuc [int], to_nuc [int],' 'Endpoint Energy [keV], Average Energy [keV],' 'B+ Intensity [ratio], ' 'Electron Capture Intensity [ratio],' 'K conversion' 'electron intensity [ratio], L conversion' 'electron intensity [ratio], M conversion' 'electron intensity [ratio]', expectedrows=len(ecbp)) ecbp_table.flush() # Close the hdf5 file db.close()
[docs]def make_decay(args): """Controller function for adding decay data.""" nuc_data, build_dir = args.nuc_data, args.build_dir with tb.open_file(nuc_data, 'r') as f: if hasattr(f.root, 'decay') and hasattr(f.root.decay, 'ecbp'): print("skipping ENSDF decay data table creation; already exists.") return # grab the decay data print("Grabbing the ENSDF decay data from NNDC") grab_ensdf_decay(build_dir) # Make atomic mass table once we have the array print("Making decay data table.") make_decay_half_life_table(nuc_data, build_dir) print("Grabbing Atomic data") grab_atomic_data(build_dir) print("Making atomic decay data table") make_atomic_decay_table(nuc_data, build_dir)