diff --git a/src/utils/openmc/tallies.py b/src/utils/openmc/tallies.py index 419f099592..59fb3910f4 100644 --- a/src/utils/openmc/tallies.py +++ b/src/utils/openmc/tallies.py @@ -145,17 +145,17 @@ class Tally(object): if self.num_realizations == other.num_realizations: new_tally.num_realizations = self.num_realizations - # If the two Tallies have same scores, replicate them in new Tally - if self.scores == other.scores: - for score in self.scores: - new_tally.add_score(score) + # If the two Tallies have same filters, replicate them in new Tally + if self.filters == other.filters: + for filter in self.filters: + new_tally.add_filter(filter) - # Generate score "cross product" + # Generate filter "cross product" else: - for self_score in self.scores: - for other_score in other.scores: - new_score = _CrossScore(self_score, other_score, '+') - new_tally.add_score(new_score) + for self_filter in self.filters: + for other_filter in other.filters: + new_filter = _CrossFilter(self_filter, other_filter, '+') + new_tally.add_filter(new_filter) # If the two Tallies have same nuclides, replicate them in new Tally if self.nuclides == other.nuclides: @@ -169,6 +169,18 @@ class Tally(object): new_nuclide = _CrossNuclide(self_nuclide, other_nuclide, '+') new_tally.add_nuclide(new_nuclide) + # If the two Tallies have same scores, replicate them in new Tally + if self.scores == other.scores: + for score in self.scores: + new_tally.add_score(score) + + # Generate score "cross product" + else: + for self_score in self.scores: + for other_score in other.scores: + new_score = _CrossScore(self_score, other_score, '+') + new_tally.add_score(new_score) + elif is_integer(other) or is_float(other): new_tally._mean = self._mean + other @@ -179,12 +191,15 @@ class Tally(object): new_tally.num_realization = self.num_realizations new_tally.num_score_bins = self.num_score_bins - for score in self.scores: - new_tally.add_score(score) + for filter in self.filters: + new_tally.add_filter(filter) for nuclide in self.nuclides: new_tally.add_nuclide(nuclide) + for score in self.scores: + new_tally.add_score(score) + else: msg = 'Unable to add {0} to Tally ID={1}'.format(other, self.id) raise ValueError(msg) @@ -232,17 +247,17 @@ class Tally(object): if self.num_realizations == other.num_realizations: new_tally.num_realizations = self.num_realizations - # If the two Tallies have same scores, replicate them in new Tally - if self.scores == other.scores: - for score in self.scores: - new_tally.add_score(score) + # If the two Tallies have same filters, replicate them in new Tally + if self.filters == other.filters: + for filter in self.filters: + new_tally.add_filter(filter) - # Generate score "cross product" + # Generate filter "cross product" else: - for self_score in self.scores: - for other_score in other.scores: - new_score = _CrossScore(self_score, other_score, '-') - new_tally.add_score(new_score) + for self_filter in self.filters: + for other_filter in other.filters: + new_filter = _CrossFilter(self_filter, other_filter, '-') + new_tally.add_filter(new_filter) # If the two Tallies have same nuclides, replicate them in new Tally if self.nuclides == other.nuclides: @@ -256,6 +271,18 @@ class Tally(object): new_nuclide = _CrossNuclide(self_nuclide, other_nuclide, '-') new_tally.add_nuclide(new_nuclide) + # If the two Tallies have same scores, replicate them in new Tally + if self.scores == other.scores: + for score in self.scores: + new_tally.add_score(score) + + # Generate score "cross product" + else: + for self_score in self.scores: + for other_score in other.scores: + new_score = _CrossScore(self_score, other_score, '-') + new_tally.add_score(new_score) + elif is_integer(other) or is_float(other): new_tally._mean = self._mean - other @@ -266,12 +293,15 @@ class Tally(object): new_tally.num_realization = self.num_realizations new_tally.num_score_bins = self.num_score_bins - for score in self.scores: - new_tally.add_score(score) + for filter in self.filters: + new_tally.add_filter(filter) for nuclide in self.nuclides: new_tally.add_nuclide(nuclide) + for score in self.scores: + new_tally.add_score(score) + else: msg = 'Unable to subtract {0} from Tally ' \ 'ID={1}'.format(other, self.id) @@ -303,8 +333,6 @@ class Tally(object): 'since it does not contain any results.'.format(other.id) raise ValueError(msg) - # FIXME: Need new CrossFilter class - data = self._align_tally_data(other) self_rel_err = data['self']['std. dev.'] / data['self']['mean'] @@ -322,17 +350,17 @@ class Tally(object): if self.num_realizations == other.num_realizations: new_tally.num_realizations = self.num_realizations - # If the two Tallies have same scores, replicate them in new Tally - if self.scores == other.scores: - for score in self.scores: - new_tally.add_score(score) + # If the two Tallies have same filters, replicate them in new Tally + if self.filters == other.filters: + for filter in self.filters: + new_tally.add_filter(filter) - # Generate score "cross product" + # Generate filter "cross product" else: - for self_score in self.scores: - for other_score in other.scores: - new_score = _CrossScore(self_score, other_score, '*') - new_tally.add_score(new_score) + for self_filter in self.filters: + for other_filter in other.filters: + new_filter = _CrossFilter(self_filter, other_filter, '*') + new_tally.add_filter(new_filter) # If the two Tallies have same nuclides, replicate them in new Tally if self.nuclides == other.nuclides: @@ -346,6 +374,18 @@ class Tally(object): new_nuclide = _CrossNuclide(self_nuclide, other_nuclide, '*') new_tally.add_nuclide(new_nuclide) + # If the two Tallies have same scores, replicate them in new Tally + if self.scores == other.scores: + for score in self.scores: + new_tally.add_score(score) + + # Generate score "cross product" + else: + for self_score in self.scores: + for other_score in other.scores: + new_score = _CrossScore(self_score, other_score, '*') + new_tally.add_score(new_score) + elif is_integer(other) or is_float(other): new_tally._mean = self._mean * other @@ -356,12 +396,15 @@ class Tally(object): new_tally.num_realization = self.num_realizations new_tally.num_score_bins = self.num_score_bins - for score in self.scores: - new_tally.add_score(score) + for filter in self.filters: + new_tally.add_filter(filter) for nuclide in self.nuclides: new_tally.add_nuclide(nuclide) + for score in self.scores: + new_tally.add_score(score) + else: msg = 'Unable to multiply Tally ID={1} ' \ 'by {0}'.format(self.id, other) @@ -412,17 +455,17 @@ class Tally(object): if self.num_realizations == other.num_realizations: new_tally.num_realizations = self.num_realizations - # If the two Tallies have same scores, replicate them in new Tally - if self.scores == other.scores: - for score in self.scores: - new_tally.add_score(score) + # If the two Tallies have same filters, replicate them in new Tally + if self.filters == other.filters: + for filter in self.filters: + new_tally.add_filter(filter) - # Generate score "cross product" + # Generate filter "cross product" else: - for self_score in self.scores: - for other_score in other.scores: - new_score = _CrossScore(self_score, other_score, '/') - new_tally.add_score(new_score) + for self_filter in self.filters: + for other_filter in other.filters: + new_filter = _CrossFilter(self_filter, other_filter, '/') + new_tally.add_filter(new_filter) # If the two Tallies have same nuclides, replicate them in new Tally if self.nuclides == other.nuclides: @@ -436,6 +479,17 @@ class Tally(object): new_nuclide = _CrossNuclide(self_nuclide, other_nuclide, '/') new_tally.add_nuclide(new_nuclide) + # If the two Tallies have same scores, replicate them in new Tally + if self.scores == other.scores: + for score in self.scores: + new_tally.add_score(score) + + # Generate score "cross product" + else: + for self_score in self.scores: + for other_score in other.scores: + new_score = _CrossScore(self_score, other_score, '/') + new_tally.add_score(new_score) elif is_integer(other) or is_float(other): @@ -447,12 +501,15 @@ class Tally(object): new_tally.num_realization = self.num_realizations new_tally.num_score_bins = self.num_score_bins - for score in self.scores: - new_tally.add_score(score) + for filter in self.filters: + new_tally.add_filter(filter) for nuclide in self.nuclides: new_tally.add_nuclide(nuclide) + for score in self.scores: + new_tally.add_score(score) + else: msg = 'Unable to divide Tally ID={0} ' \ 'by {1}'.format(self.id, other) @@ -504,17 +561,17 @@ class Tally(object): if self.num_realizations == power.num_realizations: new_tally.num_realizations = self.num_realizations - # If the two Tallies have same scores, replicate them in new Tally - if self.scores == power.scores: - for score in self.scores: - new_tally.add_score(score) + # If the two Tallies have same filters, replicate them in new Tally + if self.filters == power.filters: + for filter in self.filters: + new_tally.add_filter(filter) - # Generate score "cross product" + # Generate filter "cross product" else: - for self_score in self.scores: - for power_score in power.scores: - new_score = _CrossScore(self_score, power_score, '^') - new_tally.add_score(new_score) + for self_filter in self.filters: + for power_filter in power.filters: + new_filter = _CrossFilter(self_filter, power_filter, '^') + new_tally.add_filter(new_filter) # If the two Tallies have same nuclides, replicate them in new Tally if self.nuclides == power.nuclides: @@ -528,6 +585,18 @@ class Tally(object): new_nuclide = _CrossNuclide(self_nuclide, power_nuclide, '^') new_tally.add_nuclide(new_nuclide) + # If the two Tallies have same scores, replicate them in new Tally + if self.scores == power.scores: + for score in self.scores: + new_tally.add_score(score) + + # Generate score "cross product" + else: + for self_score in self.scores: + for power_score in power.scores: + new_score = _CrossScore(self_score, power_score, '^') + new_tally.add_score(new_score) + elif is_integer(power) or is_float(power): new_tally._mean = self._mean ** power @@ -539,12 +608,15 @@ class Tally(object): new_tally.num_realization = self.num_realizations new_tally.num_score_bins = self.num_score_bins - for score in self.scores: - new_tally.add_score(score) + for filter in self.filters: + new_tally.add_filter(filter) for nuclide in self.nuclides: new_tally.add_nuclide(nuclide) + for score in self.scores: + new_tally.add_score(score) + else: msg = 'Unable to raise Tally ID={0} to ' \ 'power {1}'.format(self.id, power) @@ -820,7 +892,7 @@ class Tally(object): global filters - if not isinstance(filter, Filter): + if not isinstance(filter, (Filter, _CrossFilter)): msg = 'Unable to add Filter "{0}" to Tally ID={1} since it is ' \ 'not a Filter object'.format(filter, self.id) raise ValueError(msg) @@ -2132,4 +2204,102 @@ class _CrossNuclide(object): else: string += str(self.right_nuclide) + ')' - return string \ No newline at end of file + return string + + +class _CrossFilter(object): + + def __init__(self, left_filter=None, right_filter=None, binary_op=None): + + self._left_filter = None + self._right_filter = None + self._binary_op = None + + if left_filter is not None: + self.left_filter = left_filter + + if right_filter is not None: + self.right_filter = right_filter + + if binary_op is not None: + self.binary_op = binary_op + + + @property + def left_filter(self): + return self._left_filter + + + @property + def right_filter(self): + return self._right_filter + + + @property + def binary_op(self): + return self._binary_op + + + @property + def type(self): + return (self.right_filter.type, self.left_filter.type) + + + @property + def bins(self): + return (self.right_filter.bins, self.left_filter.bins) + + + @property + def stride(self): + return self.left_filter.stride * self.right_filter.stride + + + @left_filter.setter + def left_filter(self, left_filter): + + if not isinstance(left_filter, Filter): + msg = 'Unable to set CrossFilter left filter to {0} which ' \ + 'is not a Filter'.format(left_filter) + raise ValueError(msg) + + self._left_filter = left_filter + + + @right_filter.setter + def right_filter(self, right_filter): + + if not isinstance(right_filter, Filter): + msg = 'Unable to set CrossFilter right filter to {0} which ' \ + 'is not a Filter'.format(right_filter) + raise ValueError(msg) + + self._right_filter = right_filter + + + @binary_op.setter + def binary_op(self, binary_op): + + if not is_string(binary_op): + msg = 'Unable to set CrossFilter binary op to {0} which ' \ + 'is not a string'.format(binary_op) + raise ValueError(msg) + + self._binary_op = binary_op + + + def __repr__(self): + + string = '_CrossFilter\n' + + filter_type = '({0} {1} {2})'.format(self.left_filter.type, + self.binary_op, + self.right_filter.type) + + filter_bins = '({0} {1} {2})'.format(self.left_filter.bins, + self.binary_op, + self.right_filter.bins) + + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', filter_type) + string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', filter_bins) + return string