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_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_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 model(): model = openmc.Model() # materials (M4 steel alloy) m4 = openmc.Material() m4.set_density('g/cc', 2.3) m4.add_nuclide('H1', 0.168018676) m4.add_nuclide("H2", 1.93244e-05) m4.add_nuclide("O16", 0.561814465) m4.add_nuclide("O17", 0.00021401) m4.add_nuclide("Na23", 0.021365) m4.add_nuclide("Al27", 0.021343) m4.add_nuclide("Si28", 0.187439342) m4.add_nuclide("Si29", 0.009517714) m4.add_nuclide("Si30", 0.006273944) m4.add_nuclide("Ca40", 0.018026179) m4.add_nuclide("Ca42", 0.00012031) m4.add_nuclide("Ca43", 2.51033e-05) m4.add_nuclide("Ca44", 0.000387892) m4.add_nuclide("Ca46", 7.438e-07) m4.add_nuclide("Ca48", 3.47727e-05) m4.add_nuclide("Fe54", 0.000248179) m4.add_nuclide("Fe56", 0.003895875) m4.add_nuclide("Fe57", 8.99727e-05) m4.add_nuclide("Fe58", 1.19737e-05) s0 = openmc.Sphere(r=240) s1 = openmc.Sphere(r=250, boundary_type='vacuum') c0 = openmc.Cell(fill=m4, region=-s0) c1 = openmc.Cell(region=+s0 & -s1) model.geometry = openmc.Geometry([c0, c1]) # settings settings = model.settings settings.run_mode = 'fixed source' settings.particles = 200 settings.batches = 2 settings.max_splits = 200 settings.photon_transport = True space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) settings.source = openmc.Source(space=space, energy=energy) # tally mesh = openmc.RegularMesh() mesh.lower_left = (-240, -240, -240) mesh.upper_right = (240, 240, 240) mesh.dimension = (5, 10, 15) mesh_filter = openmc.MeshFilter(mesh) e_bnds = [0.0, 0.5, 2E7] energy_filter = openmc.EnergyFilter(e_bnds) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally = openmc.Tally() tally.filters = [mesh_filter, energy_filter, particle_filter] tally.scores = ['flux'] model.tallies.append(tally) # weight windows # load pre-generated weight windows # (created using the same tally as above) ww_n_lower_bnds = np.loadtxt('ww_n.txt') ww_p_lower_bnds = np.loadtxt('ww_p.txt') # create a mesh matching the one used # to generate the weight windows ww_mesh = openmc.RegularMesh() ww_mesh.lower_left = (-240, -240, -240) ww_mesh.upper_right = (240, 240, 240) ww_mesh.dimension = (5, 6, 7) ww_n = openmc.WeightWindows(ww_mesh, ww_n_lower_bnds, None, 10.0, e_bnds, max_lower_bound_ratio=1.5) ww_p = openmc.WeightWindows(ww_mesh, ww_p_lower_bnds, None, 10.0, e_bnds, max_lower_bound_ratio=1.5) model.settings.weight_windows = [ww_n, ww_p] return model
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 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_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_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('.') 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_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)
def model(): openmc.reset_auto_ids() model = openmc.Model() # materials (M4 steel alloy) m4 = openmc.Material() m4.set_density('g/cc', 2.3) m4.add_nuclide('H1', 0.168018676) m4.add_nuclide("H2", 1.93244e-05) m4.add_nuclide("O16", 0.561814465) m4.add_nuclide("O17", 0.00021401) m4.add_nuclide("Na23", 0.021365) m4.add_nuclide("Al27", 0.021343) m4.add_nuclide("Si28", 0.187439342) m4.add_nuclide("Si29", 0.009517714) m4.add_nuclide("Si30", 0.006273944) m4.add_nuclide("Ca40", 0.018026179) m4.add_nuclide("Ca42", 0.00012031) m4.add_nuclide("Ca43", 2.51033e-05) m4.add_nuclide("Ca44", 0.000387892) m4.add_nuclide("Ca46", 7.438e-07) m4.add_nuclide("Ca48", 3.47727e-05) m4.add_nuclide("Fe54", 0.000248179) m4.add_nuclide("Fe56", 0.003895875) m4.add_nuclide("Fe57", 8.99727e-05) m4.add_nuclide("Fe58", 1.19737e-05) s0 = openmc.Sphere(r=240) s1 = openmc.Sphere(r=250, boundary_type='vacuum') c0 = openmc.Cell(fill=m4, region=-s0) c1 = openmc.Cell(region=+s0 & -s1) model.geometry = openmc.Geometry([c0, c1]) # settings settings = model.settings settings.run_mode = 'fixed source' settings.particles = 500 settings.batches = 2 settings.max_splits = 100 settings.photon_transport = True space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) settings.source = openmc.Source(space=space, energy=energy) # tally mesh = openmc.RegularMesh() mesh.lower_left = (-240, -240, -240) mesh.upper_right = (240, 240, 240) mesh.dimension = (3, 5, 7) mesh_filter = openmc.MeshFilter(mesh) e_bnds = [0.0, 0.5, 2E7] energy_filter = openmc.EnergyFilter(e_bnds) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally = openmc.Tally() tally.filters = [mesh_filter, energy_filter, particle_filter] tally.scores = ['flux'] model.tallies.append(tally) return model