diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index e23f927f40..6657004d65 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -47,7 +47,7 @@ class MDGXS(MGXS): name : str, optional Name of the multi-group cross section. Used as a label to identify tallies in OpenMC 'tallies.xml' file. - delayed_groups : list of int + delayed_groups : list of int, optional Delayed groups to filter out the xs num_polar : Integral, optional Number of equi-width polar angle bins for angle discretization; @@ -70,7 +70,7 @@ class MDGXS(MGXS): Domain type for spatial homogenization energy_groups : openmc.mgxs.EnergyGroups Energy group structure for energy condensation - delayed_groups : list of int + delayed_groups : list of int, optional Delayed groups to filter out the xs num_polar : Integral Number of equi-width polar angle bins for angle discretization @@ -246,7 +246,7 @@ class MDGXS(MGXS): name : str, optional Name of the multi-group cross section. Used as a label to identify tallies in OpenMC 'tallies.xml' file. Defaults to the empty string. - delayed_groups : list of int + delayed_groups : list of int, optional Delayed groups to filter out the xs num_polar : Integral, optional Number of equi-width polar angle bins for angle discretization; @@ -1316,10 +1316,10 @@ class ChiDelayed(MDGXS): # Sum out all nuclides nuclides = self.get_nuclides() - delayed_nu_fission_in = delayed_nu_fission_in.summation\ - (nuclides=nuclides) - delayed_nu_fission_out = delayed_nu_fission_out.summation\ - (nuclides=nuclides) + delayed_nu_fission_in = delayed_nu_fission_in.summation( + nuclides=nuclides) + delayed_nu_fission_out = delayed_nu_fission_out.summation( + nuclides=nuclides) # Remove coarse energy filter to keep it out of tally arithmetic energy_filter = delayed_nu_fission_in.find_filter( @@ -2169,6 +2169,8 @@ class MatrixMDGXS(MDGXS): # Eliminate the trivial score dimension xs = np.squeeze(xs, axis=len(xs.shape) - 1) + + # Eliminate NaNs which may have been produced by dividing by density xs = np.nan_to_num(xs) if in_groups == 'all': diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index e9fee5a2f1..c1fa92c176 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -15,51 +15,67 @@ from openmc.mgxs import EnergyGroups # Supported cross section types -MGXS_TYPES = ['total', - 'transport', - 'nu-transport', - 'absorption', - 'capture', - 'fission', - 'nu-fission', - 'kappa-fission', - 'scatter', - 'nu-scatter', - 'scatter matrix', - 'nu-scatter matrix', - 'multiplicity matrix', - 'nu-fission matrix', - 'scatter probability matrix', - 'consistent scatter matrix', - 'consistent nu-scatter matrix', - 'chi', - 'chi-prompt', - 'inverse-velocity', - 'prompt-nu-fission', - 'prompt-nu-fission matrix'] +MGXS_TYPES = [ + 'total', + 'transport', + 'nu-transport', + 'absorption', + 'capture', + 'fission', + 'nu-fission', + 'kappa-fission', + 'scatter', + 'nu-scatter', + 'scatter matrix', + 'nu-scatter matrix', + 'multiplicity matrix', + 'nu-fission matrix', + 'scatter probability matrix', + 'consistent scatter matrix', + 'consistent nu-scatter matrix', + 'chi', + 'chi-prompt', + 'inverse-velocity', + 'prompt-nu-fission', + 'prompt-nu-fission matrix' +] # Supported domain types -DOMAIN_TYPES = ['cell', - 'distribcell', - 'universe', - 'material', - 'mesh'] +DOMAIN_TYPES = [ + 'cell', + 'distribcell', + 'universe', + 'material', + 'mesh' +] # Filter types corresponding to each domain -_DOMAIN_TO_FILTER = {'cell': openmc.CellFilter, - 'distribcell': openmc.DistribcellFilter, - 'universe': openmc.UniverseFilter, - 'material': openmc.MaterialFilter, - 'mesh': openmc.MeshFilter} +_DOMAIN_TO_FILTER = { + 'cell': openmc.CellFilter, + 'distribcell': openmc.DistribcellFilter, + 'universe': openmc.UniverseFilter, + 'material': openmc.MaterialFilter, + 'mesh': openmc.MeshFilter +} # Supported domain classes -_DOMAINS = (openmc.Cell, - openmc.Universe, - openmc.Material, - openmc.RegularMesh) +_DOMAINS = ( + openmc.Cell, + openmc.Universe, + openmc.Material, + openmc.RegularMesh +) -# Supported ScatterMatrixXS angular distribution types -MU_TREATMENTS = ('legendre', 'histogram') +# Supported ScatterMatrixXS angular distribution types. Note that 'histogram' is +# defined here and used in mgxs_library.py, but it is not used for the current +# module +SCATTER_TABULAR = 'tabular' +SCATTER_LEGENDRE = 'legendre' +SCATTER_HISTOGRAM = 'histogram' +MU_TREATMENTS = ( + SCATTER_LEGENDRE, + SCATTER_HISTOGRAM +) # Maximum Legendre order supported by OpenMC _MAX_LEGENDRE = 10 @@ -245,38 +261,37 @@ class MGXS(metaclass=ABCMeta): def __deepcopy__(self, memo): existing = memo.get(id(self)) - # If this is the first time we have tried to copy this object, copy it - if existing is None: - clone = type(self).__new__(type(self)) - clone._name = self.name - clone._rxn_type = self.rxn_type - clone._by_nuclide = self.by_nuclide - clone._nuclides = copy.deepcopy(self._nuclides, memo) - clone._domain = self.domain - clone._domain_type = self.domain_type - clone._energy_groups = copy.deepcopy(self.energy_groups, memo) - clone._num_polar = self._num_polar - clone._num_azimuthal = self._num_azimuthal - clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo) - clone._rxn_rate_tally = copy.deepcopy(self._rxn_rate_tally, memo) - clone._xs_tally = copy.deepcopy(self._xs_tally, memo) - clone._sparse = self.sparse - clone._loaded_sp = self._loaded_sp - clone._derived = self.derived - clone._hdf5_key = self._hdf5_key - - clone._tallies = OrderedDict() - for tally_type, tally in self.tallies.items(): - clone.tallies[tally_type] = copy.deepcopy(tally, memo) - - memo[id(self)] = clone - - return clone - # If this object has been copied before, return the first copy made - else: + if existing is not None: return existing + # If this is the first time we have tried to copy this object, copy it + clone = type(self).__new__(type(self)) + clone._name = self.name + clone._rxn_type = self.rxn_type + clone._by_nuclide = self.by_nuclide + clone._nuclides = copy.deepcopy(self._nuclides, memo) + clone._domain = self.domain + clone._domain_type = self.domain_type + clone._energy_groups = copy.deepcopy(self.energy_groups, memo) + clone._num_polar = self._num_polar + clone._num_azimuthal = self._num_azimuthal + clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo) + clone._rxn_rate_tally = copy.deepcopy(self._rxn_rate_tally, memo) + clone._xs_tally = copy.deepcopy(self._xs_tally, memo) + clone._sparse = self.sparse + clone._loaded_sp = self._loaded_sp + clone._derived = self.derived + clone._hdf5_key = self._hdf5_key + + clone._tallies = OrderedDict() + for tally_type, tally in self.tallies.items(): + clone.tallies[tally_type] = copy.deepcopy(tally, memo) + + memo[id(self)] = clone + + return clone + def _add_angle_filters(self, filters): """Add the azimuthal and polar bins to the MGXS filters if needed. Filters will be provided as a ragged 2D list of openmc.Filter objects. @@ -2170,6 +2185,7 @@ class MatrixMGXS(MGXS): if not isinstance(in_groups, str): cv.check_iterable_type('groups', in_groups, Integral) filters.append(openmc.EnergyFilter) + energy_bins = [] for group in in_groups: energy_bins.append((self.energy_groups.get_group_bounds(group),)) filter_bins.append(tuple(energy_bins)) @@ -3725,7 +3741,7 @@ class ScatterMatrixXS(MatrixMGXS): num_polar, num_azimuthal) self._formulation = 'simple' self._correction = 'P0' - self._scatter_format = 'legendre' + self._scatter_format = SCATTER_LEGENDRE self._legendre_order = 0 self._histogram_bins = 16 self._estimator = 'analog' @@ -3748,12 +3764,12 @@ class ScatterMatrixXS(MatrixMGXS): process """ if self.num_polar > 1 or self.num_azimuthal > 1: - if self.scatter_format == 'histogram': + if self.scatter_format == SCATTER_HISTOGRAM: return (0, 1, 3, 4, 5) else: return (0, 1, 3, 4) else: - if self.scatter_format == 'histogram': + if self.scatter_format == SCATTER_HISTOGRAM: return (1, 2, 3) else: return (1, 2) @@ -3857,13 +3873,13 @@ class ScatterMatrixXS(MatrixMGXS): energy = openmc.EnergyFilter(group_edges) energyout = openmc.EnergyoutFilter(group_edges) - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: if self.correction == 'P0' and self.legendre_order == 0: angle_filter = openmc.LegendreFilter(order=1) else: angle_filter = \ openmc.LegendreFilter(order=self.legendre_order) - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: bins = np.linspace(-1., 1., num=self.histogram_bins + 1, endpoint=True) angle_filter = openmc.MuFilter(bins) @@ -3878,9 +3894,9 @@ class ScatterMatrixXS(MatrixMGXS): filters = [[energy], [energy]] # Group-to-group scattering probability matrix - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: angle_filter = openmc.LegendreFilter(order=self.legendre_order) - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: bins = np.linspace(-1., 1., num=self.histogram_bins + 1, endpoint=True) angle_filter = openmc.MuFilter(bins) @@ -3903,7 +3919,7 @@ class ScatterMatrixXS(MatrixMGXS): if self._rxn_rate_tally is None: if self.formulation == 'simple': - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: # If using P0 correction subtract P1 scatter from the diag. if self.correction == 'P0' and self.legendre_order == 0: scatter_p0 = self.tallies[self.rxn_type].get_slice( @@ -3937,7 +3953,7 @@ class ScatterMatrixXS(MatrixMGXS): # Otherwise, extract scattering moment reaction rate Tally else: self._rxn_rate_tally = self.tallies[self.rxn_type] - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: # Extract scattering rate distribution tally self._rxn_rate_tally = self.tallies[self.rxn_type] @@ -3967,14 +3983,14 @@ class ScatterMatrixXS(MatrixMGXS): tally_key = 'scatter matrix' # Compute normalization factor summed across outgoing energies - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: norm = self.tallies[tally_key].get_slice( scores=['scatter'], filters=[openmc.LegendreFilter], filter_bins=[('P0',)], squeeze=True) # Compute normalization factor summed across outgoing mu bins - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: norm = self.tallies[tally_key].get_slice( scores=['scatter']) norm = norm.summation( @@ -3994,14 +4010,14 @@ class ScatterMatrixXS(MatrixMGXS): if self.nu: numer = self.tallies['nu-scatter'] # Get the denominator - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: denom = self.tallies[tally_key].get_slice( scores=['scatter'], filters=[openmc.LegendreFilter], filter_bins=[('P0',)], squeeze=True) # Compute normalization factor summed across mu bins - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: denom = self.tallies[tally_key].get_slice( scores=['scatter']) @@ -4048,7 +4064,7 @@ class ScatterMatrixXS(MatrixMGXS): self._compute_xs() # Force the angle filter to be the last filter - if self.scatter_format == 'histogram': + if self.scatter_format == SCATTER_HISTOGRAM: angle_filter = self._xs_tally.find_filter(openmc.MuFilter) else: angle_filter = \ @@ -4105,13 +4121,13 @@ class ScatterMatrixXS(MatrixMGXS): def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: if correction == 'P0' and self.legendre_order > 0: msg = 'The P0 correction will be ignored since the ' \ 'scattering order {} is greater than '\ 'zero'.format(self.legendre_order) warnings.warn(msg) - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: msg = 'The P0 correction will be ignored since the ' \ 'scatter format is set to histogram' warnings.warn(msg) @@ -4131,14 +4147,14 @@ class ScatterMatrixXS(MatrixMGXS): cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, equality=True) - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: if self.correction == 'P0' and legendre_order > 0: msg = 'The P0 correction will be ignored since the ' \ 'scattering order {} is greater than '\ 'zero'.format(self.legendre_order) warnings.warn(msg, RuntimeWarning) self.correction = None - elif self.scatter_format == 'histogram': + elif self.scatter_format == SCATTER_HISTOGRAM: msg = 'The legendre order will be ignored since the ' \ 'scatter format is set to histogram' warnings.warn(msg) @@ -4226,7 +4242,7 @@ class ScatterMatrixXS(MatrixMGXS): slice_xs._xs_tally = None # Slice the Legendre order if needed - if legendre_order != 'same' and self.scatter_format == 'legendre': + if legendre_order != 'same' and self.scatter_format == SCATTER_LEGENDRE: cv.check_type('legendre_order', legendre_order, Integral) cv.check_less_than('legendre_order', legendre_order, self.legendre_order, equality=True) @@ -4363,7 +4379,7 @@ class ScatterMatrixXS(MatrixMGXS): filter_bins.append((self.energy_groups.get_group_bounds(group),)) # Construct CrossScore for requested scattering moment - if self.scatter_format == 'legendre': + if self.scatter_format == SCATTER_LEGENDRE: if moment != 'all': cv.check_type('moment', moment, Integral) cv.check_greater_than('moment', moment, 0, equality=True) @@ -4508,7 +4524,7 @@ class ScatterMatrixXS(MatrixMGXS): paths=paths) # If the matrix is P0, remove the legendre column - if self.scatter_format == 'legendre' and self.legendre_order == 0: + if self.scatter_format == SCATTER_LEGENDRE and self.legendre_order == 0: df = df.drop(axis=1, labels=['legendre']) return df @@ -4560,7 +4576,7 @@ class ScatterMatrixXS(MatrixMGXS): cv.check_value('xs_type', xs_type, ['macro', 'micro']) - if self.correction != 'P0' and self.scatter_format == 'legendre': + if self.correction != 'P0' and self.scatter_format == SCATTER_LEGENDRE: rxn_type = '{0} (P{1})'.format(self.rxn_type, moment) else: rxn_type = self.rxn_type @@ -4648,7 +4664,7 @@ class ScatterMatrixXS(MatrixMGXS): return to_print # Set the number of histogram bins - if self.scatter_format == 'histogram': + if self.scatter_format == SCATTER_HISTOGRAM: num_mu_bins = self.histogram_bins else: num_mu_bins = 0 diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 179885260c..2adc658c51 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -10,6 +10,7 @@ from scipy.special import eval_legendre import openmc import openmc.mgxs +from openmc.mgxs import SCATTER_TABULAR, SCATTER_LEGENDRE, SCATTER_HISTOGRAM from openmc.checkvalue import check_type, check_value, check_greater_than, \ check_iterable_type, check_less_than, check_filetype_version @@ -24,9 +25,6 @@ _REPRESENTATIONS = [ ] # Supported scattering angular distribution representations -SCATTER_TABULAR = 'tabular' -SCATTER_LEGENDRE = 'legendre' -SCATTER_HISTOGRAM = 'histogram' _SCATTER_TYPES = [ SCATTER_TABULAR, SCATTER_LEGENDRE,