def __init__(self, t=0.0, phi=0.0, temp=300.0, tol=1e-7, rxs=None, log=None, *args, **kwargs): """Parameters ---------- t : float Transmutations time [sec]. phi : float or array of floats Neutron flux vector [n/cm^2/sec]. Currently this must either be a scalar or match the group structure of EAF. temp : float, optional Temperature [K] of material, defaults to 300.0. tol : float Tolerance level for chain truncation. rxs : set of ints or strs Reaction ids or names to use in transmutation which produce well-defined children. This set should thus not include fission. If None, then the reactions from EAF are used. log : file-like or None The log file object should be written. A None imples the log is not desired. args : tuple, optional Other arguments ignored for compatibility with other Transmuters. kwargs : dict, optional Other keyword arguments ignored for compatibility with other Transmuters. """ eafds = EAFDataSource() eafds.load(temp=temp) gs = np.array([eafds.src_group_struct[0], eafds.src_group_struct[-1]]) eafds.dst_group_struct = gs self.xscache = XSCache(group_struct=gs, data_source_classes=(NullDataSource, )) self.xscache.data_sources.insert(0, eafds) self.t = t self._phi = None self.phi = phi self.temp = temp self.log = log self.tol = tol if rxs is None: rxs = [ 'gamma', 'gamma_1', 'gamma_2', 'p', 'p_1', 'p_2', 'd', 'd_1', 'd_2', 't', 't_1', 't_2', 'He3', 'He3_1', 'He3_2', 'a', 'a_1', 'a_2', 'z_2a', 'z_2p', 'z_2p_1', 'z_2p_2', 'z_2n', 'z_2n_1', 'z_2n_2', 'z_3n', 'z_3n_1', 'z_3n_2', 'na', 'na_1', 'na_2', 'z_2na', 'np', 'np_1', 'np_2', 'n2a', 'nd', 'nd_1', 'nd_2', 'nt', 'nt_1', 'nt_2', 'nHe3', 'nHe3_1', 'nHe3_2', 'z_4n', 'z_4n_1', 'n', 'n_1', 'n_2', 'z_3np' ] rxs = set([rxname.id(rx) for rx in rxs]) rxs.discard(rxname.id('fission')) self.rxs = rxs
def _load_reaction(self, nuc, rx, temp=300.0): """Loads reaction data from ACE files indexed by OpenMC. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The nuclide temperature in [K]. """ rx = rxname.id(rx) try: mt = rxname.mt(rx) except RuntimeError: return None totrx = rxname.id('total') absrx = rxname.id('absorption') ace_tables = self._rank_ace_tables(nuc, temp=temp) lib = ntab = None for atab in ace_tables: if atab not in self.libs: lib = self.libs[atab] = ace.Library(atab.abspath or atab.path) lib.read(atab.name) lib = self.libs[atab] ntab = lib.tables[atab.name] if mt in ntab.reactions or rx == totrx or rx == absrx: break lib = ntab = None if lib is None: return None # no reaction available E_g = self.src_group_struct E_points = ntab.energy if rx == totrx: rawdata = ntab.sigma_t elif rx == absrx: rawdata = ntab.sigma_a else: ntabrx = ntab.reactions[mt] if ntabrx.IE is None or ntabrx.IE == 0: rawdata = ntabrx.sigma else: rawdata = np.empty(len(E_points), dtype='f8') rawdata[:ntabrx.IE] = 0.0 rawdata[ntabrx.IE:] = ntabrx.sigma if (E_g[0] <= E_g[-1] and E_points[-1] <= E_points[0]) or \ (E_g[0] >= E_g[-1] and E_points[-1] >= E_points[0]): E_points = E_points[::-1] rawdata = rawdata[::-1] rxdata = bins.pointwise_linear_collapse(E_g, E_points, rawdata) return rxdata
def __init__(self, t=0.0, phi=0.0, temp=300.0, tol=1e-7, rxs=None, log=None, *args, **kwargs): """Parameters ---------- t : float Transmutations time [sec]. phi : float or array of floats Neutron flux vector [n/cm^2/sec]. Currently this must either be a scalar or match the group structure of EAF. temp : float, optional Temperature [K] of material, defaults to 300.0. tol : float Tolerance level for chain truncation. rxs : set of ints or strs Reaction ids or names to use in transmutation which produce well-defined children. This set should thus not include fission. If None, then the reactions from EAF are used. log : file-like or None The log file object should be written. A None imples the log is not desired. args : tuple, optional Other arguments ignored for compatibility with other Transmuters. kwargs : dict, optional Other keyword arguments ignored for compatibility with other Transmuters. """ eafds = EAFDataSource() eafds.load(temp=temp) gs = np.array([eafds.src_group_struct[0], eafds.src_group_struct[-1]]) eafds.dst_group_struct = gs self.xscache = XSCache(group_struct=gs, data_source_classes=(NullDataSource,)) self.xscache.data_sources.insert(0, eafds) self.t = t self._phi = None self.phi = phi self.temp = temp self.log = log self.tol = tol if rxs is None: rxs = ['gamma', 'gamma_1', 'gamma_2', 'p', 'p_1', 'p_2', 'd', 'd_1', 'd_2', 't', 't_1', 't_2', 'He3', 'He3_1', 'He3_2', 'a', 'a_1', 'a_2', 'z_2a', 'z_2p', 'z_2p_1', 'z_2p_2', 'z_2n', 'z_2n_1', 'z_2n_2', 'z_3n', 'z_3n_1', 'z_3n_2', 'na', 'na_1', 'na_2', 'z_2na', 'np', 'np_1', 'np_2', 'n2a', 'nd', 'nd_1', 'nd_2', 'nt', 'nt_1', 'nt_2', 'nHe3', 'nHe3_1', 'nHe3_2','z_4n', 'z_4n_1', 'n', 'n_1', 'n_2', 'z_3np'] rxs = set([rxname.id(rx) for rx in rxs]) rxs.discard(rxname.id('fission')) self.rxs = rxs
def reaction(self, nuc, rx, temp=300.0): """Gets the cross section data for this reaction channel either directly from the data source or from the rxcache. Parameters ---------- nuc : int or str A nuclide. rx : int or str Reaction id or name. temp : float, optional Temperature [K] of material, defaults to 300.0. Returns ------- rxdata : ndarray Source cross section data, length src_ngroups. """ nuc = nucname.id(nuc) rx = rxname.id(rx) rxkey = (nuc, rx, temp) if self._USES_TEMP else (nuc, rx) if rxkey not in self.rxcache: self.rxcache[rxkey] = None if self.fullyloaded \ else self._load_reaction(nuc, rx, temp) return self.rxcache[rxkey]
def load(self, temp=300.0): """Loads all EAF into memory. Parameters ---------- temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ rxcache = self.rxcache avail_rx = self._avail_rx absrx = rxname.id('absorption') with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.eaf_xs.eaf_xs for row in node: nuc = row['nuc_zz'] rx = avail_rx[row['rxnum']] xs = row['xs'] rxcache[nuc, rx] = xs abskey = (nuc, absrx) rxcache[abskey] = xs + rxcache.get(abskey, 0.0) self.fullyloaded = True
def generate(self, state, transmute_time): """Runs physics codes on a specific state. First runs OpenMC for transport, then uses the results to run ORIGEN for a single timestep. Parameters ---------- state : namedtuple (State) A namedtuple containing the state parameters. transmute_time : float The length of the time step we would like to run ORIGEN for. Returns ------- results : dict Dict of physics code results. Keys are either nuclide ID's or "fuel" for the full fuel results. """ print("generating for a state with transmute_time {}".format(transmute_time)) if state in self.statelibs: return self.statelibs[state] rc = self.rc k, phi_g, xstab = self.openmc(state) results = {"fuel": {}} results.update(dict(zip(rc.track_nucs, [{} for _ in rc.track_nucs]))) if 'flux' in rc: phi_tot = state.flux elif 'fuel_specific_power' in rc: raise RuntimeError('needs refactor for state') G = len(phi_g) fission_id = rxname.id("fission") if G == 1: fission_xs = {xs[0]: xs[2] * 1e-24 for xs in xstab # xs is in barns not cm2 if xs[1] == fission_id} else: fission_xs = {xs[0]: np.sum(xs[2]) * 1e-24 / len(xs[2]) for xs in xstab # xs is in barns not cm2 if xs[1] == fission_id} fuel_material = self.libs["fuel"]["material"][-1] fuel_material.atoms_per_molecule = sum([self.rc.fuel_chemical_form[m] for m in self.rc.fuel_chemical_form]) fuel_atom_frac = fuel_material.to_atom_frac() fuel_number_density = 6.022e23 * self.rc.fuel_density / \ (fuel_material.molecular_mass() * fuel_material.atoms_per_molecule) number_densities = {nuc: fuel_atom_frac[nuc] * fuel_number_density for nuc in fuel_material.comp} sum_N_i_sig_fi = sum([number_densities[nuc] * fission_xs.get(nuc, 0) for nuc in fuel_material.comp]) sum_N_i_sig_fi = sum_N_i_sig_fi[sum_N_i_sig_fi != 0] fuel_specific_power_mwcc = self.rc.fuel_density * 1e-6 * state.fuel_specific_power # see http://iriaxp.iri.tudelft.nl/~leege/SCALE44/origens.PDF for formula # (search for "the specific power due to fission", on p. 22 of the PDF) phi_tot = sum(3.125e16*fuel_specific_power_mwcc/sum_N_i_sig_fi) results = self.run_all_the_origens(state, transmute_time, phi_tot, results) results['xs'] = xstab results['phi_g'] = {'EAF': self.eafds.src_phi_g.tolist(), 'OpenMC': self.omcds.src_phi_g.tolist()} self.statelibs[state] = results return results
def _load_reaction(self, nuc, rx, temp=300.0): fissrx = rxname.id('fission') absrx = rxname.id('absorption') # Set query condition if rx in self._rx_avail: if py3k: cond = "(from_nuc == {0}) & (reaction_type == {1})" else: cond = "(from_nuc == {0}) & (reaction_type == '{1}')" cond = cond.format(nuc, self._rx_avail[rx].encode()) elif rx == fissrx: cond = 'nuc == {0}'.format(nuc) elif rx == absrx: cond = "(from_nuc == {0}) & (reaction_type != b'c')".format(nuc) else: return None # read & collapse data with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.cinder_xs.fission if rx == fissrx else \ f.root.neutron.cinder_xs.absorption rows = [np.array(row['xs']) for row in node.where(cond)] if 1 == len(rows): rxdata = rows[0] elif 1 < len(rows): rows = np.array(rows) rxdata = rows.sum(axis=0) else: rxdata = None # add fission data to absorption if rx == absrx: fdata = self._load_reaction(nuc, fissrx) if fdata is not None: rxdata = fdata if rxdata is None else rxdata + fdata return rxdata
def test_id_mts(): assert_equal(rxname.id(107), _hash("a")) assert_equal(rxname.id(1), _hash("total")) assert_equal(rxname.id(long(107)), _hash("a")) assert_equal(rxname.id(long(1)), _hash("total")) assert_equal(rxname.id("107"), _hash("a")) assert_equal(rxname.id("1"), _hash("total"))
def test_id_ids(): assert_equal(rxname.id(_hash("a")), _hash("a")) assert_equal(rxname.id(_hash("total")), _hash("total")) assert_equal(rxname.id(long(_hash("a"))), _hash("a")) assert_equal(rxname.id(long(_hash("total"))), _hash("total")) assert_equal(rxname.id(str(_hash("a"))), _hash("a")) assert_equal(rxname.id(str(_hash("total"))), _hash("total"))
def _load_reaction(self, nuc, rx, temp=300.0): """Loads reaction specific data for EAF. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ absrx = rxname.id('absorption') if rx in self._rx_avail: if py3k is True: cond = "(nuc_zz == {0}) & (rxnum == {1})" else: cond = "(nuc_zz == {0}) & (rxnum == '{1}')" cond = cond.format(nuc, self._rx_avail[rx]) elif rx == absrx: cond = "(nuc_zz == {0})".format(nuc) else: return None # Grab data with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.eaf_xs.eaf_xs rows = node.readWhere(cond) #rows = [np.array(row['xs']) for row in node.where(cond)] if len(rows) == 0: rxdata = None elif 1 < len(rows): xss = rows['xs'] rxnums = rows['rxnum'] for rxnum, xs in zip(rxnums, xss): self.rxcache[nuc, self._avail_rx[rxnum]] = xs rxdata = xss.sum(axis=0) else: rxdata = rows[0]['xs'] return rxdata
def test_id_names(): assert_equal(rxname.id("a"), _hash("a")) assert_equal(rxname.id("total"), _hash("total"))
############################################### # rxnames from textwrap import TextWrapper from prettytable import PrettyTable, FRAME from pyne import rxname tw = TextWrapper(initial_indent=" ", subsequent_indent=" ", break_long_words=False) style = {"style": "margin-left:auto;margin-right:auto;"} rxtab = PrettyTable(['reaction', 'id', 'description']) rxtab.align['reaction'] = 'l' rxtab.align['id'] = 'r' rxtab.align['description'] = 'l' for name in sorted(rxname.names): rxtab.add_row(["'" + name + "'", rxname.id(name), rxname.doc(name)]) rxtab = "\n".join(tw.wrap(rxtab.get_html_string(attributes=style))) aliastab = PrettyTable(['alias', 'reaction']) aliastab.align['alias'] = 'l' aliastab.align['reaction'] = 'l' for alias, rxid in sorted(rxname.altnames.items()): aliastab.add_row(["'" + alias + "'", "'" + rxname.name(rxid) + "'"]) aliastab = "\n".join(tw.wrap(aliastab.get_html_string(attributes=style))) _rxname_rst = """**Reactions:** .. raw:: html <div> {0}
class CinderDataSource(DataSource): """Cinder cross section data source. The relevant cinder cross section data must be present in the nuc_data for this data source to exist. This data source does not use material temperature information. Parameters ---------- kwargs : optional Keyword arguments to be sent to base class. """ # 'h' stands for helion or 'He3' _rx_avail = { rxname.id("np_1"): "np *", rxname.id("a_1"): "a *", rxname.id("He3_1"): "h *", rxname.id("z_2p_1"): "2p *", rxname.id("z_3n_1"): "3n *", rxname.id("d_1"): "d *", rxname.id("npd"): "np/d", rxname.id("na"): "na", rxname.id("excited"): "*", rxname.id("nd"): "nd", rxname.id("gamma_1"): "g *", rxname.id("z_3n"): "3n", rxname.id("np"): "np", rxname.id("nt"): "nt", rxname.id("t"): "t", rxname.id("nt_1"): "nt *", rxname.id("z_4n_1"): "4n *", rxname.id("na_1"): "na *", rxname.id("nd_1"): "nd *", rxname.id("t_1"): "t *", rxname.id("a"): "a", rxname.id("z_2p"): "2p", rxname.id("d"): "d", rxname.id("gamma"): "g", rxname.id("He3"): "h", rxname.id("n"): "n", rxname.id("z_4n"): "4n", rxname.id("p"): "p", rxname.id("n_1"): "n *", rxname.id("z_2a"): "2a", rxname.id("z_2n_1"): "2n *", rxname.id("z_2n"): "2n", rxname.id("nHe3_1"): "nh *", rxname.id("p_1"): "p *", # not real or unique absorption reactions # rxname.id(''): "", # rxname.id(''): 'x', # rxname.id(''): 'x *', # rxname.id(''): 'c', # rxname.id('fission'): 'f', } _USES_TEMP = False def __init__(self, **kwargs): super(CinderDataSource, self).__init__(**kwargs) def _load_group_structure(self): """Loads the cinder energy bounds array, E_g, from nuc_data.""" with tb.open_file(nuc_data, "r") as f: E_g = np.array(f.root.neutron.cinder_xs.E_g) self.src_group_struct = E_g @property def exists(self): if self._exists is None: with tb.open_file(nuc_data, "r") as f: self._exists = "/neutron/cinder_xs" in f return self._exists def _load_reaction(self, nuc, rx, temp=300.0): fissrx = rxname.id("fission") absrx = rxname.id("absorption") # Set query condition if rx in self._rx_avail: if py3k: cond = "(from_nuc == {0}) & (reaction_type == {1})" else: cond = "(from_nuc == {0}) & (reaction_type == '{1}')" cond = cond.format(nuc, self._rx_avail[rx].encode()) elif rx == fissrx: cond = "nuc == {0}".format(nuc) elif rx == absrx: cond = "(from_nuc == {0}) & (reaction_type != b'c')".format(nuc) else: return None # read & collapse data with tb.open_file(nuc_data, "r") as f: node = (f.root.neutron.cinder_xs.fission if rx == fissrx else f.root.neutron.cinder_xs.absorption) rows = [np.array(row["xs"]) for row in node.where(cond)] if 1 == len(rows): rxdata = rows[0] elif 1 < len(rows): rows = np.array(rows) rxdata = rows.sum(axis=0) else: rxdata = None # add fission data to absorption if rx == absrx: fdata = self._load_reaction(nuc, fissrx) if fdata is not None: rxdata = fdata if rxdata is None else rxdata + fdata return rxdata
def _parse_decay_dataset(lines, decay_s): """ This parses a gamma ray dataset. It returns a tuple of the parsed data. Parameters ---------- lines : list of str list containing lines from one dataset of an ensdf file decay_s : str string of the decay type Returns ------- Tuple of decay parameters which is described in detail in gamma_rays docs """ gammarays = [] betas = [] alphas = [] ecbp = [] ident = _ident.match(lines[0]) daughter = ident.group(1) daughter_id = abs(_to_id(daughter)) parent = ident.group(2).split()[0] parent = parent.split('(')[0] parents = parent.split(',') if len(parents) > 1: pfinal = abs(_to_id(parents[0])) else: pfinal = abs(_to_id(parents[0][:5])) tfinal = None tfinalerr = None nrbr = None nbbr = None nrbr_err = None nbbr_err = None nb_err = None br_err = None nb = None br = None level = None special = " " goodgray = False parent2 = None for line in lines: level_l = _level_regex.match(line) if level_l is not None: level, half_lifev, from_nuc, \ state, special = _parse_level_record(level_l) continue b_rec = _beta.match(line) if b_rec is not None: dat = _parse_beta_record(b_rec) if parent2 is None: bparent = pfinal else: bparent = parent2 level = 0.0 if level is None else level bdaughter = abs(data.id_from_level(_to_id(daughter), level)) betas.append([bparent, bdaughter, dat[0], 0.0, dat[2]]) bc_rec = _betac.match(line) if bc_rec is not None: bcdat = _parse_beta_continuation_record(bc_rec) if bcdat[0] is not None: if bc_rec.group(2) == 'B': betas[-1][3] = bcdat[0] else: ecbp[-1][3] = bcdat[0] bggc = _gc.match(line) conv = _parse_gamma_continuation_record(bggc, dat[2], dat[8]) if 'K' in conv: ecbp[-1][-3] = conv['K'][0] if 'L' in conv: ecbp[-1][-2] = conv['L'][0] if 'M' in conv: ecbp[-1][-1] = conv['M'][0] a_rec = _alpha.match(line) if a_rec is not None: dat = _parse_alpha_record(a_rec) if parent2 is None: aparent = pfinal else: aparent = parent2 level = 0.0 if level is None else level adaughter = abs(data.id_from_level(_to_id(daughter), level)) alphas.append([aparent, adaughter, dat[0], dat[2]]) ec_rec = _ec.match(line) if ec_rec is not None: dat = _parse_ec_record(ec_rec) if parent2 is None: ecparent = pfinal else: ecparent = parent2 level = 0.0 if level is None else level ecdaughter = abs(data.id_from_level(_to_id(daughter), level)) ecbp.append([ecparent, ecdaughter, dat[0], 0.0, dat[2], dat[4], 0, 0, 0]) continue g_rec = _g.match(line) if g_rec is not None: dat = _parse_gamma_record(g_rec) if dat[0] is not None: gparent = 0 gdaughter = 0 if level is not None: gparent = abs(data.id_from_level(_to_id(daughter), level, special)) dlevel = level - dat[0] gdaughter = abs(data.id_from_level(_to_id(daughter), dlevel, special)) if parent2 is None: gp2 = pfinal else: gp2 = parent2 dat.insert(0, daughter_id) dat.insert(0, gp2) dat.insert(0, gdaughter) dat.insert(0, gparent) for i in range(3): dat.append(0) gammarays.append(dat) goodgray = True else: goodgray = False continue gc_rec = _gc.match(line) if gc_rec is not None and goodgray is True: conv = _parse_gamma_continuation_record(gc_rec, gammarays[-1][6], gammarays[-1][10]) if 'K' in conv: gammarays[-1][-3] = conv['K'][0] if 'L' in conv: gammarays[-1][-2] = conv['L'][0] if 'M' in conv: gammarays[-1][-1] = conv['M'][0] continue n_rec = _norm.match(line) if n_rec is not None: nr, nr_err, nt, nt_err, br, br_err, nb, nb_err, nrbr, nrbr_err = \ _parse_normalization_record(n_rec) if nb is not None and br is not None: nbbr = nb * br if nb_err is not None and br_err is not None and nb_err != 0: nbbr_err = nbbr*((br_err/br) ** 2 * (nb_err/nb) ** 2) ** 0.5 continue np_rec = _normp.match(line) if np_rec is not None: nrbr2, nrbr_err2, ntbr, ntbr_err, nbbr2, nbbr_err2 = \ _parse_production_normalization_record(np_rec) if nrbr2 is not None and nrbr is None: nrbr = nrbr2 nrbr_err = nrbr_err2 if nbbr2 is not None and nbbr is None: nbbr = nbbr2 nbbr_err = nbbr_err2 continue p_rec = _p.match(line) if p_rec is not None: # only 2 parents are supported so this can be here multi = False if parent2 is not None: multi = True pfinal = [parent2,] tfinal = [t,] tfinalerr = [terr,] parent2, t, terr, e, e_err, special = _parse_parent_record(p_rec) parent2 = abs(data.id_from_level(_to_id(parent2), e, special)) if terr is not None and not isinstance(terr, float): terr = (terr[0] + terr[1])/2.0 if multi: tfinal.append(t) tfinalerr.append(terr) pfinal.append(parent2) else: tfinal = t tfinalerr = terr pfinal = parent2 continue if len(gammarays) > 0 or len(alphas) > 0 or len(betas) > 0 or len(ecbp) > 0: if len(parents) > 1 and parent2 is None: pfinal = [] for item in parents: pfinal.append(_to_id(item)) return pfinal, daughter_id, rxname.id(decay_s.strip().lower()), \ tfinal, tfinalerr, \ br, br_err, nrbr, nrbr_err, nbbr, nbbr_err, gammarays, alphas, \ betas, ecbp return None
def levels(filename, levellist=None): """ This takes an ENSDF filename or file object and parses the ADOPTED LEVELS records to assign level numbers by energy. It also parses the different reported decay types and branching ratios. Parameters ---------- filename : str or file Name of ENSDF formatted file or a file-like object containing ENSDF formatted data levellist : list of tuples This is a list object which all newly processed levels will be added to. If it's None a new one will be created. Returns ------- levellist : list of tuples This is a list of all the level data. Each level has base entry with a reaction id of 0 and additional entries for any listed decays. The format of each row is: nuc_id : int The state_id of the level rx_id : int The id of the decay "reaction" in PyNE reaction id form. half_life : float Half life of the state in s level : float energy of the level in keV branch_ratio : float if rx_id != 0 this is the percent of decays in that channel metastable : int metastable id number of the level (if given) special : string single character denoting levels with unknown relation to ground state """ badlist = ["ecsf", "34si", "|b{+-}fission", "{+24}ne", "{+22}ne", "24ne", "b-f", "{+20}o", "2|e", "b++ec", "ecp+ec2p", "ecf", "mg", "ne", "{+20}ne", "{+25}ne", "{+28}mg", "sf(+ec+b+)"] special = "" if levellist is None: levellist = [] if isinstance(filename, str): with open(filename, 'r') as f: dat = f.read() else: dat = filename.read() datasets = dat.split(80 * " " + "\n")[0:-1] for dataset in datasets: lines = dataset.splitlines() ident = re.match(_ident, lines[0]) if ident is None: continue if 'ADOPTED LEVELS' in ident.group(2): leveln = 0 brs = {} level_found = False for line in lines: level_l = _level_regex.match(line) if level_l is not None: if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) branch_percent = float(val.split("(")[0]) levellist.append((nuc_id, rx, half_lifev, level, branch_percent, state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) brs = {} level, half_lifev, from_nuc, state, special = \ _parse_level_record(level_l) if from_nuc is not None: nuc_id = from_nuc + leveln leveln += 1 level_found = True else: level_found = False continue levelc = _level_cont_regex.match(line) if levelc is not None: brs.update(_parse_level_continuation_record(levelc)) continue if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) branch_percent = float(val.split("(")[0]) levellist.append((nuc_id, rx, half_lifev, level, branch_percent, state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) _adjust_ge100_branches(levellist) _adjust_metastables(levellist) _adjust_half_lives(levellist) return levellist
class SimpleDataSource(DataSource): """Simple cross section data source based off of KAERI data. This data source does not use material temperature information. Parameters ---------- kwargs : optional Keyword arguments to be sent to base class. """ _rx_avail = { rxname.id('total'): 't', rxname.id('scattering'): 's', rxname.id('elastic'): 'e', rxname.id('inelastic'): 'i', rxname.id('absorption'): 'a', rxname.id('gamma'): 'gamma', rxname.id('fission'): 'f', rxname.id('alpha'): 'alpha', rxname.id('proton'): 'proton', rxname.id('deut'): 'deut', rxname.id('trit'): 'trit', rxname.id('z_2n'): '2n', rxname.id('z_3n'): '3n', rxname.id('z_4n'): '4n' } def __init__(self, **kwargs): super(SimpleDataSource, self).__init__(**kwargs) @property def exists(self): if self._exists is None: with tb.openFile(nuc_data, 'r') as f: self._exists = ('/neutron/simple_xs' in f) return self._exists _USES_TEMP = False def _load_group_structure(self): """Sets the simple energy bounds array, E_g.""" self.src_group_struct = np.array([14.0, 1.0, 2.53E-8, 0.0], dtype='float64') def _load_reaction(self, nuc, rx, temp=300.0): if rx not in self._rx_avail: return None cond = "nuc == {0}".format(nuc) sig = 'sigma_' + self._rx_avail[rx] with tb.openFile(nuc_data, 'r') as f: simple_xs = f.root.neutron.simple_xs fteen = [row[sig] for row in simple_xs.fourteen_MeV.where(cond)] fissn = [ row[sig] for row in simple_xs.fission_spectrum_ave.where(cond) ] therm = [row[sig] for row in simple_xs.thermal.where(cond)] if 0 == len(therm): therm = [ row[sig] for row in simple_xs.thermal_maxwell_ave.where(cond) ] if 0 == len(fteen) and 0 == len(fissn) and 0 == len(therm): rxdata = None else: rxdata = np.array([fteen[0], fissn[0], therm[0]], dtype='float64') return rxdata def discretize(self, nuc, rx, temp=300.0, src_phi_g=None, dst_phi_g=None): """Discretizes the reaction channel from simple group structure to that of the destination weighted by the group fluxes. Since the simple data source consists of only thermal (2.53E-8 MeV), fission (1 MeV), and 14 MeV data points, the following piecewise functional form is assumed: .. math:: \\sigma(E) = \\sigma(2.53E-8) \\sqrt{\\frac{2.53E-8}{E}} \\sigma(E) = \\frac{\sigma(14) - \\sigma(1)}{14 - 1} (E - 1) + \\sigma(1) Parameters ---------- nuc : int or str A nuclide. rx : int or str Reaction key ('gamma', 'alpha', 'p', etc.) or MT number. temp : float, optional Temperature [K] of material, defaults to 300.0. src_phi_g : array-like, optional IGNORED!!! Included for API compatability dst_phi_g : array-like, optional Group fluxes for the destiniation structure, length dst_ngroups. Returns ------- dst_sigma : ndarray Destination cross section data, length dst_ngroups. """ src_phi_g = self.src_phi_g if src_phi_g is None else np.asarray( src_phi_g) src_sigma = self.reaction(nuc, rx, temp) if src_sigma is None: return None # not the most efficient, but data sizes should be smallish center_g = self._dst_centers dst_sigma = (src_sigma[2] * np.sqrt(2.53E-8)) / np.sqrt(center_g) dst_fissn = ((src_sigma[0] - src_sigma[1])/13.0) * (center_g - 1.0) + \ src_sigma[1] mask = (dst_sigma < dst_fissn) dst_sigma[mask] = dst_fissn[mask] if dst_phi_g is not None: dst_sigma = (dst_sigma * dst_phi_g) / dst_phi_g.sum() return dst_sigma @property def dst_group_struct(self): return self._dst_group_struct @dst_group_struct.setter def dst_group_struct(self, dst_group_struct): if dst_group_struct is None: self._dst_group_struct = None self._dst_centers = None self._dst_ngroups = 0 else: self._dst_group_struct = np.asarray(dst_group_struct) self._dst_centers = (self._dst_group_struct[1:] + self._dst_group_struct[:-1]) / 2.0 self._dst_ngroups = len(dst_group_struct) - 1 self._src_to_dst_matrix = None
def test_id_nucdelta(): assert_equal(rxname.id("U235", "U236"), _hash("absorption")) assert_equal(rxname.id("U235", "Np236", "p"), _hash("absorption")) assert_equal(rxname.id(922350, 912350), _hash("p"))
def test_id_alts(): assert_equal(rxname.id("alpha"), _hash("a")) assert_equal(rxname.id("tot"), _hash("total"))
def pointwise(self, nuc, rx, temp=300.0): """Returns pointwise reaction data from ACE files indexed by OpenMC. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The nuclide temperature in [K]. Returns ------- E_points : array-like The array or energy points that the reaction is evaluated at. rawdata : array-like Raw pointwise reaction data. """ nuc = nucname.id(nuc) rx = rxname.id(rx) try: mt = rxname.mt(rx) except RuntimeError: return None totrx = rxname.id("total") absrx = rxname.id("absorption") ace_tables = self._rank_ace_tables(nuc, temp=temp) lib = ntab = None for atab in ace_tables: if os.path.isfile(atab.abspath or atab.path): if atab not in self.libs: lib = self.libs[atab] = ace.Library(atab.abspath or atab.path) lib.read(atab.name) lib = self.libs[atab] ntab = lib.tables[atab.name] if mt in ntab.reactions or rx == totrx or rx == absrx: break lib = ntab = None if lib is None: return None # no reaction available E_g = self.src_group_struct E_points = ntab.energy if rx == totrx: rawdata = ntab.sigma_t elif rx == absrx: rawdata = ntab.sigma_a else: ntabrx = ntab.reactions[mt] if ntabrx.IE is None or ntabrx.IE == 0: rawdata = ntabrx.sigma else: rawdata = np.empty(len(E_points), dtype="f8") rawdata[:ntabrx.IE] = 0.0 rawdata[ntabrx.IE:] = ntabrx.sigma if (E_g[0] <= E_g[-1] and E_points[-1] <= E_points[0]) or ( E_g[0] >= E_g[-1] and E_points[-1] >= E_points[0]): E_points = E_points[::-1] rawdata = rawdata[::-1] return E_points, rawdata
def levels(filename, levellist=None): """ This takes an ENSDF filename or file object and parses the ADOPTED LEVELS records to assign level numbers by energy. It also parses the different reported decay types and branching ratios. Parameters ---------- filename : str or file Name of ENSDF formatted file or a file-like object containing ENSDF formatted data levellist : list of tuples This is a list object which all newly processed levels will be added to. If it's None a new one will be created. Returns ------- levellist : list of tuples This is a list of all the level data. Each level has base entry with a reaction id of 0 and additional entries for any listed decays. The format of each row is: nuc_id : int The state_id of the level rx_id : int The id of the decay "reaction" in PyNE reaction id form. half_life : float Half life of the state in s level : float energy of the level in keV branch_ratio : float if rx_id != 0 this is the percent of decays in that channel metastable : int metastable id number of the level (if given) special : string single character denoting levels with unknown relation to ground state """ badlist = ["ecsf", "34si", "|b{+-}fission", "{+24}ne", "{+22}ne", "24ne", "b-f", "{+20}o", "2|e", "b++ec", "ecp+ec2p", "ecf", "mg", "ne", "{+20}ne", "{+25}ne", "{+28}mg", "sf(+ec+b+)"] special = "" if levellist is None: levellist = [] if isinstance(filename, str): with open(filename, 'r') as f: dat = f.read() else: dat = filename.read() datasets = dat.split(80 * " " + "\n")[0:-1] for dataset in datasets: lines = dataset.splitlines() ident = re.match(_ident, lines[0]) if ident is None: continue if 'ADOPTED LEVELS' in ident.group(2): leveln = 0 brs = {} level_found = False for line in lines: level_l = _level_regex.match(line) if level_l is not None: if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append((nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) brs = {} level, half_lifev, from_nuc, state, special = \ _parse_level_record(level_l) if from_nuc is not None: nuc_id = from_nuc + leveln leveln += 1 level_found = True else: level_found = False continue levelc = _level_cont_regex.match(line) if levelc is not None: brs.update(_parse_level_continuation_record(levelc)) continue if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append((nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) return levellist
def _parse_decay_dataset(lines, decay_s): """ This parses a gamma ray dataset. It returns a tuple of the parsed data. Parameters ---------- lines : list of str list containing lines from one dataset of an ensdf file decay_s : str string of the decay type Returns ------- Tuple of decay parameters which is described in detail in gamma_rays docs """ gammarays = [] betas = [] alphas = [] ecbp = [] ident = _ident.match(lines[0]) daughter = ident.group(1) daughter_id = _to_id(daughter) parent = ident.group(2).split()[0] parent = parent.split('(')[0] parents = parent.split(',') if len(parents) > 1: pfinal = _to_id(parents[0]) else: pfinal = _to_id(parents[0][:5]) tfinal = None tfinalerr = None nrbr = None nbbr = None nrbr_err = None nbbr_err = None nb_err = None br_err = None nb = None br = None level = None special = " " goodgray = False parent2 = None for line in lines: level_l = _level_regex.match(line) if level_l is not None: level, half_lifev, from_nuc, \ state, special = _parse_level_record(level_l) continue b_rec = _beta.match(line) if b_rec is not None: dat = _parse_beta_record(b_rec) if parent2 is None: bparent = pfinal else: bparent = parent2 level = 0.0 if level is None else level bdaughter = data.id_from_level(_to_id(daughter), level) betas.append([bparent, bdaughter, dat[0], 0.0, dat[2]]) bc_rec = _betac.match(line) if bc_rec is not None: bcdat = _parse_beta_continuation_record(bc_rec) if bcdat[0] is not None: if bc_rec.group(2) == 'B': betas[-1][3] = bcdat[0] else: ecbp[-1][3] = bcdat[0] bggc = _gc.match(line) conv = _parse_gamma_continuation_record(bggc, dat[2], dat[8]) if 'K' in conv: ecbp[-1][-3] = conv['K'][0] if 'L' in conv: ecbp[-1][-2] = conv['L'][0] if 'M' in conv: ecbp[-1][-1] = conv['M'][0] a_rec = _alpha.match(line) if a_rec is not None: dat = _parse_alpha_record(a_rec) if parent2 is None: aparent = pfinal else: aparent = parent2 level = 0.0 if level is None else level adaughter = data.id_from_level(_to_id(daughter), level) alphas.append((aparent, adaughter, dat[0], dat[2])) ec_rec = _ec.match(line) if ec_rec is not None: dat = _parse_ec_record(ec_rec) if parent2 is None: ecparent = pfinal else: ecparent = parent2 level = 0.0 if level is None else level ecdaughter = data.id_from_level(_to_id(daughter), level) ecbp.append([ecparent, ecdaughter, dat[0], 0.0, dat[2], dat[4], 0, 0, 0]) continue g_rec = _g.match(line) if g_rec is not None: dat = _parse_gamma_record(g_rec) if dat[0] is not None: gparent = 0 gdaughter = 0 if level is not None: gparent = data.id_from_level(_to_id(daughter), level, special) dlevel = level - dat[0] gdaughter = data.id_from_level(_to_id(daughter), dlevel, special) if parent2 is None: gp2 = pfinal else: gp2 = parent2 dat.insert(0, daughter_id) dat.insert(0, gp2) dat.insert(0, gdaughter) dat.insert(0, gparent) for i in range(3): dat.append(0) gammarays.append(dat) goodgray = True else: goodgray = False continue gc_rec = _gc.match(line) if gc_rec is not None and goodgray is True: conv = _parse_gamma_continuation_record(gc_rec, gammarays[-1][6], gammarays[-1][10]) if 'K' in conv: gammarays[-1][-3] = conv['K'][0] if 'L' in conv: gammarays[-1][-2] = conv['L'][0] if 'M' in conv: gammarays[-1][-1] = conv['M'][0] continue n_rec = _norm.match(line) if n_rec is not None: nr, nr_err, nt, nt_err, br, br_err, nb, nb_err, nrbr, nrbr_err = \ _parse_normalization_record(n_rec) if nb is not None and br is not None: nbbr = nb * br if nb_err is not None and br_err is not None and nb_err != 0: nbbr_err = nbbr*((br_err/br) ** 2 * (nb_err/nb) ** 2) ** 0.5 continue np_rec = _normp.match(line) if np_rec is not None: nrbr2, nrbr_err2, ntbr, ntbr_err, nbbr2, nbbr_err2 = \ _parse_production_normalization_record(np_rec) if nrbr2 is not None and nrbr is None: nrbr = nrbr2 nrbr_err = nrbr_err2 if nbbr2 is not None and nbbr is None: nbbr = nbbr2 nbbr_err = nbbr_err2 continue p_rec = _p.match(line) if p_rec is not None: # only 2 parents are supported so this can be here multi = False if parent2 is not None: multi = True pfinal = [parent2,] tfinal = [t,] tfinalerr = [terr,] parent2, t, terr, e, e_err, special = _parse_parent_record(p_rec) parent2 = data.id_from_level(_to_id(parent2), e, special) if terr is not None and not isinstance(terr, float): terr = (terr[0] + terr[1])/2.0 if multi: tfinal.append(t) tfinalerr.append(terr) pfinal.append(parent2) else: tfinal = t tfinalerr = terr pfinal = parent2 continue if len(gammarays) > 0 or len(alphas) > 0 or len(betas) > 0 or len(ecbp) > 0: if len(parents) > 1 and parent2 is None: pfinal = [] for item in parents: pfinal.append(_to_id(item)) return pfinal, daughter_id, rxname.id(decay_s.strip().lower()), \ tfinal, tfinalerr, \ br, br_err, nrbr, nrbr_err, nbbr, nbbr_err, gammarays, alphas, \ betas, ecbp return None
def levels(filename, levellist=None, lmap=None, lcount=0): badlist = ["ecsf", "34si", "|b{+-}fission", "{+24}ne", "{+22}ne", "24ne", "b-f", "{+20}o", "2|e", "b++ec", "ecp+ec2p", "ecf", "mg", "ne", "{+20}ne", "{+25}ne", "{+28}mg", "sf(+ec+b+)"] special = "" if levellist is None: levellist = [] if lmap is None: lmap = dict() if isinstance(filename, str): with open(filename, 'r') as f: dat = f.read() else: dat = filename.read() datasets = dat.split(80 * " " + "\n")[0:-1] for dataset in datasets: lines = dataset.splitlines() ident = re.match(_ident, lines[0]) if ident is None: continue if 'ADOPTED LEVELS' in ident.group(2): leveln = 0 brs = {} level_found = False for line in lines: level_l = _level_regex.match(line) if level_l is not None: if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append((nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) brs = {} level, half_lifev, from_nuc, state, special = \ _parse_level_record(level_l) if from_nuc is not None: nuc_id = from_nuc + leveln if leveln == 0: lmap.update({nuc_id: lcount}) leveln += 1 lcount += 1 level_found = True else: level_found = False continue levelc = _level_cont_regex.match(line) if levelc is not None: brs.update(_parse_level_continuation_record(levelc)) continue if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append((nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) return levellist
class OpenMCDataSource(DataSource): """Data source for ACE data that is listed in an OpenMC cross_sections.xml file. This data source discretizes the reactions to a given group stucture when the reactions are loaded in. Reseting this source group structure will clear the reaction cache. """ self_shield_reactions = { rxname.id('fission'), rxname.id('gamma'), rxname.id('total') } def __init__(self, cross_sections=None, src_group_struct=None, **kwargs): """Parameters ---------- cross_sections : openmc.CrossSections or string or file-like, optional Path or file to OpenMC cross_sections.xml src_group_struct : array-like, optional The group structure to discretize the ACE data to, defaults to ``np.logspace(1, -9, 101)``. kwargs : optional Keyword arguments to be sent to DataSource base class. """ if not isinstance(cross_sections, openmc.CrossSections): cross_sections = cross_sections or os.getenv('CROSS_SECTIONS') cross_sections = openmc.CrossSections(f=cross_sections) self.cross_sections = cross_sections self._src_group_struct = src_group_struct super(OpenMCDataSource, self).__init__(**kwargs) self.libs = {} # cross section libraries, index by openmc.AceTables @property def exists(self): if self._exists is None: self._exists = len(self.cross_sections.ace_tables) > 0 return self._exists def _load_group_structure(self): if self._src_group_struct is None: self._src_group_struct = np.logspace(1, -9, 101) self.src_group_struct = self._src_group_struct def pointwise(self, nuc, rx, temp=300.0): """Returns pointwise reaction data from ACE files indexed by OpenMC. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The nuclide temperature in [K]. Returns ------- E_points : array-like The array or energy points that the reaction is evaluated at. rawdata : array-like Raw pointwise reaction data. """ nuc = nucname.id(nuc) rx = rxname.id(rx) try: mt = rxname.mt(rx) except RuntimeError: return None totrx = rxname.id('total') absrx = rxname.id('absorption') ace_tables = self._rank_ace_tables(nuc, temp=temp) lib = ntab = None for atab in ace_tables: if os.path.isfile(atab.abspath or atab.path): if atab not in self.libs: lib = self.libs[atab] = ace.Library(atab.abspath or atab.path) lib.read(atab.name) lib = self.libs[atab] ntab = lib.tables[atab.name] if mt in ntab.reactions or rx == totrx or rx == absrx: break lib = ntab = None if lib is None: return None # no reaction available E_g = self.src_group_struct E_points = ntab.energy if rx == totrx: rawdata = ntab.sigma_t elif rx == absrx: rawdata = ntab.sigma_a else: ntabrx = ntab.reactions[mt] if ntabrx.IE is None or ntabrx.IE == 0: rawdata = ntabrx.sigma else: rawdata = np.empty(len(E_points), dtype='f8') rawdata[:ntabrx.IE] = 0.0 rawdata[ntabrx.IE:] = ntabrx.sigma if (E_g[0] <= E_g[-1] and E_points[-1] <= E_points[0]) or \ (E_g[0] >= E_g[-1] and E_points[-1] >= E_points[0]): E_points = E_points[::-1] rawdata = rawdata[::-1] return E_points, rawdata def _load_reaction(self, nuc, rx, temp=300.0): """Loads reaction data from ACE files indexed by OpenMC. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The nuclide temperature in [K]. """ rtn = self.pointwise(nuc, rx, temp=temp) if rtn is None: return E_points, rawdata = rtn E_g = self.src_group_struct if self.atom_dens.get( nuc, 0.0) > 1.0E19 and rx in self.self_shield_reactions: rxdata = self.self_shield(nuc, rx, temp, E_points, rawdata) else: rxdata = bins.pointwise_linear_collapse(E_g, E_points, rawdata) return rxdata def self_shield(self, nuc, rx, temp, E_points, xs_points): """Calculates the self shielded cross section for a given nuclide and reaction. This calculation uses the Bonderanko method. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The nuclide temperature in [K]. E_points : array like The point wise energies. xs_points : array like Point wise cross sections Returns ------- rxdata : array like collapsed self shielded cross section for nuclide nuc and reaction rx """ sigb = self.bkg_xs(nuc, temp=temp) e_n = self.src_group_struct sig_b = np.ones(len(E_points), 'f8') for n in range(len(sigb)): sig_b[(e_n[n] <= E_points) & (E_points <= e_n[n + 1])] = sigb[n] rtn = self.pointwise(nuc, 'total', temp) if rtn is None: sig_t = 0.0 else: sig_t = rtn[1] numer = bins.pointwise_linear_collapse( self.src_group_struct, E_points, xs_points / (E_points * (sig_b + sig_t))) denom = bins.pointwise_linear_collapse( self.src_group_struct, E_points, 1.0 / (E_points * (sig_b + sig_t))) return numer / denom def bkg_xs(self, nuc, temp=300): """Calculates the background cross section for a nuclide (nuc) Parameters ---------- nuc : int Nuclide id. temp : float, optional The nuclide temperature in [K]. Returns ------- sig_b : array like Group wise background cross sections. """ e_n = self.src_group_struct sig_b = np.zeros(self.src_ngroups, float) for i, a in self.atom_dens.items(): if i == nuc: continue rtn = self.pointwise(i, 'total', temp) if rtn is None: continue sig_b += a * bins.pointwise_linear_collapse(e_n, rtn[0], rtn[1]) return sig_b / self.atom_dens.get(nuc, 0.0) def _rank_ace_tables(self, nuc, temp=300.0): """Filters and sorts the potential ACE tables based on nucliude and temperature. """ tabs = [t for t in self.cross_sections.ace_tables if t.nucid == nuc] if len(tabs) == 0: return tabs temps = {t.temperature for t in tabs} temps = sorted(temps, key=lambda s: abs(float(s) - temp * MeV_per_K)) nearest_temp = temps[0] tabs = [t for t in tabs if t.temperature == nearest_temp] tabs.sort(reverse=True, key=lambda t: t.name) return tabs def load(self, temp=300.0): """Loads the entire data source into memory. This can be expensive for lots of ACE data. Parameters ---------- temp : float, optional Temperature [K] of material, defaults to 300.0. """ for atab in self.cross_sections.ace_tables: if os.path.isfile(atab.abspath or atab.path): lib = self.libs[atab] = ace.Library(atab.abspath or atab.path) lib.read(atab.name)
class EAFDataSource(DataSource): """European Activation File cross section data source. The relevant EAF cross section data must be present in the nuc-data for this data source to exist. Parameters ---------- kwargs : optional Keyword arguments to be sent to base class. Notes ----- EAF data does not use temperature information. """ # MT#s included in the EAF data _rx_avail = { rxname.id("gamma"): b"1020", rxname.id("gamma_1"): b"1021", rxname.id("gamma_2"): b"1022", rxname.id("p"): b"1030", rxname.id("p_1"): b"1031", rxname.id("p_2"): b"1032", rxname.id("d"): b"1040", rxname.id("d_1"): b"1041", rxname.id("d_2"): b"1042", rxname.id("t"): b"1050", rxname.id("t_1"): b"1051", rxname.id("t_2"): b"1052", rxname.id("He3"): b"1060", rxname.id("He3_1"): b"1061", rxname.id("He3_2"): b"1062", rxname.id("a"): b"1070", rxname.id("a_1"): b"1071", rxname.id("a_2"): b"1072", rxname.id("z_2a"): b"1080", rxname.id("z_2p"): b"1110", rxname.id("z_2p_1"): b"1111", rxname.id("z_2p_2"): b"1112", rxname.id("z_2n"): b"160", rxname.id("z_2n_1"): b"161", rxname.id("z_2n_2"): b"162", rxname.id("z_3n"): b"170", rxname.id("z_3n_1"): b"171", rxname.id("z_3n_2"): b"172", rxname.id("fission"): b"180", rxname.id("na"): b"220", rxname.id("na_1"): b"221", rxname.id("na_2"): b"222", rxname.id("z_2na"): b"240", rxname.id("np"): b"280", rxname.id("np_1"): b"281", rxname.id("np_2"): b"282", rxname.id("n2a"): b"290", rxname.id("nd"): b"320", rxname.id("nd_1"): b"321", rxname.id("nd_2"): b"322", rxname.id("nt"): b"330", rxname.id("nt_1"): b"331", rxname.id("nt_2"): b"332", rxname.id("nHe3"): b"340", rxname.id("nHe3_1"): b"341", rxname.id("nHe3_2"): b"342", rxname.id("z_4n"): b"370", rxname.id("z_4n_1"): b"371", rxname.id("n"): b"40", rxname.id("n_1"): b"41", rxname.id("n_2"): b"42", rxname.id("z_3np"): b"420", } _avail_rx = dict([_[::-1] for _ in _rx_avail.items()]) _USES_TEMP = False def __init__(self, **kwargs): super(EAFDataSource, self).__init__(**kwargs) def _load_group_structure(self): """Loads the EAF energy bounds array, E_g, from nuc_data.""" with tb.open_file(nuc_data, "r") as f: E_g = np.array(f.root.neutron.eaf_xs.E_g) self.src_group_struct = E_g @property def exists(self): if self._exists is None: with tb.open_file(nuc_data, "r") as f: self._exists = "/neutron/eaf_xs" in f return self._exists def _load_reaction(self, nuc, rx, temp=300.0): """Loads reaction specific data for EAF. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ absrx = rxname.id("absorption") if rx in self._rx_avail: if py3k is True: cond = "(nuc_zz == {0}) & (rxnum == {1})" else: cond = "(nuc_zz == {0}) & (rxnum == '{1}')" cond = cond.format(nuc, self._rx_avail[rx]) elif rx == absrx: cond = "(nuc_zz == {0})".format(nuc) else: return None # Grab data with tb.open_file(nuc_data, "r") as f: node = f.root.neutron.eaf_xs.eaf_xs rows = node.read_where(cond) # rows = [np.array(row['xs']) for row in node.where(cond)] if len(rows) == 0: rxdata = None elif 1 < len(rows): xss = rows["xs"] rxnums = rows["rxnum"] for rxnum, xs in zip(rxnums, xss): self.rxcache[nuc, self._avail_rx[rxnum]] = xs rxdata = xss.sum(axis=0) else: rxdata = rows[0]["xs"] return rxdata def load(self, temp=300.0): """Loads all EAF into memory. Parameters ---------- temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ rxcache = self.rxcache avail_rx = self._avail_rx absrx = rxname.id("absorption") with tb.open_file(nuc_data, "r") as f: node = f.root.neutron.eaf_xs.eaf_xs for row in node: nuc = row["nuc_zz"] rx = avail_rx[row["rxnum"]] xs = row["xs"] rxcache[nuc, rx] = xs abskey = (nuc, absrx) rxcache[abskey] = xs + rxcache.get(abskey, 0.0) self.fullyloaded = True
class EAFDataSource(DataSource): """European Activation File cross section data source. The relevant EAF cross section data must be present in the nuc-data for this data source to exist. Parameters ---------- kwargs : optional Keyword arguments to be sent to base class. Notes ----- EAF data does not use temperature information. """ # MT#s included in the EAF data _rx_avail = { rxname.id('gamma'): b'1020', rxname.id('gamma_1'): b'1021', rxname.id('gamma_2'): b'1022', rxname.id('p'): b'1030', rxname.id('p_1'): b'1031', rxname.id('p_2'): b'1032', rxname.id('d'): b'1040', rxname.id('d_1'): b'1041', rxname.id('d_2'): b'1042', rxname.id('t'): b'1050', rxname.id('t_1'): b'1051', rxname.id('t_2'): b'1052', rxname.id('He3'): b'1060', rxname.id('He3_1'): b'1061', rxname.id('He3_2'): b'1062', rxname.id('a'): b'1070', rxname.id('a_1'): b'1071', rxname.id('a_2'): b'1072', rxname.id('z_2a'): b'1080', rxname.id('z_2p'): b'1110', rxname.id('z_2p_1'): b'1111', rxname.id('z_2p_2'): b'1112', rxname.id('z_2n'): b'160', rxname.id('z_2n_1'): b'161', rxname.id('z_2n_2'): b'162', rxname.id('z_3n'): b'170', rxname.id('z_3n_1'): b'171', rxname.id('z_3n_2'): b'172', rxname.id('fission'): b'180', rxname.id('na'): b'220', rxname.id('na_1'): b'221', rxname.id('na_2'): b'222', rxname.id('z_2na'): b'240', rxname.id('np'): b'280', rxname.id('np_1'): b'281', rxname.id('np_2'): b'282', rxname.id('n2a'): b'290', rxname.id('nd'): b'320', rxname.id('nd_1'): b'321', rxname.id('nd_2'): b'322', rxname.id('nt'): b'330', rxname.id('nt_1'): b'331', rxname.id('nt_2'): b'332', rxname.id('nHe3'): b'340', rxname.id('nHe3_1'): b'341', rxname.id('nHe3_2'): b'342', rxname.id('z_4n'): b'370', rxname.id('z_4n_1'): b'371', rxname.id('n'): b'40', rxname.id('n_1'): b'41', rxname.id('n_2'): b'42', rxname.id('z_3np'): b'420', } _avail_rx = dict([_[::-1] for _ in _rx_avail.items()]) _USES_TEMP = False def __init__(self, **kwargs): super(EAFDataSource, self).__init__(**kwargs) def _load_group_structure(self): """Loads the EAF energy bounds array, E_g, from nuc_data.""" with tb.openFile(nuc_data, 'r') as f: E_g = np.array(f.root.neutron.eaf_xs.E_g) self.src_group_struct = E_g @property def exists(self): if self._exists is None: with tb.openFile(nuc_data, 'r') as f: self._exists = ('/neutron/eaf_xs' in f) return self._exists def _load_reaction(self, nuc, rx, temp=300.0): """Loads reaction specific data for EAF. Parameters ---------- nuc : int Nuclide id. rx : int Reaction id. temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ absrx = rxname.id('absorption') if rx in self._rx_avail: if py3k is True: cond = "(nuc_zz == {0}) & (rxnum == {1})" else: cond = "(nuc_zz == {0}) & (rxnum == '{1}')" cond = cond.format(nuc, self._rx_avail[rx]) elif rx == absrx: cond = "(nuc_zz == {0})".format(nuc) else: return None # Grab data with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.eaf_xs.eaf_xs rows = node.readWhere(cond) #rows = [np.array(row['xs']) for row in node.where(cond)] if len(rows) == 0: rxdata = None elif 1 < len(rows): xss = rows['xs'] rxnums = rows['rxnum'] for rxnum, xs in zip(rxnums, xss): self.rxcache[nuc, self._avail_rx[rxnum]] = xs rxdata = xss.sum(axis=0) else: rxdata = rows[0]['xs'] return rxdata def load(self, temp=300.0): """Loads all EAF into memory. Parameters ---------- temp : float, optional The material temperature Notes ----- EAF data does not use temperature information (temp). """ rxcache = self.rxcache avail_rx = self._avail_rx absrx = rxname.id('absorption') with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.eaf_xs.eaf_xs for row in node: nuc = row['nuc_zz'] rx = avail_rx[row['rxnum']] xs = row['xs'] rxcache[nuc, rx] = xs abskey = (nuc, absrx) rxcache[abskey] = xs + rxcache.get(abskey, 0.0) self.fullyloaded = True
class CinderDataSource(DataSource): """Cinder cross section data source. The relevant cinder cross section data must be present in the nuc_data for this data source to exist. This data source does not use material temperature information. Parameters ---------- kwargs : optional Keyword arguments to be sent to base class. """ # 'h' stands for helion or 'He3' _rx_avail = { rxname.id('np_1'): 'np *', rxname.id('a_1'): 'a *', rxname.id('He3_1'): 'h *', rxname.id('z_2p_1'): '2p *', rxname.id('z_3n_1'): '3n *', rxname.id('d_1'): 'd *', rxname.id('npd'): 'np/d', rxname.id('na'): 'na', rxname.id('excited'): '*', rxname.id('nd'): 'nd', rxname.id('gamma_1'): 'g *', rxname.id('z_3n'): '3n', rxname.id('np'): 'np', rxname.id('nt'): 'nt', rxname.id('t'): 't', rxname.id('nt_1'): 'nt *', rxname.id('z_4n_1'): '4n *', rxname.id('na_1'): 'na *', rxname.id('nd_1'): 'nd *', rxname.id('t_1'): 't *', rxname.id('a'): 'a', rxname.id('z_2p'): '2p', rxname.id('d'): 'd', rxname.id('gamma'): 'g', rxname.id('He3'): 'h', rxname.id('n'): 'n', rxname.id('z_4n'): '4n', rxname.id('p'): 'p', rxname.id('n_1'): 'n *', rxname.id('z_2a'): '2a', rxname.id('z_2n_1'): '2n *', rxname.id('z_2n'): '2n', rxname.id('nHe3_1'): 'nh *', rxname.id('p_1'): 'p *', # not real or unique absorption reactions #rxname.id(''): "", #rxname.id(''): 'x', #rxname.id(''): 'x *', #rxname.id(''): 'c', #rxname.id('fission'): 'f', } _USES_TEMP = False def __init__(self, **kwargs): super(CinderDataSource, self).__init__(**kwargs) def _load_group_structure(self): """Loads the cinder energy bounds array, E_g, from nuc_data.""" with tb.openFile(nuc_data, 'r') as f: E_g = np.array(f.root.neutron.cinder_xs.E_g) self.src_group_struct = E_g @property def exists(self): if self._exists is None: with tb.openFile(nuc_data, 'r') as f: self._exists = ('/neutron/cinder_xs' in f) return self._exists def _load_reaction(self, nuc, rx, temp=300.0): fissrx = rxname.id('fission') absrx = rxname.id('absorption') # Set query condition if rx in self._rx_avail: if py3k: cond = "(from_nuc == {0}) & (reaction_type == {1})" else: cond = "(from_nuc == {0}) & (reaction_type == '{1}')" cond = cond.format(nuc, self._rx_avail[rx].encode()) elif rx == fissrx: cond = 'nuc == {0}'.format(nuc) elif rx == absrx: cond = "(from_nuc == {0}) & (reaction_type != b'c')".format(nuc) else: return None # read & collapse data with tb.openFile(nuc_data, 'r') as f: node = f.root.neutron.cinder_xs.fission if rx == fissrx else \ f.root.neutron.cinder_xs.absorption rows = [np.array(row['xs']) for row in node.where(cond)] if 1 == len(rows): rxdata = rows[0] elif 1 < len(rows): rows = np.array(rows) rxdata = rows.sum(axis=0) else: rxdata = None # add fission data to absorption if rx == absrx: fdata = self._load_reaction(nuc, fissrx) if fdata is not None: rxdata = fdata if rxdata is None else rxdata + fdata return rxdata
def levels(filename, levellist=None, lmap=None, lcount=0): badlist = [ "ecsf", "34si", "|b{+-}fission", "{+24}ne", "{+22}ne", "24ne", "b-f", "{+20}o", "2|e", "b++ec", "ecp+ec2p", "ecf", "mg", "ne", "{+20}ne", "{+25}ne", "{+28}mg", "sf(+ec+b+)" ] special = "" if levellist is None: levellist = [] if lmap is None: lmap = dict() if isinstance(filename, str): with open(filename, 'r') as f: dat = f.read() else: dat = filename.read() datasets = dat.split(80 * " " + "\n")[0:-1] for dataset in datasets: lines = dataset.splitlines() ident = re.match(_ident, lines[0]) if ident is None: continue if 'ADOPTED LEVELS' in ident.group(2): leveln = 0 brs = {} level_found = False for line in lines: level_l = _level_regex.match(line) if level_l is not None: if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append( (nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append((nuc_id, 0, half_lifev, level, 0.0, state, special)) brs = {} level, half_lifev, from_nuc, state, special = \ _parse_level_record(level_l) if from_nuc is not None: nuc_id = from_nuc + leveln if leveln == 0: lmap.update({nuc_id: lcount}) leveln += 1 lcount += 1 level_found = True else: level_found = False continue levelc = _level_cont_regex.match(line) if levelc is not None: brs.update(_parse_level_continuation_record(levelc)) continue if len(brs) > 0: for key, val in brs.items(): goodkey = True keystrip = key.replace("%", "").lower() for item in badlist: if keystrip == item: goodkey = False if goodkey is True: rx = rxname.id(keystrip) levellist.append((nuc_id, rx, half_lifev, level, val.split("(")[0], state, special)) if level_found is True: levellist.append( (nuc_id, 0, half_lifev, level, 0.0, state, special)) return levellist