def from_hdf5(cls, group): """Generate angular distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.AngleDistribution Angular distribution """ energy = group['energy'].value data = group['mu'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] mu = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines j = offsets[i] if i < n_energy - 1: n = offsets[i+1] - j else: n = data.shape[1] - j interp = INTERPOLATION_SCHEME[interpolation[i]] mu_i = Tabular(data[0, j:j+n], data[1, j:j+n], interp) mu_i.c = data[2, j:j+n] mu.append(mu_i) return cls(energy, mu)
def from_endf(cls, file_obj): """Generate correlated angle-energy distribution from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of a section for a correlated angle-energy distribution Returns ------- openmc.data.CorrelatedAngleEnergy Correlated angle-energy distribution """ params, tab2 = get_tab2_record(file_obj) lep = params[3] ne = params[5] energy = np.zeros(ne) n_discrete_energies = np.zeros(ne, dtype=int) energy_out = [] mu = [] for i in range(ne): items, values = get_list_record(file_obj) energy[i] = items[1] n_discrete_energies[i] = items[2] # TODO: separate out discrete lines n_angle = items[3] n_energy_out = items[5] values = np.asarray(values) values.shape = (n_energy_out, n_angle + 2) # Outgoing energy distribution at the i-th incoming energy eout_i = values[:, 0] eout_p_i = values[:, 1] energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep], ignore_negative=True) energy_out.append(energy_out_i) # Legendre coefficients used for angular distributions mu_i = [] for j in range(n_energy_out): mu_i.append(Legendre(values[j, 1:])) mu.append(mu_i) return cls(tab2.breakpoints, tab2.interpolation, energy, energy_out, mu)
def from_endf(cls, file_obj): """Generate Kalbach-Mann distribution from an ENDF evaluation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of the Kalbach-Mann distribution Returns ------- openmc.data.KalbachMann Kalbach-Mann energy-angle distribution """ params, tab2 = get_tab2_record(file_obj) lep = params[3] ne = params[5] energy = np.zeros(ne) n_discrete_energies = np.zeros(ne, dtype=int) energy_out = [] precompound = [] slope = [] for i in range(ne): items, values = get_list_record(file_obj) energy[i] = items[1] n_discrete_energies[i] = items[2] # TODO: split out discrete energies n_angle = items[3] n_energy_out = items[5] values = np.asarray(values) values.shape = (n_energy_out, n_angle + 2) # Outgoing energy distribution at the i-th incoming energy eout_i = values[:,0] eout_p_i = values[:,1] energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep]) energy_out.append(energy_out_i) # Precompound and slope factors for Kalbach-Mann r_i = values[:,2] if n_angle == 2: a_i = values[:,3] else: a_i = np.zeros_like(r_i) precompound.append(Tabulated1D(eout_i, r_i)) slope.append(Tabulated1D(eout_i, a_i)) return cls(tab2.breakpoints, tab2.interpolation, energy, energy_out, precompound, slope)
def from_hdf5(cls, group): """Generate Kalbach-Mann distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.KalbachMann Kalbach-Mann energy distribution """ interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] energy = group['energy'][()] data = group['distribution'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] n_discrete_lines = data.attrs['n_discrete_lines'] energy_out = [] precompound = [] slope = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines j = offsets[i] if i < n_energy - 1: n = offsets[i+1] - j else: n = data.shape[1] - j m = n_discrete_lines[i] # Create discrete distribution if lines are present if m > 0: eout_discrete = Discrete(data[0, j:j+m], data[1, j:j+m]) eout_discrete.c = data[2, j:j+m] p_discrete = eout_discrete.c[-1] # Create continuous distribution if m < n: interp = INTERPOLATION_SCHEME[interpolation[i]] eout_continuous = Tabular(data[0, j+m:j+n], data[1, j+m:j+n], interp) eout_continuous.c = data[2, j+m:j+n] # If both continuous and discrete are present, create a mixture # distribution if m == 0: eout_i = eout_continuous elif m == n: eout_i = eout_discrete else: eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) # Precompound factor and slope are on rows 3 and 4, respectively km_r = Tabulated1D(data[0, j:j+n], data[3, j:j+n]) km_a = Tabulated1D(data[0, j:j+n], data[4, j:j+n]) energy_out.append(eout_i) precompound.append(km_r) slope.append(km_a) return cls(energy_breakpoints, energy_interpolation, energy, energy_out, precompound, slope)
def from_endf(cls, ev, mt): """Generate an angular distribution from an ENDF evaluation Parameters ---------- ev : openmc.data.endf.Evaluation ENDF evaluation mt : int The MT value of the reaction to get angular distributions for Returns ------- openmc.data.AngleDistribution Angular distribution """ file_obj = StringIO(ev.section[4, mt]) # Read HEAD record items = get_head_record(file_obj) lvt = items[2] ltt = items[3] # Read CONT record items = get_cont_record(file_obj) li = items[2] nk = items[4] center_of_mass = (items[3] == 2) # Check for obsolete energy transformation matrix. If present, just skip # it and keep reading if lvt > 0: warn('Obsolete energy transformation matrix in MF=4 angular ' 'distribution.') for _ in range((nk + 5) // 6): file_obj.readline() if ltt == 0 and li == 1: # Purely isotropic energy = np.array([0., ev.info['energy_max']]) mu = [Uniform(-1., 1.), Uniform(-1., 1.)] elif ltt == 1 and li == 0: # Legendre polynomial coefficients params, tab2 = get_tab2_record(file_obj) n_energy = params[5] energy = np.zeros(n_energy) mu = [] for i in range(n_energy): items, al = get_list_record(file_obj) temperature = items[0] energy[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) elif ltt == 2 and li == 0: # Tabulated probability distribution params, tab2 = get_tab2_record(file_obj) n_energy = params[5] energy = np.zeros(n_energy) mu = [] for i in range(n_energy): params, f = get_tab1_record(file_obj) temperature = params[0] energy[i] = params[1] if f.n_regions > 1: raise NotImplementedError( 'Angular distribution with multiple ' 'interpolation regions not supported.') mu.append( Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]])) elif ltt == 3 and li == 0: # Legendre for low energies / tabulated for high energies params, tab2 = get_tab2_record(file_obj) n_energy_legendre = params[5] energy_legendre = np.zeros(n_energy_legendre) mu = [] for i in range(n_energy_legendre): items, al = get_list_record(file_obj) temperature = items[0] energy_legendre[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) params, tab2 = get_tab2_record(file_obj) n_energy_tabulated = params[5] energy_tabulated = np.zeros(n_energy_tabulated) for i in range(n_energy_tabulated): params, f = get_tab1_record(file_obj) temperature = params[0] energy_tabulated[i] = params[1] if f.n_regions > 1: raise NotImplementedError( 'Angular distribution with multiple ' 'interpolation regions not supported.') mu.append( Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]])) energy = np.concatenate((energy_legendre, energy_tabulated)) return AngleDistribution(energy, mu)
def from_ace(cls, ace, location_dist, location_start): """Generate an angular distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from location_dist : int Index in the XSS array corresponding to the start of a block, e.g. JXS(9). location_start : int Index in the XSS array corresponding to the start of an angle distribution array Returns ------- openmc.data.AngleDistribution Angular distribution """ # Set starting index for angle distribution idx = location_dist + location_start - 1 # Number of energies at which angular distributions are tabulated n_energies = int(ace.xss[idx]) idx += 1 # Incoming energy grid energy = ace.xss[idx:idx + n_energies] * EV_PER_MEV idx += n_energies # Read locations for angular distributions lc = ace.xss[idx:idx + n_energies].astype(int) idx += n_energies mu = [] for i in range(n_energies): if lc[i] > 0: # Equiprobable 32 bin distribution idx = location_dist + abs(lc[i]) - 1 cos = ace.xss[idx:idx + 33] pdf = np.zeros(33) pdf[:32] = 1.0 / (32.0 * np.diff(cos)) cdf = np.linspace(0.0, 1.0, 33) mu_i = Tabular(cos, pdf, 'histogram', ignore_negative=True) mu_i.c = cdf elif lc[i] < 0: # Tabular angular distribution idx = location_dist + abs(lc[i]) - 1 intt = int(ace.xss[idx]) n_points = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 3 * n_points] data.shape = (3, n_points) mu_i = Tabular(data[0], data[1], INTERPOLATION_SCHEME[intt]) mu_i.c = data[2] else: # Isotropic angular distribution mu_i = Uniform(-1., 1.) mu.append(mu_i) return cls(energy, mu)
def _get_products(ev, mt): """Generate products from MF=6 in an ENDF evaluation Parameters ---------- ev : openmc.data.endf.Evaluation ENDF evaluation to read from mt : int The MT value of the reaction to get products for Returns ------- products : list of openmc.data.Product Products of the reaction """ file_obj = StringIO(ev.section[6, mt]) # Read HEAD record items = get_head_record(file_obj) reference_frame = {1: 'laboratory', 2: 'center-of-mass', 3: 'light-heavy', 4: 'breakup'}[items[3]] n_products = items[4] products = [] for i in range(n_products): # Get yield for this product params, yield_ = get_tab1_record(file_obj) za = int(params[0]) awr = params[1] lip = params[2] law = params[3] if za == 0: p = Product('photon') elif za == 1: p = Product('neutron') elif za == 1000: p = Product('electron') else: Z, A = divmod(za, 1000) p = Product('{}{}'.format(ATOMIC_SYMBOL[Z], A)) p.yield_ = yield_ """ # Set reference frame if reference_frame == 'laboratory': p.center_of_mass = False elif reference_frame == 'center-of-mass': p.center_of_mass = True elif reference_frame == 'light-heavy': p.center_of_mass = (awr <= 4.0) """ if law == 0: # No distribution given pass if law == 1: # Continuum energy-angle distribution # Peak ahead to determine type of distribution position = file_obj.tell() params = get_cont_record(file_obj) file_obj.seek(position) lang = params[2] if lang == 1: p.distribution = [CorrelatedAngleEnergy.from_endf(file_obj)] elif lang == 2: p.distribution = [KalbachMann.from_endf(file_obj)] elif law == 2: # Discrete two-body scattering params, tab2 = get_tab2_record(file_obj) ne = params[5] energy = np.zeros(ne) mu = [] for i in range(ne): items, values = get_list_record(file_obj) energy[i] = items[1] lang = items[2] if lang == 0: mu.append(Legendre(values)) elif lang == 12: mu.append(Tabular(values[::2], values[1::2])) elif lang == 14: mu.append(Tabular(values[::2], values[1::2], 'log-linear')) angle_dist = AngleDistribution(energy, mu) dist = UncorrelatedAngleEnergy(angle_dist) p.distribution = [dist] # TODO: Add level-inelastic info? elif law == 3: # Isotropic discrete emission p.distribution = [UncorrelatedAngleEnergy()] # TODO: Add level-inelastic info? elif law == 4: # Discrete two-body recoil pass elif law == 5: # Charged particle elastic scattering pass elif law == 6: # N-body phase-space distribution p.distribution = [NBodyPhaseSpace.from_endf(file_obj)] elif law == 7: # Laboratory energy-angle distribution p.distribution = [LaboratoryAngleEnergy.from_endf(file_obj)] products.append(p) return products
def from_ace(cls, ace, idx, ldis): """Generate correlated angle-energy distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from idx : int Index in XSS array of the start of the energy distribution data (LDIS + LOCC - 1) ldis : int Index in XSS array of the start of the energy distribution block (e.g. JXS[11]) Returns ------- openmc.data.CorrelatedAngleEnergy Correlated angle-energy distribution """ # Read number of interpolation regions and incoming energies n_regions = int(ace.xss[idx]) n_energy_in = int(ace.xss[idx + 1 + 2*n_regions]) # Get interpolation information idx += 1 if n_regions > 0: breakpoints = ace.xss[idx:idx + n_regions].astype(int) interpolation = ace.xss[idx + n_regions:idx + 2*n_regions].astype(int) else: breakpoints = np.array([n_energy_in]) interpolation = np.array([2]) # Incoming energies at which distributions exist idx += 2*n_regions + 1 energy = ace.xss[idx:idx + n_energy_in]*EV_PER_MEV # Location of distributions idx += n_energy_in loc_dist = ace.xss[idx:idx + n_energy_in].astype(int) # Initialize list of distributions energy_out = [] mu = [] # Read each outgoing energy distribution for i in range(n_energy_in): idx = ldis + loc_dist[i] - 1 # intt = interpolation scheme (1=hist, 2=lin-lin) INTTp = int(ace.xss[idx]) intt = INTTp % 10 n_discrete_lines = (INTTp - intt)//10 if intt not in (1, 2): warn("Interpolation scheme for continuous tabular distribution " "is not histogram or linear-linear.") intt = 2 # Secondary energy distribution n_energy_out = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 4*n_energy_out].copy() data.shape = (4, n_energy_out) data[0,:] *= EV_PER_MEV # Create continuous distribution eout_continuous = Tabular(data[0][n_discrete_lines:], data[1][n_discrete_lines:]/EV_PER_MEV, INTERPOLATION_SCHEME[intt], ignore_negative=True) eout_continuous.c = data[2][n_discrete_lines:] if np.any(data[1][n_discrete_lines:] < 0.0): warn("Correlated angle-energy distribution has negative " "probabilities.") # If discrete lines are present, create a mixture distribution if n_discrete_lines > 0: eout_discrete = Discrete(data[0][:n_discrete_lines], data[1][:n_discrete_lines]) eout_discrete.c = data[2][:n_discrete_lines] if n_discrete_lines == n_energy_out: eout_i = eout_discrete else: p_discrete = min(sum(eout_discrete.p), 1.0) eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) else: eout_i = eout_continuous energy_out.append(eout_i) lc = data[3].astype(int) # Secondary angular distributions mu_i = [] for j in range(n_energy_out): if lc[j] > 0: idx = ldis + abs(lc[j]) - 1 intt = int(ace.xss[idx]) n_cosine = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 3*n_cosine] data.shape = (3, n_cosine) mu_ij = Tabular(data[0], data[1], INTERPOLATION_SCHEME[intt]) mu_ij.c = data[2] else: # Isotropic distribution mu_ij = Uniform(-1., 1.) mu_i.append(mu_ij) # Add cosine distributions for this incoming energy to list mu.append(mu_i) return cls(breakpoints, interpolation, energy, energy_out, mu)
def from_hdf5(cls, group): """Generate correlated angle-energy distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.CorrelatedAngleEnergy Correlated angle-energy distribution """ interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] energy = group['energy'].value offsets = group['energy_out'].attrs['offsets'] interpolation = group['energy_out'].attrs['interpolation'] n_discrete_lines = group['energy_out'].attrs['n_discrete_lines'] dset_eout = group['energy_out'].value energy_out = [] dset_mu = group['mu'].value mu = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines offset_e = offsets[i] if i < n_energy - 1: n = offsets[i+1] - offset_e else: n = dset_eout.shape[1] - offset_e m = n_discrete_lines[i] # Create discrete distribution if lines are present if m > 0: x = dset_eout[0, offset_e:offset_e+m] p = dset_eout[1, offset_e:offset_e+m] eout_discrete = Discrete(x, p) eout_discrete.c = dset_eout[2, offset_e:offset_e+m] p_discrete = eout_discrete.c[-1] # Create continuous distribution if m < n: interp = INTERPOLATION_SCHEME[interpolation[i]] x = dset_eout[0, offset_e+m:offset_e+n] p = dset_eout[1, offset_e+m:offset_e+n] eout_continuous = Tabular(x, p, interp, ignore_negative=True) eout_continuous.c = dset_eout[2, offset_e+m:offset_e+n] # If both continuous and discrete are present, create a mixture # distribution if m == 0: eout_i = eout_continuous elif m == n: eout_i = eout_discrete else: eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) # Read angular distributions mu_i = [] for j in range(n): # Determine interpolation scheme interp_code = int(dset_eout[3, offsets[i] + j]) # Determine offset and length offset_mu = int(dset_eout[4, offsets[i] + j]) if offsets[i] + j < dset_eout.shape[1] - 1: n_mu = int(dset_eout[4, offsets[i] + j + 1]) - offset_mu else: n_mu = dset_mu.shape[1] - offset_mu # Get data x = dset_mu[0, offset_mu:offset_mu+n_mu] p = dset_mu[1, offset_mu:offset_mu+n_mu] c = dset_mu[2, offset_mu:offset_mu+n_mu] if interp_code == 0: mu_ij = Discrete(x, p) else: mu_ij = Tabular(x, p, INTERPOLATION_SCHEME[interp_code], ignore_negative=True) mu_ij.c = c mu_i.append(mu_ij) offset_mu += n_mu energy_out.append(eout_i) mu.append(mu_i) return cls(energy_breakpoints, energy_interpolation, energy, energy_out, mu)
def from_ace(cls, ace, idx, ldis): """Generate Kalbach-Mann energy-angle distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from idx : int Index in XSS array of the start of the energy distribution data (LDIS + LOCC - 1) ldis : int Index in XSS array of the start of the energy distribution block (e.g. JXS[11]) Returns ------- openmc.data.KalbachMann Kalbach-Mann energy-angle distribution """ # Read number of interpolation regions and incoming energies n_regions = int(ace.xss[idx]) n_energy_in = int(ace.xss[idx + 1 + 2*n_regions]) # Get interpolation information idx += 1 if n_regions > 0: breakpoints = ace.xss[idx:idx + n_regions].astype(int) interpolation = ace.xss[idx + n_regions:idx + 2*n_regions].astype(int) else: breakpoints = np.array([n_energy_in]) interpolation = np.array([2]) # Incoming energies at which distributions exist idx += 2*n_regions + 1 energy = ace.xss[idx:idx + n_energy_in]*EV_PER_MEV # Location of distributions idx += n_energy_in loc_dist = ace.xss[idx:idx + n_energy_in].astype(int) # Initialize variables energy_out = [] km_r = [] km_a = [] # Read each outgoing energy distribution for i in range(n_energy_in): idx = ldis + loc_dist[i] - 1 # intt = interpolation scheme (1=hist, 2=lin-lin) INTTp = int(ace.xss[idx]) intt = INTTp % 10 n_discrete_lines = (INTTp - intt)//10 if intt not in (1, 2): warn("Interpolation scheme for continuous tabular distribution " "is not histogram or linear-linear.") intt = 2 n_energy_out = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 5*n_energy_out].copy() data.shape = (5, n_energy_out) data[0,:] *= EV_PER_MEV # Create continuous distribution eout_continuous = Tabular(data[0][n_discrete_lines:], data[1][n_discrete_lines:]/EV_PER_MEV, INTERPOLATION_SCHEME[intt], ignore_negative=True) eout_continuous.c = data[2][n_discrete_lines:] if np.any(data[1][n_discrete_lines:] < 0.0): warn("Kalbach-Mann energy distribution has negative " "probabilities.") # If discrete lines are present, create a mixture distribution if n_discrete_lines > 0: eout_discrete = Discrete(data[0][:n_discrete_lines], data[1][:n_discrete_lines]) eout_discrete.c = data[2][:n_discrete_lines] if n_discrete_lines == n_energy_out: eout_i = eout_discrete else: p_discrete = min(sum(eout_discrete.p), 1.0) eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) else: eout_i = eout_continuous energy_out.append(eout_i) km_r.append(Tabulated1D(data[0], data[3])) km_a.append(Tabulated1D(data[0], data[4])) return cls(breakpoints, interpolation, energy, energy_out, km_r, km_a)
def from_hdf5(cls, group): """Generate correlated angle-energy distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.CorrelatedAngleEnergy Correlated angle-energy distribution """ interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] energy = group['energy'][()] offsets = group['energy_out'].attrs['offsets'] interpolation = group['energy_out'].attrs['interpolation'] n_discrete_lines = group['energy_out'].attrs['n_discrete_lines'] dset_eout = group['energy_out'][()] energy_out = [] dset_mu = group['mu'][()] mu = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines offset_e = offsets[i] if i < n_energy - 1: n = offsets[i+1] - offset_e else: n = dset_eout.shape[1] - offset_e m = n_discrete_lines[i] # Create discrete distribution if lines are present if m > 0: x = dset_eout[0, offset_e:offset_e+m] p = dset_eout[1, offset_e:offset_e+m] eout_discrete = Discrete(x, p) eout_discrete.c = dset_eout[2, offset_e:offset_e+m] p_discrete = eout_discrete.c[-1] # Create continuous distribution if m < n: interp = INTERPOLATION_SCHEME[interpolation[i]] x = dset_eout[0, offset_e+m:offset_e+n] p = dset_eout[1, offset_e+m:offset_e+n] eout_continuous = Tabular(x, p, interp, ignore_negative=True) eout_continuous.c = dset_eout[2, offset_e+m:offset_e+n] # If both continuous and discrete are present, create a mixture # distribution if m == 0: eout_i = eout_continuous elif m == n: eout_i = eout_discrete else: eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) # Read angular distributions mu_i = [] for j in range(n): # Determine interpolation scheme interp_code = int(dset_eout[3, offsets[i] + j]) # Determine offset and length offset_mu = int(dset_eout[4, offsets[i] + j]) if offsets[i] + j < dset_eout.shape[1] - 1: n_mu = int(dset_eout[4, offsets[i] + j + 1]) - offset_mu else: n_mu = dset_mu.shape[1] - offset_mu # Get data x = dset_mu[0, offset_mu:offset_mu+n_mu] p = dset_mu[1, offset_mu:offset_mu+n_mu] c = dset_mu[2, offset_mu:offset_mu+n_mu] if interp_code == 0: mu_ij = Discrete(x, p) else: mu_ij = Tabular(x, p, INTERPOLATION_SCHEME[interp_code], ignore_negative=True) mu_ij.c = c mu_i.append(mu_ij) offset_mu += n_mu energy_out.append(eout_i) mu.append(mu_i) return cls(energy_breakpoints, energy_interpolation, energy, energy_out, mu)
def from_ace(cls, ace_or_filename, name=None): """Generate thermal scattering data from an ACE table Parameters ---------- ace_or_filename : openmc.data.ace.Table or str ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str GND-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. Returns ------- openmc.data.ThermalScattering Thermal scattering data """ if isinstance(ace_or_filename, Table): ace = ace_or_filename else: ace = get_table(ace_or_filename) # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') name = get_thermal_name(ace_name) # Assign temperature to the running list kTs = [ace.temperature * EV_PER_MEV] temperatures = [ str(int(round(ace.temperature * EV_PER_MEV / K_BOLTZMANN))) + "K" ] table = cls(name, ace.atomic_weight_ratio, kTs) # Incoherent inelastic scattering cross section idx = ace.jxs[1] n_energy = int(ace.xss[idx]) energy = ace.xss[idx + 1:idx + 1 + n_energy] * EV_PER_MEV xs = ace.xss[idx + 1 + n_energy:idx + 1 + 2 * n_energy] table.inelastic_xs[temperatures[0]] = Tabulated1D(energy, xs) if ace.nxs[7] == 0: table.secondary_mode = 'equal' elif ace.nxs[7] == 1: table.secondary_mode = 'skewed' elif ace.nxs[7] == 2: table.secondary_mode = 'continuous' n_energy_out = ace.nxs[4] if table.secondary_mode in ('equal', 'skewed'): n_mu = ace.nxs[3] idx = ace.jxs[3] table.inelastic_e_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2): n_mu + 2]*EV_PER_MEV table.inelastic_e_out[temperatures[0]].shape = \ (n_energy, n_energy_out) table.inelastic_mu_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)] table.inelastic_mu_out[temperatures[0]].shape = \ (n_energy, n_energy_out, n_mu+2) table.inelastic_mu_out[temperatures[0]] = \ table.inelastic_mu_out[temperatures[0]][:, :, 1:] else: n_mu = ace.nxs[3] - 1 idx = ace.jxs[3] locc = ace.xss[idx:idx + n_energy].astype(int) n_energy_out = \ ace.xss[idx + n_energy:idx + 2 * n_energy].astype(int) energy_out = [] mu_out = [] for i in range(n_energy): idx = locc[i] # Outgoing energy distribution for incoming energy i e = ace.xss[idx + 1:idx + 1 + n_energy_out[i] * (n_mu + 3):n_mu + 3] * EV_PER_MEV p = ace.xss[idx + 2:idx + 2 + n_energy_out[i] * (n_mu + 3):n_mu + 3] / EV_PER_MEV c = ace.xss[idx + 3:idx + 3 + n_energy_out[i] * (n_mu + 3):n_mu + 3] eout_i = Tabular(e, p, 'linear-linear', ignore_negative=True) eout_i.c = c # Outgoing angle distribution for each # (incoming, outgoing) energy pair mu_i = [] for j in range(n_energy_out[i]): mu = ace.xss[idx + 4:idx + 4 + n_mu] p_mu = 1. / n_mu * np.ones(n_mu) mu_ij = Discrete(mu, p_mu) mu_ij.c = np.cumsum(p_mu) mu_i.append(mu_ij) idx += 3 + n_mu energy_out.append(eout_i) mu_out.append(mu_i) # Create correlated angle-energy distribution breakpoints = [n_energy] interpolation = [2] energy = table.inelastic_xs[temperatures[0]].x table.inelastic_dist[temperatures[0]] = CorrelatedAngleEnergy( breakpoints, interpolation, energy, energy_out, mu_out) # Incoherent/coherent elastic scattering cross section idx = ace.jxs[4] n_mu = ace.nxs[6] + 1 if idx != 0: n_energy = int(ace.xss[idx]) energy = ace.xss[idx + 1:idx + 1 + n_energy] * EV_PER_MEV P = ace.xss[idx + 1 + n_energy:idx + 1 + 2 * n_energy] if ace.nxs[5] == 4: # Coherent elastic table.elastic_xs[temperatures[0]] = CoherentElastic( energy, P * EV_PER_MEV) # Coherent elastic shouldn't have angular distributions listed assert n_mu == 0 else: # Incoherent elastic table.elastic_xs[temperatures[0]] = Tabulated1D(energy, P) # Angular distribution assert n_mu > 0 idx = ace.jxs[6] table.elastic_mu_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_mu] table.elastic_mu_out[temperatures[0]].shape = \ (n_energy, n_mu) # Get relevant nuclides -- NJOY only allows one to specify three # nuclides that the S(a,b) table applies to. Thus, for all elements # other than H and Fe, we automatically add all the naturally-occurring # isotopes. for zaid, awr in ace.pairs: if zaid > 0: Z, A = divmod(zaid, 1000) element = ATOMIC_SYMBOL[Z] if element in ['H', 'Fe']: table.nuclides.append(element + str(A)) else: if element + '0' not in table.nuclides: table.nuclides.append(element + '0') for isotope in sorted(NATURAL_ABUNDANCE): if re.match(r'{}\d+'.format(element), isotope): if isotope not in table.nuclides: table.nuclides.append(isotope) return table
def from_ace(cls, ace_or_filename, name=None): """Generate thermal scattering data from an ACE table Parameters ---------- ace_or_filename : openmc.data.ace.Table or str ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str GND-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. Returns ------- openmc.data.ThermalScattering Thermal scattering data """ if isinstance(ace_or_filename, Table): ace = ace_or_filename else: ace = get_table(ace_or_filename) # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') name = get_thermal_name(ace_name) # Assign temperature to the running list kTs = [ace.temperature*EV_PER_MEV] temperatures = [str(int(round(ace.temperature*EV_PER_MEV / K_BOLTZMANN))) + "K"] table = cls(name, ace.atomic_weight_ratio, kTs) # Incoherent inelastic scattering cross section idx = ace.jxs[1] n_energy = int(ace.xss[idx]) energy = ace.xss[idx+1 : idx+1+n_energy]*EV_PER_MEV xs = ace.xss[idx+1+n_energy : idx+1+2*n_energy] table.inelastic_xs[temperatures[0]] = Tabulated1D(energy, xs) if ace.nxs[7] == 0: table.secondary_mode = 'equal' elif ace.nxs[7] == 1: table.secondary_mode = 'skewed' elif ace.nxs[7] == 2: table.secondary_mode = 'continuous' n_energy_out = ace.nxs[4] if table.secondary_mode in ('equal', 'skewed'): n_mu = ace.nxs[3] idx = ace.jxs[3] table.inelastic_e_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2): n_mu + 2]*EV_PER_MEV table.inelastic_e_out[temperatures[0]].shape = \ (n_energy, n_energy_out) table.inelastic_mu_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)] table.inelastic_mu_out[temperatures[0]].shape = \ (n_energy, n_energy_out, n_mu+2) table.inelastic_mu_out[temperatures[0]] = \ table.inelastic_mu_out[temperatures[0]][:, :, 1:] else: n_mu = ace.nxs[3] - 1 idx = ace.jxs[3] locc = ace.xss[idx:idx + n_energy].astype(int) n_energy_out = \ ace.xss[idx + n_energy:idx + 2 * n_energy].astype(int) energy_out = [] mu_out = [] for i in range(n_energy): idx = locc[i] # Outgoing energy distribution for incoming energy i e = ace.xss[idx + 1:idx + 1 + n_energy_out[i]*(n_mu + 3): n_mu + 3]*EV_PER_MEV p = ace.xss[idx + 2:idx + 2 + n_energy_out[i]*(n_mu + 3): n_mu + 3]/EV_PER_MEV c = ace.xss[idx + 3:idx + 3 + n_energy_out[i]*(n_mu + 3): n_mu + 3] eout_i = Tabular(e, p, 'linear-linear', ignore_negative=True) eout_i.c = c # Outgoing angle distribution for each # (incoming, outgoing) energy pair mu_i = [] for j in range(n_energy_out[i]): mu = ace.xss[idx + 4:idx + 4 + n_mu] p_mu = 1. / n_mu * np.ones(n_mu) mu_ij = Discrete(mu, p_mu) mu_ij.c = np.cumsum(p_mu) mu_i.append(mu_ij) idx += 3 + n_mu energy_out.append(eout_i) mu_out.append(mu_i) # Create correlated angle-energy distribution breakpoints = [n_energy] interpolation = [2] energy = table.inelastic_xs[temperatures[0]].x table.inelastic_dist[temperatures[0]] = CorrelatedAngleEnergy( breakpoints, interpolation, energy, energy_out, mu_out) # Incoherent/coherent elastic scattering cross section idx = ace.jxs[4] n_mu = ace.nxs[6] + 1 if idx != 0: n_energy = int(ace.xss[idx]) energy = ace.xss[idx + 1: idx + 1 + n_energy]*EV_PER_MEV P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] if ace.nxs[5] == 4: # Coherent elastic table.elastic_xs[temperatures[0]] = CoherentElastic( energy, P*EV_PER_MEV) # Coherent elastic shouldn't have angular distributions listed assert n_mu == 0 else: # Incoherent elastic table.elastic_xs[temperatures[0]] = Tabulated1D(energy, P) # Angular distribution assert n_mu > 0 idx = ace.jxs[6] table.elastic_mu_out[temperatures[0]] = \ ace.xss[idx:idx + n_energy * n_mu] table.elastic_mu_out[temperatures[0]].shape = \ (n_energy, n_mu) # Get relevant nuclides -- NJOY only allows one to specify three # nuclides that the S(a,b) table applies to. Thus, for all elements # other than H and Fe, we automatically add all the naturally-occurring # isotopes. for zaid, awr in ace.pairs: if zaid > 0: Z, A = divmod(zaid, 1000) element = ATOMIC_SYMBOL[Z] if element in ['H', 'Fe']: table.nuclides.append(element + str(A)) else: if element + '0' not in table.nuclides: table.nuclides.append(element + '0') for isotope in sorted(NATURAL_ABUNDANCE): if re.match(r'{}\d+'.format(element), isotope): if isotope not in table.nuclides: table.nuclides.append(isotope) return table
def from_ace(cls, ace_or_filename, name=None): """Generate thermal scattering data from an ACE table Parameters ---------- ace_or_filename : openmc.data.ace.Table or str ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str GND-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. Returns ------- openmc.data.ThermalScattering Thermal scattering data """ if isinstance(ace_or_filename, Table): ace = ace_or_filename else: ace = get_table(ace_or_filename) # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') if not xs.endswith('t'): raise TypeError( "{} is not a thermal scattering ACE table.".format(ace)) if name is None: name = get_thermal_name(ace_name) # Assign temperature to the running list kTs = [ace.temperature * EV_PER_MEV] # Incoherent inelastic scattering cross section idx = ace.jxs[1] n_energy = int(ace.xss[idx]) energy = ace.xss[idx + 1:idx + 1 + n_energy] * EV_PER_MEV xs = ace.xss[idx + 1 + n_energy:idx + 1 + 2 * n_energy] inelastic_xs = Tabulated1D(energy, xs) energy_max = energy[-1] # Incoherent inelastic angle-energy distribution continuous = (ace.nxs[7] == 2) n_energy_out = ace.nxs[4] if not continuous: n_mu = ace.nxs[3] idx = ace.jxs[3] energy_out = ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2):n_mu + 2] * EV_PER_MEV energy_out.shape = (n_energy, n_energy_out) mu_out = ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)] mu_out.shape = (n_energy, n_energy_out, n_mu + 2) mu_out = mu_out[:, :, 1:] skewed = (ace.nxs[7] == 1) distribution = IncoherentInelasticAEDiscrete( energy_out, mu_out, skewed) else: n_mu = ace.nxs[3] - 1 idx = ace.jxs[3] locc = ace.xss[idx:idx + n_energy].astype(int) n_energy_out = \ ace.xss[idx + n_energy:idx + 2 * n_energy].astype(int) energy_out = [] mu_out = [] for i in range(n_energy): idx = locc[i] # Outgoing energy distribution for incoming energy i e = ace.xss[idx + 1:idx + 1 + n_energy_out[i] * (n_mu + 3):n_mu + 3] * EV_PER_MEV p = ace.xss[idx + 2:idx + 2 + n_energy_out[i] * (n_mu + 3):n_mu + 3] / EV_PER_MEV c = ace.xss[idx + 3:idx + 3 + n_energy_out[i] * (n_mu + 3):n_mu + 3] eout_i = Tabular(e, p, 'linear-linear', ignore_negative=True) eout_i.c = c # Outgoing angle distribution for each # (incoming, outgoing) energy pair mu_i = [] for j in range(n_energy_out[i]): mu = ace.xss[idx + 4:idx + 4 + n_mu] p_mu = 1. / n_mu * np.ones(n_mu) mu_ij = Discrete(mu, p_mu) mu_ij.c = np.cumsum(p_mu) mu_i.append(mu_ij) idx += 3 + n_mu energy_out.append(eout_i) mu_out.append(mu_i) # Create correlated angle-energy distribution breakpoints = [n_energy] interpolation = [2] energy = inelastic_xs.x distribution = IncoherentInelasticAE(breakpoints, interpolation, energy, energy_out, mu_out) table = cls(name, ace.atomic_weight_ratio, energy_max, kTs) T = table.temperatures[0] table.inelastic = ThermalScatteringReaction({T: inelastic_xs}, {T: distribution}) # Incoherent/coherent elastic scattering cross section idx = ace.jxs[4] n_mu = ace.nxs[6] + 1 if idx != 0: n_energy = int(ace.xss[idx]) energy = ace.xss[idx + 1:idx + 1 + n_energy] * EV_PER_MEV P = ace.xss[idx + 1 + n_energy:idx + 1 + 2 * n_energy] if ace.nxs[5] == 4: # Coherent elastic xs = CoherentElastic(energy, P * EV_PER_MEV) distribution = CoherentElasticAE(xs) # Coherent elastic shouldn't have angular distributions listed assert n_mu == 0 else: # Incoherent elastic xs = Tabulated1D(energy, P) # Angular distribution assert n_mu > 0 idx = ace.jxs[6] mu_out = ace.xss[idx:idx + n_energy * n_mu] mu_out.shape = (n_energy, n_mu) distribution = IncoherentElasticAEDiscrete(mu_out) table.elastic = ThermalScatteringReaction({T: xs}, {T: distribution}) # Get relevant nuclides -- NJOY only allows one to specify three # nuclides that the S(a,b) table applies to. Thus, for all elements # other than H and Fe, we automatically add all the naturally-occurring # isotopes. for zaid, awr in ace.pairs: if zaid > 0: Z, A = divmod(zaid, 1000) element = ATOMIC_SYMBOL[Z] if element in ['H', 'Fe']: table.nuclides.append(element + str(A)) else: if element + '0' not in table.nuclides: table.nuclides.append(element + '0') for isotope, _ in isotopes(element): if isotope not in table.nuclides: table.nuclides.append(isotope) return table
def from_ace(cls, ace, location_dist, location_start): """Generate an angular distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from location_dist : int Index in the XSS array corresponding to the start of a block, e.g. JXS(9). location_start : int Index in the XSS array corresponding to the start of an angle distribution array Returns ------- openmc.data.AngleDistribution Angular distribution """ # Set starting index for angle distribution idx = location_dist + location_start - 1 # Number of energies at which angular distributions are tabulated n_energies = int(ace.xss[idx]) idx += 1 # Incoming energy grid energy = ace.xss[idx:idx + n_energies]*EV_PER_MEV idx += n_energies # Read locations for angular distributions lc = ace.xss[idx:idx + n_energies].astype(int) idx += n_energies mu = [] for i in range(n_energies): if lc[i] > 0: # Equiprobable 32 bin distribution idx = location_dist + abs(lc[i]) - 1 cos = ace.xss[idx:idx + 33] pdf = np.zeros(33) pdf[:32] = 1.0/(32.0*np.diff(cos)) cdf = np.linspace(0.0, 1.0, 33) mu_i = Tabular(cos, pdf, 'histogram', ignore_negative=True) mu_i.c = cdf elif lc[i] < 0: # Tabular angular distribution idx = location_dist + abs(lc[i]) - 1 intt = int(ace.xss[idx]) n_points = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 3*n_points] data.shape = (3, n_points) mu_i = Tabular(data[0], data[1], INTERPOLATION_SCHEME[intt]) mu_i.c = data[2] else: # Isotropic angular distribution mu_i = Uniform(-1., 1.) mu.append(mu_i) return cls(energy, mu)
def from_ace(cls, ace, idx, ldis): """Generate correlated angle-energy distribution from ACE data Parameters ---------- ace : openmc.data.ace.Table ACE table to read from idx : int Index in XSS array of the start of the energy distribution data (LDIS + LOCC - 1) ldis : int Index in XSS array of the start of the energy distribution block (e.g. JXS[11]) Returns ------- openmc.data.CorrelatedAngleEnergy Correlated angle-energy distribution """ # Read number of interpolation regions and incoming energies n_regions = int(ace.xss[idx]) n_energy_in = int(ace.xss[idx + 1 + 2*n_regions]) # Get interpolation information idx += 1 if n_regions > 0: breakpoints = ace.xss[idx:idx + n_regions].astype(int) interpolation = ace.xss[idx + n_regions:idx + 2*n_regions].astype(int) else: breakpoints = np.array([n_energy_in]) interpolation = np.array([2]) # Incoming energies at which distributions exist idx += 2*n_regions + 1 energy = ace.xss[idx:idx + n_energy_in]*EV_PER_MEV # Location of distributions idx += n_energy_in loc_dist = ace.xss[idx:idx + n_energy_in].astype(int) # Initialize list of distributions energy_out = [] mu = [] # Read each outgoing energy distribution for i in range(n_energy_in): idx = ldis + loc_dist[i] - 1 # intt = interpolation scheme (1=hist, 2=lin-lin). When discrete # lines are present, the value given is 10*n_discrete_lines + intt n_discrete_lines, intt = divmod(int(ace.xss[idx]), 10) if intt not in (1, 2): warn("Interpolation scheme for continuous tabular distribution " "is not histogram or linear-linear.") intt = 2 # Secondary energy distribution n_energy_out = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 4*n_energy_out].copy() data.shape = (4, n_energy_out) data[0,:] *= EV_PER_MEV # Create continuous distribution eout_continuous = Tabular(data[0][n_discrete_lines:], data[1][n_discrete_lines:]/EV_PER_MEV, INTERPOLATION_SCHEME[intt], ignore_negative=True) eout_continuous.c = data[2][n_discrete_lines:] if np.any(data[1][n_discrete_lines:] < 0.0): warn("Correlated angle-energy distribution has negative " "probabilities.") # If discrete lines are present, create a mixture distribution if n_discrete_lines > 0: eout_discrete = Discrete(data[0][:n_discrete_lines], data[1][:n_discrete_lines]) eout_discrete.c = data[2][:n_discrete_lines] if n_discrete_lines == n_energy_out: eout_i = eout_discrete else: p_discrete = min(sum(eout_discrete.p), 1.0) eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) else: eout_i = eout_continuous energy_out.append(eout_i) lc = data[3].astype(int) # Secondary angular distributions mu_i = [] for j in range(n_energy_out): if lc[j] > 0: idx = ldis + abs(lc[j]) - 1 intt = int(ace.xss[idx]) n_cosine = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 3*n_cosine] data.shape = (3, n_cosine) mu_ij = Tabular(data[0], data[1], INTERPOLATION_SCHEME[intt]) mu_ij.c = data[2] else: # Isotropic distribution mu_ij = Uniform(-1., 1.) mu_i.append(mu_ij) # Add cosine distributions for this incoming energy to list mu.append(mu_i) return cls(breakpoints, interpolation, energy, energy_out, mu)
def from_hdf5(cls, group): """Generate Kalbach-Mann distribution from HDF5 data Parameters ---------- group : h5py.Group HDF5 group to read from Returns ------- openmc.data.KalbachMann Kalbach-Mann energy distribution """ interp_data = group['energy'].attrs['interpolation'] energy_breakpoints = interp_data[0, :] energy_interpolation = interp_data[1, :] energy = group['energy'].value data = group['distribution'] offsets = data.attrs['offsets'] interpolation = data.attrs['interpolation'] n_discrete_lines = data.attrs['n_discrete_lines'] energy_out = [] precompound = [] slope = [] n_energy = len(energy) for i in range(n_energy): # Determine length of outgoing energy distribution and number of # discrete lines j = offsets[i] if i < n_energy - 1: n = offsets[i+1] - j else: n = data.shape[1] - j m = n_discrete_lines[i] # Create discrete distribution if lines are present if m > 0: eout_discrete = Discrete(data[0, j:j+m], data[1, j:j+m]) eout_discrete.c = data[2, j:j+m] p_discrete = eout_discrete.c[-1] # Create continuous distribution if m < n: interp = INTERPOLATION_SCHEME[interpolation[i]] eout_continuous = Tabular(data[0, j+m:j+n], data[1, j+m:j+n], interp) eout_continuous.c = data[2, j+m:j+n] # If both continuous and discrete are present, create a mixture # distribution if m == 0: eout_i = eout_continuous elif m == n: eout_i = eout_discrete else: eout_i = Mixture([p_discrete, 1. - p_discrete], [eout_discrete, eout_continuous]) km_r = Tabulated1D(data[0, j:j+n], data[3, j:j+n]) km_a = Tabulated1D(data[0, j:j+n], data[4, j:j+n]) energy_out.append(eout_i) precompound.append(km_r) slope.append(km_a) return cls(energy_breakpoints, energy_interpolation, energy, energy_out, precompound, slope)