diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index ff739fe851..6502a5ef2c 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -3154,30 +3154,133 @@ class DiffusionCoefficient(TransportXS): raise ValueError(msg) # Switch EnergyoutFilter to EnergyFilter + if 'scatter-1' in self.tallies: + p1_tally = self.tallies['scatter-1'] + old_filt = p1_tally.filters[-2] + new_filt = openmc.EnergyFilter(old_filt.values) + p1_tally.filters[-2] = new_filt + + p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], + filter_bins=[('P1',)],squeeze=True) + p1_tally._scores = ['scatter-1'] + total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] + trans_corr = p1_tally / self.tallies['flux (analog)'] + transport = total_xs - trans_corr + diff_coef = transport**(-1) / 3.0 + self._xs_tally = diff_coef + self._compute_xs() + + else: + self._xs_tally = self.tallies[self._rxn_type] / self.tallies['flux (tracklength)'] + self._compute_xs() + + return self._xs_tally + + def get_condensed_xs(self, coarse_groups, condense_diff_coef=True): + """Construct an energy-condensed version of this cross section. + + Parameters + ---------- + coarse_groups : openmc.mgxs.EnergyGroups + The coarse energy group structure of interest + + Returns + ------- + MGXS + A new MGXS condensed to the group structure of interest + + """ + + cv.check_type('coarse_groups', coarse_groups, EnergyGroups) + cv.check_less_than('coarse groups', coarse_groups.num_groups, + self.num_groups, equality=True) + cv.check_value('upper coarse energy', coarse_groups.group_edges[-1], + [self.energy_groups.group_edges[-1]]) + cv.check_value('lower coarse energy', coarse_groups.group_edges[0], + [self.energy_groups.group_edges[0]]) + + # Clone this MGXS to initialize the condensed version + condensed_xs = copy.deepcopy(self) + + if condense_diff_coef: p1_tally = self.tallies['scatter-1'] old_filt = p1_tally.filters[-2] new_filt = openmc.EnergyFilter(old_filt.values) p1_tally.filters[-2] = new_filt - - # Slice Legendre expansion filter and change name of score p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], filter_bins=[('P1',)], squeeze=True) p1_tally._scores = ['scatter-1'] - - # Compute total cross section total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] - - # Compute transport correction term trans_corr = p1_tally / self.tallies['flux (analog)'] - - # Compute the diffusion coefficient transport = total_xs - trans_corr diff_coef = transport**(-1) / 3.0 - self._xs_tally = diff_coef - self._compute_xs() + diff_coef *= self.tallies['flux (tracklength)'] + flux_tally = condensed_xs.tallies['flux (tracklength)'] + condensed_xs._tallies = OrderedDict() + condensed_xs._tallies[self._rxn_type] = diff_coef + condensed_xs._tallies['flux (tracklength)'] = flux_tally + condensed_xs._rxn_rate_tally = diff_coef + condensed_xs._xs_tally = None + condensed_xs._sparse = False + condensed_xs._energy_groups = coarse_groups - return self._xs_tally + else: + condensed_xs._rxn_rate_tally = None + condensed_xs._xs_tally = None + condensed_xs._sparse = False + condensed_xs._energy_groups = coarse_groups + + # Build energy indices to sum across + energy_indices = [] + for group in range(coarse_groups.num_groups, 0, -1): + low, high = coarse_groups.get_group_bounds(group) + low_index = np.where(self.energy_groups.group_edges == low)[0][0] + energy_indices.append(low_index) + + fine_edges = self.energy_groups.group_edges + + # Condense each of the tallies to the coarse group structure + for tally in condensed_xs.tallies.values(): + + # Make condensed tally derived and null out sum, sum_sq + tally._derived = True + tally._sum = None + tally._sum_sq = None + + # Get tally data arrays reshaped with one dimension per filter + mean = tally.get_reshaped_data(value='mean') + std_dev = tally.get_reshaped_data(value='std_dev') + + # Sum across all applicable fine energy group filters + for i, tally_filter in enumerate(tally.filters): + if not isinstance(tally_filter, (openmc.EnergyFilter, + openmc.EnergyoutFilter)): + continue + elif len(tally_filter.bins) != len(fine_edges) - 1: + continue + elif not np.allclose(tally_filter.bins[:, 0], fine_edges[:-1]): + continue + else: + cedge = coarse_groups.group_edges + tally_filter.values = cedge + tally_filter.bins = np.vstack((cedge[:-1], cedge[1:])).T + mean = np.add.reduceat(mean, energy_indices, axis=i) + std_dev = np.add.reduceat(std_dev**2, energy_indices, + axis=i) + std_dev = np.sqrt(std_dev) + + # Reshape condensed data arrays with one dimension for all filters + mean = np.reshape(mean, tally.shape) + std_dev = np.reshape(std_dev, tally.shape) + + # Override tally's data with the new condensed data + tally._mean = mean + tally._std_dev = std_dev + + # Compute the energy condensed multi-group cross section + condensed_xs.sparse = self.sparse + return condensed_xs class AbsorptionXS(MGXS): r"""An absorption multi-group cross section.