Fixed some bugs in tally arithmetic tiling / repeats of NumPy data arrays

This commit is contained in:
Will Boyd 2015-05-31 17:12:06 -07:00
parent 6c23391309
commit e5b1cae874
2 changed files with 67 additions and 57 deletions

View file

@ -21,15 +21,15 @@ class Filter(object):
def __eq__(self, filter2):
# Check type
if self._type != filter2._type:
if self.type != filter2.type:
return False
# Check number of bins
elif len(self._bins) != len(filter2._bins):
elif len(self.bins) != len(filter2.bins):
return False
# Check bin edges
elif not np.allclose(self._bins, filter2._bins):
elif not np.allclose(self.bins, filter2.bins):
return False
else:
@ -38,8 +38,8 @@ class Filter(object):
def __hash__(self):
hashable = []
hashable.append(self._type)
hashable.append(self._bins)
hashable.append(self.type)
hashable.append(self.bins)
return hash(tuple(hashable))
@ -51,12 +51,12 @@ class Filter(object):
if existing is None:
clone = type(self).__new__(type(self))
clone._type = self._type
clone._bins = copy.deepcopy(self._bins, memo)
clone._num_bins = self._num_bins
clone._mesh = copy.deepcopy(self._mesh, memo)
clone._offset = self._offset
clone._stride = self._stride
clone._type = self.type
clone._bins = copy.deepcopy(self.bins, memo)
clone._num_bins = self.num_bins
clone._mesh = copy.deepcopy(self.mesh, memo)
clone._offset = self.offset
clone._stride = self.stride
memo[id(self)] = clone
@ -117,7 +117,7 @@ class Filter(object):
if bins is None:
self.num_bins = 0
elif self._type is None:
elif self.type is None:
msg = 'Unable to set bins for Filter to "{0}" since ' \
'the Filter type has not yet been set'.format(bins)
raise ValueError(msg)
@ -130,35 +130,35 @@ class Filter(object):
else:
bins = list(bins)
if self._type in ['cell', 'cellborn', 'surface', 'material',
if self.type in ['cell', 'cellborn', 'surface', 'material',
'universe', 'distribcell']:
for edge in bins:
if not is_integer(edge):
msg = 'Unable to add bin "{0}" to a {1} Filter since ' \
'it is a non-integer'.format(edge, self._type)
'it is a non-integer'.format(edge, self.type)
raise ValueError(msg)
elif edge < 0:
msg = 'Unable to add bin "{0}" to a {1} Filter since ' \
'it is a negative integer'.format(edge, self._type)
'it is a negative integer'.format(edge, self.type)
raise ValueError(msg)
elif self._type in ['energy', 'energyout']:
elif self.type in ['energy', 'energyout']:
for edge in bins:
if not is_integer(edge) and not is_float(edge):
msg = 'Unable to add bin edge "{0}" to a {1} Filter ' \
'since it is a non-integer or floating point ' \
'value'.format(edge, self._type)
'value'.format(edge, self.type)
raise ValueError(msg)
elif edge < 0.:
msg = 'Unable to add bin edge "{0}" to a {1} Filter ' \
'since it is a negative value'.format(edge, self._type)
'since it is a negative value'.format(edge, self.type)
raise ValueError(msg)
# Check that bin edges are monotonically increasing
@ -167,12 +167,12 @@ class Filter(object):
if index > 0 and bins[index] < bins[index-1]:
msg = 'Unable to add bin edges "{0}" to a {1} Filter ' \
'since they are not monotonically ' \
'increasing'.format(bins, self._type)
'increasing'.format(bins, self.type)
raise ValueError(msg)
# mesh filters
elif self._type == 'mesh':
elif self.type == 'mesh':
if not len(bins) == 1:
msg = 'Unable to add bins "{0}" to a mesh Filter since ' \
@ -193,14 +193,13 @@ class Filter(object):
self._bins = bins
# FIXME
@num_bins.setter
def num_bins(self, num_bins):
if not is_integer(num_bins) or num_bins < 0:
msg = 'Unable to set the number of bins "{0}" for a {1} Filter ' \
'since it is not a positive ' \
'integer'.format(num_bins, self._type)
'integer'.format(num_bins, self.type)
raise ValueError(msg)
self._num_bins = num_bins
@ -216,7 +215,7 @@ class Filter(object):
self._mesh = mesh
self.type = 'mesh'
self.bins = self._mesh._id
self.bins = self.mesh.id
@offset.setter
@ -224,7 +223,7 @@ class Filter(object):
if not is_integer(offset):
msg = 'Unable to set offset "{0}" for a {1} Filter since it is a ' \
'non-integer value'.format(offset, self._type)
'non-integer value'.format(offset, self.type)
raise ValueError(msg)
self._offset = offset
@ -235,12 +234,12 @@ class Filter(object):
if not is_integer(stride):
msg = 'Unable to set stride "{0}" for a {1} Filter since it is a ' \
'non-integer value'.format(stride, self._type)
'non-integer value'.format(stride, self.type)
raise ValueError(msg)
if stride < 0:
msg = 'Unable to set stride "{0}" for a {1} Filter since it is a ' \
'negative value'.format(stride, self._type)
'negative value'.format(stride, self.type)
raise ValueError(msg)
self._stride = stride
@ -274,14 +273,14 @@ class Filter(object):
def merge(self, filter):
if not self.can_merge(filter):
msg = 'Unable to merge {0} with {1} filters'.format(self._type, filter._type)
msg = 'Unable to merge {0} with {1} filters'.format(self.type, filter.type)
raise ValueError(msg)
# Create deep copy of filter to return as merged filter
merged_filter = copy.deepcopy(self)
# Merge unique filter bins
merged_bins = list(set(self._bins + filter._bins))
merged_bins = list(set(self.bins + filter.bins))
merged_filter.bins = merged_bins
merged_filter.num_bins = len(merged_bins)
@ -335,7 +334,7 @@ class Filter(object):
# Filter bins for distribcell are the "IDs" of each unique placement
# of the Cell in the Geometry (integers starting at 0)
elif self._type == 'distribcell':
elif self.type == 'distribcell':
filter_index = filter_bin
# Use ID for all other Filters (e.g., material, cell, etc.)
@ -354,7 +353,7 @@ class Filter(object):
def __repr__(self):
string = 'Filter\n'
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self._bins)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self._offset)
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self.offset)
return string

