diff --git a/openmc/filter.py b/openmc/filter.py index fc133168d2..260354d190 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -2,8 +2,10 @@ from __future__ import division from abc import ABCMeta from collections import Iterable, OrderedDict import copy +from functools import reduce import hashlib from numbers import Real, Integral +import operator from xml.etree import ElementTree as ET from six import add_metaclass @@ -95,7 +97,6 @@ class Filter(IDManagerMixin): def __init__(self, bins, filter_id=None): self.bins = bins self.id = filter_id - self._num_bins = 0 def __eq__(self, other): if type(self) is not type(other): @@ -170,7 +171,7 @@ class Filter(IDManagerMixin): # there is no overriden from_hdf5 method. Pass the bins to __init__. if group['type'].value.decode() == cls.short_name.lower(): out = cls(group['bins'].value, filter_id) - out.num_bins = group['n_bins'].value + out._num_bins = group['n_bins'].value return out # Search through all subclasses and find the one matching the HDF5 @@ -188,7 +189,7 @@ class Filter(IDManagerMixin): @property def num_bins(self): - return self._num_bins + return len(self.bins) @bins.setter def bins(self, bins): @@ -200,12 +201,6 @@ class Filter(IDManagerMixin): self._bins = bins - @num_bins.setter - def num_bins(self, num_bins): - cv.check_type('filter num_bins', num_bins, Integral) - cv.check_greater_than('filter num_bins', num_bins, 0, equality=True) - self._num_bins = num_bins - def check_bins(self, bins): """Make sure given bins are valid for this filter. @@ -430,17 +425,6 @@ class Filter(IDManagerMixin): class WithIDFilter(Filter): """Abstract parent for filters of types with ids (Cell, Material, etc.).""" - @property - def num_bins(self): - return len(self.bins) - - # Since num_bins property is declared, also need a num_bins.setter, but - # we don't want it to do anything since num_bins is completely determined - # by len(self.bins). We also don't want to raise an error because that - # makes importing from HDF5 more complicated. - @num_bins.setter - def num_bins(self, num_bins): pass - def _smart_set_bins(self, bins, bin_type): # Format the bins as a 1D numpy array. bins = np.atleast_1d(bins) @@ -634,10 +618,6 @@ class SurfaceFilter(Filter): def bins(self): return self._bins - @property - def num_bins(self): - return len(self.bins) - @bins.setter def bins(self, bins): # Format the bins as a 1D numpy array. @@ -650,8 +630,12 @@ class SurfaceFilter(Filter): self._bins = bins - @num_bins.setter - def num_bins(self, num_bins): pass + @property + def num_bins(self): + # Need to handle number of bins carefully -- for surface current + # tallies, the number of bins depends on the mesh, which we don't have a + # reference to in this filter + return self._num_bins def get_pandas_dataframe(self, data_size, stride, **kwargs): """Builds a Pandas DataFrame for the Filter's bins. @@ -737,7 +721,7 @@ class MeshFilter(Filter): filter_id = int(group.name.split('/')[-1].lstrip('filter ')) out = cls(mesh_obj, filter_id) - out.num_bins = group['n_bins'].value + out._num_bins = group['n_bins'].value return out @@ -751,6 +735,13 @@ class MeshFilter(Filter): self._mesh = mesh self.bins = mesh.id + @property + def num_bins(self): + try: + return self._num_bins + except AttributeError: + return reduce(operator.mul, self.mesh.dimension) + def check_bins(self, bins): if not len(bins) == 1: msg = 'Unable to add bins "{0}" to a MeshFilter since ' \ @@ -898,7 +889,7 @@ class RealFilter(Filter): A grid of bin values. id : int Unique identifier for the filter - num_bins : Integral + num_bins : int The number of filter bins """ @@ -915,12 +906,6 @@ class RealFilter(Filter): def num_bins(self): return len(self.bins) - 1 - @num_bins.setter - def num_bins(self, num_bins): - cv.check_type('filter num_bins', num_bins, Integral) - cv.check_greater_than('filter num_bins', num_bins, 0, equality=True) - self._num_bins = num_bins - def can_merge(self, other): if type(self) is not type(other): return False @@ -1006,7 +991,7 @@ class EnergyFilter(RealFilter): A grid of energy values in eV. id : int Unique identifier for the filter - num_bins : Integral + num_bins : int The number of filter bins """ @@ -1104,7 +1089,7 @@ class EnergyoutFilter(EnergyFilter): A grid of energy values in eV. id : int Unique identifier for the filter - num_bins : Integral + num_bins : int The number of filter bins """ @@ -1163,7 +1148,7 @@ class DistribcellFilter(Filter): An iterable with one element---the ID of the distributed Cell. id : int Unique identifier for the filter - num_bins : Integral + num_bins : int The number of filter bins paths : list of str The paths traversed through the CSG tree to reach each distribcell @@ -1185,7 +1170,7 @@ class DistribcellFilter(Filter): filter_id = int(group.name.split('/')[-1].lstrip('filter ')) out = cls(group['bins'].value, filter_id) - out.num_bins = group['n_bins'].value + out._num_bins = group['n_bins'].value return out @@ -1193,6 +1178,12 @@ class DistribcellFilter(Filter): def bins(self): return self._bins + @property + def num_bins(self): + # Need to handle number of bins carefully -- for distribcell tallies, we + # need to know how many instances of the cell there are + return self._num_bins + @property def paths(self): return self._paths @@ -1703,10 +1694,6 @@ class DelayedGroupFilter(Filter): def bins(self): return self._bins - @property - def num_bins(self): - return len(self.bins) - @bins.setter def bins(self, bins): # Format the bins as a 1D numpy array. @@ -1719,9 +1706,6 @@ class DelayedGroupFilter(Filter): self._bins = bins - @num_bins.setter - def num_bins(self, num_bins): pass - class EnergyFunctionFilter(Filter): """Multiplies tally scores by an arbitrary function of incident energy. diff --git a/openmc/tallies.py b/openmc/tallies.py index 9f8f7e505e..52e7a03c52 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -3,9 +3,10 @@ from __future__ import division from collections import Iterable, MutableSequence import copy import re -from functools import partial +from functools import partial, reduce from itertools import product from numbers import Integral, Real +import operator import warnings from xml.etree import ElementTree as ET @@ -185,19 +186,11 @@ class Tally(IDManagerMixin): @property def num_filter_bins(self): - num_bins = 1 - - for self_filter in self.filters: - num_bins *= self_filter.num_bins - - return num_bins + return reduce(operator.mul, (f.num_bins for f in self.filters), 1) @property def num_bins(self): - num_bins = self.num_filter_bins - num_bins *= self.num_nuclides - num_bins *= self.num_scores - return num_bins + return self.num_filter_bins * self.num_nuclides * self.num_scores @property def shape(self): @@ -2842,7 +2835,7 @@ class Tally(IDManagerMixin): num_bins += 1 find_filter.bins = np.unique(find_filter.bins[bin_indices]) - find_filter.num_bins = num_bins + find_filter._num_bins = num_bins # If original tally was sparse, sparsify the sliced tally new_tally.sparse = self.sparse