diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 64eac8317b..90aaa1e6e4 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -191,8 +191,6 @@ class ThermalScattering(EqualityMixin): self.name = name self.atomic_weight_ratio = atomic_weight_ratio self.kTs = kTs - self.temperatures = [str(int(round(kT / K_BOLTZMANN))) + "K" - for kT in kTs] self.elastic_xs = {} self.elastic_mu_out = {} self.inelastic_xs = {} @@ -208,6 +206,10 @@ class ThermalScattering(EqualityMixin): else: return "" + @property + def temperatures(self): + return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs] + def export_to_hdf5(self, path, mode='a'): """Export table to an HDF5 file. @@ -277,142 +279,36 @@ class ThermalScattering(EqualityMixin): Thermal scattering data """ - if isinstance(ace_or_filename, Table): - ace = ace_or_filename - else: - ace = get_table(ace_or_filename) + data = ThermalScattering.from_ace(ace_or_filename, name) - # Get new name that is GND-consistent - ace_name, xs = ace.name.split('.') - if name is None: - if ace_name.lower() in _THERMAL_NAMES: - name = _THERMAL_NAMES[ace_name.lower()] - else: - # Make an educated guess? This actually works well for JEFF-3.2 - # which stupidly uses names like lw00.32t, lw01.32t, etc. for - # different temperatures - matches = get_close_matches( - ace_name.lower(), _THERMAL_NAMES.keys(), cutoff=0.5) - if len(matches) > 0: - name = _THERMAL_NAMES[matches[0]] - else: - # OK, we give up. Just use the ACE name. - name = 'c_' + ace.name - warn('Thermal scattering material "{}" is not recognized. ' - 'Assigning a name of {}.'.format(ace.name, name)) + # Check if temprature already exists + strT = data.temperatures[0] + if strT in self.temperatures: + warn('S(a,b) data at T={} already exists.'.format(strT)) + return - # If this ACE data matches the data within self then get the data - if ace.temperature not in self.kTs: - if name == self.name: - # Add temperature and kTs - strT = str(int(round(ace.temperature / K_BOLTZMANN))) + "K" - self.temperatures.append(strT) - self.kTs.append(ace.temperature) + # Check that name matches + if data.name != self.name: + raise ValueError('Data provided for an incorrect material.') - # Incoherent inelastic scattering cross section - idx = ace.jxs[1] - n_energy = int(ace.xss[idx]) - energy = ace.xss[idx + 1: idx + 1 + n_energy] - xs = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] - self.inelastic_xs[strT] = Tabulated1D(energy, xs) + # Add temperature + self.kTs += data.kTs - # Make sure secondary_mode is always equal. This should always - # be the case, but to reduce future debugging should something - # change, this will alert the developers to the issue. - if ace.nxs[7] == 0: - secondary_mode = 'equal' - elif ace.nxs[7] == 1: - secondary_mode = 'skewed' - elif ace.nxs[7] == 2: - secondary_mode = 'continuous' + # Add inelastic cross section and distributions + if strT in data.inelastic_xs: + self.inelastic_xs[strT] = data.inelastic_xs[strT] + if strT in data.inelastic_e_out: + self.inelastic_e_out[strT] = data.inelastic_e_out[strT] + if strT in data.inelastic_mu_out: + self.inelastic_mu_out[strT] = data.inelastic_mu_out[strT] + if strT in data.inelastic_dist: + self.inelastic_dist[strT] = data.inelastic_dist[strT] - if secondary_mode != self.secondary_mode: - raise ValueError('Secondary Modes are inconsistent.') - - n_energy_out = ace.nxs[4] - if self.secondary_mode in ('equal', 'skewed'): - n_mu = ace.nxs[3] - idx = ace.jxs[3] - self.inelastic_e_out[strT] = \ - ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2): - n_mu + 2] - self.inelastic_e_out[strT].shape = \ - (n_energy, n_energy_out) - - self.inelastic_mu_out[strT] = \ - ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)] - self.inelastic_mu_out[strT].shape = \ - (n_energy, n_energy_out, n_mu + 2) - self.inelastic_mu_out[strT] = \ - self.inelastic_mu_out[strT][:, :, 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] - p = ace.xss[idx + 2:idx + 2 + n_energy_out[i]*(n_mu + 3): - n_mu + 3] - 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 = self.inelastic_xs[strT].x - self.inelastic_dist[strT] = CorrelatedAngleEnergy( - breakpoints, interpolation, energy, energy_out, mu_out) - - # Incoherent/coherent elastic scattering cross section - idx = ace.jxs[4] - if idx != 0: - n_energy = int(ace.xss[idx]) - energy = ace.xss[idx + 1: idx + 1 + n_energy] - P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] - - if ace.nxs[5] == 4: - self.elastic_xs[strT] = CoherentElastic(energy, P) - else: - self.elastic_xs[strT] = Tabulated1D(energy, P) - - # Angular distribution - n_mu = ace.nxs[6] - if n_mu != -1: - idx = ace.jxs[6] - self.elastic_mu_out[strT] = \ - ace.xss[idx:idx + n_energy * n_mu] - self.elastic_mu_out[strT].shape = \ - (n_energy, n_mu) - - else: - raise ValueError('Data provided for an incorrect library') - else: - warn('{} already has data for T={:.1f} K'.format( - self.name, ace.temperature / K_BOLTZMANN)) + # Add elastic cross sectoin and angular distribution + if strT in data.elastic_xs: + self.elastic_xs[strT] = data.elastic_xs[strT] + if strT in data.elastic_mu_out: + self.elastic_mu_out[strT] = data.elastic_mu_out[strT] @classmethod def from_hdf5(cls, group_or_filename):