View file

@ -58,14 +58,14 @@ class Tally(object):
self_num_filter_bins = self.mean.shape[0]
other_num_filter_bins = other.mean.shape[0]
num_filter_bins = self_num_filter_bins * other_num_filter_bins
self_new_bins = max(num_filter_bins - self_num_filter_bins, 1)
other_new_bins = max(num_filter_bins - other_num_filter_bins, 1)
self_repeat_factor = num_filter_bins / self_num_filter_bins
other_tile_factor = num_filter_bins / other_num_filter_bins
# Replicate the data
self_mean = np.repeat(self_mean, self_new_bins, axis=0)
other_mean = np.tile(other_mean, (other_new_bins, 1, 1))
self_std_dev = np.repeat(self_std_dev, self_new_bins, axis=0)
other_std_dev = np.tile(other_std_dev, (other_new_bins, 1, 1))
self_mean = np.repeat(self_mean, self_repeat_factor, axis=0)
other_mean = np.tile(other_mean, (other_tile_factor, 1, 1))
self_std_dev = np.repeat(self_std_dev, self_repeat_factor, axis=0)
other_std_dev = np.tile(other_std_dev, (other_tile_factor, 1, 1))
if self.nuclides != other.nuclides:
@ -74,14 +74,14 @@ class Tally(object):
self_num_nuclide_bins = self.mean.shape[1]
other_num_nuclide_bins = other.mean.shape[1]
num_nuclide_bins = self_num_nuclide_bins * other_num_nuclide_bins
self_new_bins = max(num_nuclide_bins - self_num_nuclide_bins, 1)
other_new_bins = max(num_nuclide_bins - other_num_nuclide_bins, 1)
self_repeat_factor = num_nuclide_bins / self_num_nuclide_bins
other_tile_factor = num_nuclide_bins / other_num_nuclide_bins
# Replicate the data
self_mean = np.repeat(self_mean, self_new_bins, axis=1)
other_mean = np.tile(other_mean, (1, other_new_bins, 1))
self_std_dev = np.repeat(self_std_dev, self_new_bins, axis=1)
other_std_dev = np.tile(other_std_dev, (1, other_new_bins, 1))
self_mean = np.repeat(self_mean, self_repeat_factor, axis=1)
other_mean = np.tile(other_mean, (1, other_tile_factor, 1))
self_std_dev = np.repeat(self_std_dev, self_repeat_factor, axis=1)
other_std_dev = np.tile(other_std_dev, (1, other_tile_factor, 1))
if self.scores != other.scores:
@ -90,14 +90,14 @@ class Tally(object):
self_num_score_bins = self.mean.shape[2]
other_num_score_bins = other.mean.shape[2]
num_score_bins = self_num_score_bins * other_num_score_bins
self_new_bins = max(num_score_bins - self_num_score_bins, 1)
other_new_bins = max(num_score_bins - other_num_score_bins, 1)
self_repeat_factor = num_score_bins / self_num_score_bins
other_tile_factor = num_score_bins / other_num_score_bins
# Replicate the data
self_mean = np.repeat(self_mean, self_new_bins, axis=2)
other_mean = np.tile(other_mean, (1, 1, other_new_bins))
self_std_dev = np.repeat(self_std_dev, self_new_bins, axis=2)
other_std_dev = np.tile(other_std_dev, (1, 1, other_new_bins))
self_mean = np.repeat(self_mean, self_repeat_factor, axis=2)
other_mean = np.tile(other_mean, (1, 1, other_tile_factor))
self_std_dev = np.repeat(self_std_dev, self_repeat_factor, axis=2)
other_std_dev = np.tile(other_std_dev, (1, 1, other_tile_factor))
data = {}
data['self'] = {}
@ -1571,10 +1571,21 @@ class Tally(object):
# Find the total length of the tally data array
data_size = self.mean.size
# Split CrossFilters into separate filters
split_filters = []
for filter in self.filters:
if isinstance(filter, _CrossFilter):
split_filters.append(filter.left_filter)
split_filters.append(filter.right_filter)
else:
split_filters.append(filter)
# Build DataFrame columns for filters if user requested them
if filters:
for filter in self.filters:
for filter in split_filters:
# mesh filters
if filter.type == 'mesh':
@ -2114,7 +2125,7 @@ class _CrossScore(object):
@left_score.setter
def left_score(self, left_score):
if not is_string(left_score):
if not isinstance(left_score, (_CrossScore, str)):
msg = 'Unable to set CrossScore left score to {0} which ' \
'is not a string'.format(left_score)
raise ValueError(msg)
@ -2125,7 +2136,7 @@ class _CrossScore(object):
@right_score.setter
def right_score(self, right_score):
if not is_string(right_score):
if not isinstance(right_score, (_CrossScore, str)):
msg = 'Unable to set CrossScore right score to {0} which ' \
'is not a string'.format(right_score)
raise ValueError(msg)
@ -2186,7 +2197,7 @@ class _CrossNuclide(object):
@left_nuclide.setter
def left_nuclide(self, left_nuclide):
if not isinstance(left_nuclide, Nuclide) or is_integer(left_nuclide):
if not isinstance(left_nuclide, (Nuclide, _CrossNuclide, int)):
msg = 'Unable to set CrossNuclide left nuclide to {0} which ' \
'is not an integer or Nuclide'.format(left_nuclide)
raise ValueError(msg)
@ -2197,7 +2208,7 @@ class _CrossNuclide(object):
@right_nuclide.setter
def right_nuclide(self, right_nuclide):
if not isinstance(right_nuclide, Nuclide) or is_integer(right_nuclide):
if not isinstance(right_nuclide, (Nuclide, _CrossNuclide, int)):
msg = 'Unable to set CrossNuclide right nuclide to {0} which ' \
'is not an integer or Nuclide'.format(right_nuclide)
raise ValueError(msg)
@ -2290,7 +2301,7 @@ class _CrossFilter(object):
@left_filter.setter
def left_filter(self, left_filter):
if not isinstance(left_filter, Filter):
if not isinstance(left_filter, (Filter, _CrossFilter)):
msg = 'Unable to set CrossFilter left filter to {0} which ' \
'is not a Filter'.format(left_filter)
raise ValueError(msg)
@ -2301,7 +2312,7 @@ class _CrossFilter(object):
@right_filter.setter
def right_filter(self, right_filter):
if not isinstance(right_filter, Filter):
if not isinstance(right_filter, (Filter, _CrossFilter)):
msg = 'Unable to set CrossFilter right filter to {0} which ' \
'is not a Filter'.format(right_filter)
raise ValueError(msg)