From 45495b300f3418d9fe79bf9aac7527a0bba27559 Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Wed, 27 Jan 2016 16:44:52 -0500 Subject: [PATCH 1/6] Fixed issues with typechecking for tally aggregation --- openmc/aggregate.py | 409 ------------------------------------------ openmc/cross.py | 422 +++++++++++++++++++++++++++++++++++++++++++- openmc/tallies.py | 11 +- 3 files changed, 419 insertions(+), 423 deletions(-) delete mode 100644 openmc/aggregate.py diff --git a/openmc/aggregate.py b/openmc/aggregate.py deleted file mode 100644 index 011ad3850..000000000 --- a/openmc/aggregate.py +++ /dev/null @@ -1,409 +0,0 @@ -import sys -from numbers import Integral - -import numpy as np - -from openmc import Filter, Nuclide -from openmc.cross import CrossScore, CrossNuclide, CrossFilter -from openmc.filter import _FILTER_TYPES -import openmc.checkvalue as cv - - -if sys.version_info[0] >= 3: - basestring = str - -# Acceptable tally aggregation operations -_TALLY_AGGREGATE_OPS = ['sum', 'mean'] - - -class AggregateScore(object): - """A special-purpose tally score used to encapsulate an aggregate of a - subset or all of tally's scores for tally aggregation. - - Parameters - ---------- - scores : Iterable of str or CrossScore - The scores included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally's scores with this AggregateScore - - Attributes - ---------- - scores : Iterable of str or CrossScore - The scores included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally's scores with this AggregateScore - - """ - - def __init__(self, scores=None, aggregate_op=None): - - self._scores = None - self._aggregate_op = None - - if scores is not None: - self.scores = scores - if aggregate_op is not None: - self.aggregate_op = aggregate_op - - def __hash__(self): - return hash(repr(self)) - - def __eq__(self, other): - return str(other) == str(self) - - def __ne__(self, other): - return not self == other - - def __deepcopy__(self, memo): - existing = memo.get(id(self)) - - # If this is the first time we have tried to copy this object, create a copy - if existing is None: - clone = type(self).__new__(type(self)) - clone._scores = self.scores - clone._aggregate_op = self.aggregate_op - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - def __repr__(self): - string = ', '.join(map(str, self.scores)) - string = '{0}({1})'.format(self.aggregate_op, string) - return string - - @property - def scores(self): - return self._scores - - @property - def aggregate_op(self): - return self._aggregate_op - - @scores.setter - def scores(self, scores): - cv.check_iterable_type('scores', scores, basestring) - self._scores = scores - - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore)) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - - -class AggregateNuclide(object): - """A special-purpose tally nuclide used to encapsulate an aggregate of a - subset or all of tally's nuclides for tally aggregation. - - Parameters - ---------- - nuclides : Iterable of str or Nuclide or CrossNuclide - The nuclides included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally's nuclides with this AggregateNuclide - - Attributes - ---------- - nuclides : Iterable of str or Nuclide or CrossNuclide - The nuclides included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally's nuclides with this AggregateNuclide - - """ - - def __init__(self, nuclides=None, aggregate_op=None): - - self._nuclides = None - self._aggregate_op = None - - if nuclides is not None: - self.nuclides = nuclides - if aggregate_op is not None: - self.aggregate_op = aggregate_op - - def __hash__(self): - return hash(repr(self)) - - def __eq__(self, other): - return str(other) == str(self) - - def __ne__(self, other): - return not self == other - - def __deepcopy__(self, memo): - existing = memo.get(id(self)) - - # If this is the first time we have tried to copy this object, create a copy - if existing is None: - clone = type(self).__new__(type(self)) - clone._nuclides = self.nuclides - clone._aggregate_op = self._aggregate_op - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - def __repr__(self): - - # Append each nuclide in the aggregate to the string - string = '{0}('.format(self.aggregate_op) - names = [nuclide.name if isinstance(nuclide, Nuclide) else str(nuclide) - for nuclide in self.nuclides] - string += ', '.join(map(str, names)) + ')' - return string - - @property - def nuclides(self): - return self._nuclides - - @property - def aggregate_op(self): - return self._aggregate_op - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, - (basestring, Nuclide, CrossNuclide)) - self._nuclides = nuclides - - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, basestring) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - - -class AggregateFilter(object): - """A special-purpose tally filter used to encapsulate an aggregate of a - subset or all of a tally filter's bins for tally aggregation. - - Parameters - ---------- - aggregate_filter : Filter or CrossFilter - The filter included in the aggregation - bins : Iterable of tuple - The filter bins included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally filter's bins with this AggregateFilter - - Attributes - ---------- - type : str - The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)') - aggregate_filter : filter - The filter included in the aggregation - aggregate_op : str - The tally aggregation operator (e.g., 'sum', 'mean', etc.) used - to aggregate across a tally filter's bins with this AggregateFilter - bins : Iterable of tuple - The filter bins included in the aggregation - num_bins : Integral - The number of filter bins (always 1 if aggregate_filter is defined) - stride : Integral - The number of filter, nuclide and score bins within each of this - aggregatefilter's bins. - - """ - - def __init__(self, aggregate_filter=None, bins=None, aggregate_op=None): - - self._type = '{0}({1})'.format(aggregate_op, aggregate_filter.type) - self._bins = None - self._stride = None - - self._aggregate_filter = None - self._aggregate_op = None - - if aggregate_filter is not None: - self.aggregate_filter = aggregate_filter - if bins is not None: - self.bins = bins - if aggregate_op is not None: - self.aggregate_op = aggregate_op - - def __hash__(self): - return hash(repr(self)) - - def __eq__(self, other): - return str(other) == str(self) - - def __ne__(self, other): - return not self == other - - def __repr__(self): - string = 'AggregateFilter\n' - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type) - string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins) - return string - - def __deepcopy__(self, memo): - existing = memo.get(id(self)) - - # If this is the first time we have tried to copy this object, create a copy - if existing is None: - clone = type(self).__new__(type(self)) - clone._type = self.type - clone._aggregate_filter = self.aggregate_filter - clone._aggregate_op = self.aggregate_op - clone._bins = self._bins - clone._stride = self.stride - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - @property - def aggregate_filter(self): - return self._aggregate_filter - - @property - def aggregate_op(self): - return self._aggregate_op - - @property - def type(self): - return self._type - - @property - def bins(self): - return self._bins - - @property - def num_bins(self): - return 1 if self.aggregate_filter else 0 - - @property - def stride(self): - return self._stride - - @type.setter - def type(self, filter_type): - if filter_type not in _FILTER_TYPES.values(): - msg = 'Unable to set AggregateFilter type to "{0}" since it ' \ - 'is not one of the supported types'.format(filter_type) - raise ValueError(msg) - - self._type = filter_type - - @aggregate_filter.setter - def aggregate_filter(self, aggregate_filter): - cv.check_type('aggregate_filter', aggregate_filter, (Filter, CrossFilter)) - self._aggregate_filter = aggregate_filter - - @bins.setter - def bins(self, bins): - cv.check_iterable_type('bins', bins, (Integral, tuple)) - self._bins = bins - - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, basestring) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - - @stride.setter - def stride(self, stride): - self._stride = stride - - def get_bin_index(self, filter_bin): - """Returns the index in the AggregateFilter for some bin. - - Parameters - ---------- - filter_bin : Integral or tuple of Real - A tuple of value(s) corresponding to the bin of interest in - the aggregated filter. The bin is the integer ID for 'material', - 'surface', 'cell', 'cellborn', and 'universe' Filters. The bin - is the integer cell instance ID for 'distribcell' Filters. The - bin is a 2-tuple of floats for 'energy' and 'energyout' filters - corresponding to the energy boundaries of the bin of interest. - The bin is a (x,y,z) 3-tuple for 'mesh' filters corresponding to - the mesh cell of interest. - - Returns - ------- - filter_index : Integral - The index in the Tally data array for this filter bin. For an - AggregateTally the filter bin index is always unity. - - Raises - ------ - ValueError - When the filter_bin is not part of the aggregated filter's bins - - """ - - if filter_bin not in self.bins: - msg = 'Unable to get the bin index for AggregateFilter since ' \ - '"{0}" is not one of the bins'.format(filter_bin) - raise ValueError(msg) - else: - return 0 - - def get_pandas_dataframe(self, datasize, summary=None): - """Builds a Pandas DataFrame for the AggregateFilter's bins. - - This method constructs a Pandas DataFrame object for the AggregateFilter - with columns annotated by filter bin information. This is a helper - method for the Tally.get_pandas_dataframe(...) method. - - Parameters - ---------- - datasize : Integral - The total number of bins in the tally corresponding to this filter - summary : None or Summary - An optional Summary object to be used to construct columns for - distribcell tally filters (default is None). NOTE: This parameter - is not used by the AggregateFilter and simply mirrors the method - signature for the CrossFilter. - - Returns - ------- - pandas.DataFrame - A Pandas DataFrame with columns of strings that characterize the - aggregatefilter's bins. Each entry in the DataFrame will include - one or more aggregation operations used to construct the - aggregatefilter's bins. The number of rows in the DataFrame is the - same as the total number of bins in the corresponding tally, with - the filter bins appropriately tiled to map to the corresponding - tally bins. - - See also - -------- - Tally.get_pandas_dataframe(), Filter.get_pandas_dataframe(), - CrossFilter.get_pandas_dataframe() - - """ - - import pandas as pd - - # Construct a sring representing the filter aggregation - aggregate_bin = '{0}('.format(self.aggregate_op) - aggregate_bin += ', '.join(map(str, self.bins)) + ')' - - # Construct NumPy array of bin repeated for each element in dataframe - aggregate_bin_array = np.array([aggregate_bin]) - aggregate_bin_array = np.repeat(aggregate_bin_array, datasize) - - # Construct Pandas DataFrame for the AggregateFilter - df = pd.DataFrame({self.type: aggregate_bin_array}) - return df diff --git a/openmc/cross.py b/openmc/cross.py index ee0fcb4c8..65e12c5d2 100644 --- a/openmc/cross.py +++ b/openmc/cross.py @@ -1,16 +1,21 @@ import sys +from numbers import Integral + +import numpy as np from openmc import Filter, Nuclide from openmc.filter import _FILTER_TYPES import openmc.checkvalue as cv - if sys.version_info[0] >= 3: basestring = str # Acceptable tally arithmetic binary operations _TALLY_ARITHMETIC_OPS = ['+', '-', '*', '/', '^'] +# Acceptable tally aggregation operations +_TALLY_AGGREGATE_OPS = ['sum', 'mean'] + class CrossScore(object): """A special-purpose tally score used to encapsulate all combinations of two @@ -97,17 +102,19 @@ class CrossScore(object): @left_score.setter def left_score(self, left_score): - cv.check_type('left_score', left_score, (basestring, CrossScore)) + cv.check_type('left_score', left_score, + (basestring, CrossScore, AggregateScore)) self._left_score = left_score @right_score.setter def right_score(self, right_score): - cv.check_type('right_score', right_score, (basestring, CrossScore)) + cv.check_type('right_score', right_score, + (basestring, CrossScore, AggregateScore)) self._right_score = right_score @binary_op.setter def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, (basestring, CrossScore)) + cv.check_type('binary_op', binary_op, basestring) cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) self._binary_op = binary_op @@ -214,12 +221,14 @@ class CrossNuclide(object): @left_nuclide.setter def left_nuclide(self, left_nuclide): - cv.check_type('left_nuclide', left_nuclide, (Nuclide, CrossNuclide)) + cv.check_type('left_nuclide', left_nuclide, + (Nuclide, CrossNuclide, AggregateNuclide)) self._left_nuclide = left_nuclide @right_nuclide.setter def right_nuclide(self, right_nuclide): - cv.check_type('right_nuclide', right_nuclide, (Nuclide, CrossNuclide)) + cv.check_type('right_nuclide', right_nuclide, + (Nuclide, CrossNuclide, AggregateNuclide)) self._right_nuclide = right_nuclide @binary_op.setter @@ -372,13 +381,15 @@ class CrossFilter(object): @left_filter.setter def left_filter(self, left_filter): - cv.check_type('left_filter', left_filter, (Filter, CrossFilter)) + cv.check_type('left_filter', left_filter, + (Filter, CrossFilter, AggregateFilter)) self._left_filter = left_filter self._bins['left'] = left_filter.bins @right_filter.setter def right_filter(self, right_filter): - cv.check_type('right_filter', right_filter, (Filter, CrossFilter)) + cv.check_type('right_filter', right_filter, + (Filter, CrossFilter, AggregateFilter)) self._right_filter = right_filter self._bins['right'] = right_filter.bins @@ -472,3 +483,398 @@ class CrossFilter(object): df = '(' + left_df + ' ' + self.binary_op + ' ' + right_df + ')' return df + + +class AggregateScore(object): + """A special-purpose tally score used to encapsulate an aggregate of a + subset or all of tally's scores for tally aggregation. + + Parameters + ---------- + scores : Iterable of str or CrossScore + The scores included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally's scores with this AggregateScore + + Attributes + ---------- + scores : Iterable of str or CrossScore + The scores included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally's scores with this AggregateScore + + """ + + def __init__(self, scores=None, aggregate_op=None): + + self._scores = None + self._aggregate_op = None + + if scores is not None: + self.scores = scores + if aggregate_op is not None: + self.aggregate_op = aggregate_op + + def __hash__(self): + return hash(repr(self)) + + def __eq__(self, other): + return str(other) == str(self) + + def __ne__(self, other): + return not self == other + + def __deepcopy__(self, memo): + existing = memo.get(id(self)) + + # If this is the first time we have tried to copy this object, create a copy + if existing is None: + clone = type(self).__new__(type(self)) + clone._scores = self.scores + clone._aggregate_op = self.aggregate_op + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + def __repr__(self): + string = ', '.join(map(str, self.scores)) + string = '{0}({1})'.format(self.aggregate_op, string) + return string + + @property + def scores(self): + return self._scores + + @property + def aggregate_op(self): + return self._aggregate_op + + @scores.setter + def scores(self, scores): + cv.check_iterable_type('scores', scores, + (basestring, CrossScore, AggregateScore)) + self._scores = scores + + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore)) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + + +class AggregateNuclide(object): + """A special-purpose tally nuclide used to encapsulate an aggregate of a + subset or all of tally's nuclides for tally aggregation. + + Parameters + ---------- + nuclides : Iterable of str or Nuclide or CrossNuclide + The nuclides included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally's nuclides with this AggregateNuclide + + Attributes + ---------- + nuclides : Iterable of str or Nuclide or CrossNuclide + The nuclides included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally's nuclides with this AggregateNuclide + + """ + + def __init__(self, nuclides=None, aggregate_op=None): + + self._nuclides = None + self._aggregate_op = None + + if nuclides is not None: + self.nuclides = nuclides + if aggregate_op is not None: + self.aggregate_op = aggregate_op + + def __hash__(self): + return hash(repr(self)) + + def __eq__(self, other): + return str(other) == str(self) + + def __ne__(self, other): + return not self == other + + def __deepcopy__(self, memo): + existing = memo.get(id(self)) + + # If this is the first time we have tried to copy this object, create a copy + if existing is None: + clone = type(self).__new__(type(self)) + clone._nuclides = self.nuclides + clone._aggregate_op = self._aggregate_op + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + def __repr__(self): + + # Append each nuclide in the aggregate to the string + string = '{0}('.format(self.aggregate_op) + names = [nuclide.name if isinstance(nuclide, Nuclide) else str(nuclide) + for nuclide in self.nuclides] + string += ', '.join(map(str, names)) + ')' + return string + + @property + def nuclides(self): + return self._nuclides + + @property + def aggregate_op(self): + return self._aggregate_op + + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, + (basestring, Nuclide, CrossNuclide, AggregateNuclide)) + self._nuclides = nuclides + + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, basestring) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + + +class AggregateFilter(object): + """A special-purpose tally filter used to encapsulate an aggregate of a + subset or all of a tally filter's bins for tally aggregation. + + Parameters + ---------- + aggregate_filter : Filter or CrossFilter + The filter included in the aggregation + bins : Iterable of tuple + The filter bins included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally filter's bins with this AggregateFilter + + Attributes + ---------- + type : str + The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)') + aggregate_filter : filter + The filter included in the aggregation + aggregate_op : str + The tally aggregation operator (e.g., 'sum', 'mean', etc.) used + to aggregate across a tally filter's bins with this AggregateFilter + bins : Iterable of tuple + The filter bins included in the aggregation + num_bins : Integral + The number of filter bins (always 1 if aggregate_filter is defined) + stride : Integral + The number of filter, nuclide and score bins within each of this + aggregatefilter's bins. + + """ + + def __init__(self, aggregate_filter=None, bins=None, aggregate_op=None): + + self._type = '{0}({1})'.format(aggregate_op, aggregate_filter.type) + self._bins = None + self._stride = None + + self._aggregate_filter = None + self._aggregate_op = None + + if aggregate_filter is not None: + self.aggregate_filter = aggregate_filter + if bins is not None: + self.bins = bins + if aggregate_op is not None: + self.aggregate_op = aggregate_op + + def __hash__(self): + return hash(repr(self)) + + def __eq__(self, other): + return str(other) == str(self) + + def __ne__(self, other): + return not self == other + + def __repr__(self): + string = 'AggregateFilter\n' + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type) + string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins) + return string + + def __deepcopy__(self, memo): + existing = memo.get(id(self)) + + # If this is the first time we have tried to copy this object, create a copy + if existing is None: + clone = type(self).__new__(type(self)) + clone._type = self.type + clone._aggregate_filter = self.aggregate_filter + clone._aggregate_op = self.aggregate_op + clone._bins = self._bins + clone._stride = self.stride + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + @property + def aggregate_filter(self): + return self._aggregate_filter + + @property + def aggregate_op(self): + return self._aggregate_op + + @property + def type(self): + return self._type + + @property + def bins(self): + return self._bins + + @property + def num_bins(self): + return 1 if self.aggregate_filter else 0 + + @property + def stride(self): + return self._stride + + @type.setter + def type(self, filter_type): + if filter_type not in _FILTER_TYPES.values(): + msg = 'Unable to set AggregateFilter type to "{0}" since it ' \ + 'is not one of the supported types'.format(filter_type) + raise ValueError(msg) + + self._type = filter_type + + @aggregate_filter.setter + def aggregate_filter(self, aggregate_filter): + cv.check_type('aggregate_filter', aggregate_filter, + (Filter, CrossFilter, AggregateFilter)) + self._aggregate_filter = aggregate_filter + + @bins.setter + def bins(self, bins): + cv.check_iterable_type('bins', bins, (Integral, tuple)) + self._bins = bins + + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, basestring) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + + @stride.setter + def stride(self, stride): + self._stride = stride + + def get_bin_index(self, filter_bin): + """Returns the index in the AggregateFilter for some bin. + + Parameters + ---------- + filter_bin : Integral or tuple of Real + A tuple of value(s) corresponding to the bin of interest in + the aggregated filter. The bin is the integer ID for 'material', + 'surface', 'cell', 'cellborn', and 'universe' Filters. The bin + is the integer cell instance ID for 'distribcell' Filters. The + bin is a 2-tuple of floats for 'energy' and 'energyout' filters + corresponding to the energy boundaries of the bin of interest. + The bin is a (x,y,z) 3-tuple for 'mesh' filters corresponding to + the mesh cell of interest. + + Returns + ------- + filter_index : Integral + The index in the Tally data array for this filter bin. For an + AggregateTally the filter bin index is always unity. + + Raises + ------ + ValueError + When the filter_bin is not part of the aggregated filter's bins + + """ + + if filter_bin not in self.bins: + msg = 'Unable to get the bin index for AggregateFilter since ' \ + '"{0}" is not one of the bins'.format(filter_bin) + raise ValueError(msg) + else: + return 0 + + def get_pandas_dataframe(self, datasize, summary=None): + """Builds a Pandas DataFrame for the AggregateFilter's bins. + + This method constructs a Pandas DataFrame object for the AggregateFilter + with columns annotated by filter bin information. This is a helper + method for the Tally.get_pandas_dataframe(...) method. + + Parameters + ---------- + datasize : Integral + The total number of bins in the tally corresponding to this filter + summary : None or Summary + An optional Summary object to be used to construct columns for + distribcell tally filters (default is None). NOTE: This parameter + is not used by the AggregateFilter and simply mirrors the method + signature for the CrossFilter. + + Returns + ------- + pandas.DataFrame + A Pandas DataFrame with columns of strings that characterize the + aggregatefilter's bins. Each entry in the DataFrame will include + one or more aggregation operations used to construct the + aggregatefilter's bins. The number of rows in the DataFrame is the + same as the total number of bins in the corresponding tally, with + the filter bins appropriately tiled to map to the corresponding + tally bins. + + See also + -------- + Tally.get_pandas_dataframe(), Filter.get_pandas_dataframe(), + CrossFilter.get_pandas_dataframe() + + """ + + import pandas as pd + + # Construct a sring representing the filter aggregation + aggregate_bin = '{0}('.format(self.aggregate_op) + aggregate_bin += ', '.join(map(str, self.bins)) + ')' + + # Construct NumPy array of bin repeated for each element in dataframe + aggregate_bin_array = np.array([aggregate_bin]) + aggregate_bin_array = np.repeat(aggregate_bin_array, datasize) + + # Construct Pandas DataFrame for the AggregateFilter + df = pd.DataFrame({self.type: aggregate_bin_array}) + return df diff --git a/openmc/tallies.py b/openmc/tallies.py index 9b75f35d4..fb07532a0 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -12,8 +12,7 @@ import sys import numpy as np from openmc import Mesh, Filter, Trigger, Nuclide -from openmc.cross import CrossScore, CrossNuclide, CrossFilter -from openmc.aggregate import AggregateScore, AggregateNuclide, AggregateFilter +from openmc.cross import * from openmc.filter import _FILTER_TYPES import openmc.checkvalue as cv from openmc.clean_xml import * @@ -2680,11 +2679,11 @@ class Tally(object): new_tally = copy.deepcopy(self) new_tally.sparse = False - if self.sum is not None: + if not self.derived and self.sum is not None: new_sum = self.get_values(scores, filters, filter_bins, nuclides, 'sum') new_tally.sum = new_sum - if self.sum_sq is not None: + if not self.derived and self.sum_sq is not None: new_sum_sq = self.get_values(scores, filters, filter_bins, nuclides, 'sum_sq') new_tally.sum_sq = new_sum_sq @@ -2955,10 +2954,10 @@ class Tally(object): diag_indices[start:end] = indices + (i * new_filter.num_bins**2) # Inject this Tally's data along the diagonal of the diagonalized Tally - if self.sum is not None: + if not self.derived and self.sum is not None: new_tally._sum = np.zeros(new_tally.shape, dtype=np.float64) new_tally._sum[diag_indices, :, :] = self.sum - if self.sum_sq is not None: + if not self.derived and self.sum_sq is not None: new_tally._sum_sq = np.zeros(new_tally.shape, dtype=np.float64) new_tally._sum_sq[diag_indices, :, :] = self.sum_sq if self.mean is not None: From bd841a268f86117da6e9e370ef99088f9ea416d6 Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Thu, 28 Jan 2016 12:56:52 -0500 Subject: [PATCH 2/6] Fixed bug in StatePoint.with_summary property --- openmc/statepoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 49ac43590..4c6f956a4 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -451,7 +451,7 @@ class StatePoint(object): @property def with_summary(self): - return False if self.summary is None else True + return False if self.summary is False else True @sparse.setter def sparse(self, sparse): From 3d9353b086076cce4f0a95ee19d1b028c1c41c18 Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Thu, 28 Jan 2016 13:41:08 -0500 Subject: [PATCH 3/6] Removed StatePoint.with_summary property --- openmc/mgxs/library.py | 2 +- openmc/mgxs/mgxs.py | 2 +- openmc/statepoint.py | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index ca9fa5d66..4b8d8a914 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -396,7 +396,7 @@ class Library(object): cv.check_type('statepoint', statepoint, openmc.StatePoint) - if not statepoint.with_summary: + if statepoint.summary is None: msg = 'Unable to load data from a statepoint which has not been ' \ 'linked with a summary file' raise ValueError(msg) diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index bfa8b02c5..d1f3d4b06 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -583,7 +583,7 @@ class MGXS(object): cv.check_type('statepoint', statepoint, openmc.statepoint.StatePoint) - if not statepoint.with_summary: + if statepoint.summary is None: msg = 'Unable to load data from a statepoint which has not been ' \ 'linked with a summary file' raise ValueError(msg) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 4c6f956a4..b7af1a961 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -1,4 +1,4 @@ -import sys +mport sys import re import numpy as np @@ -449,10 +449,6 @@ class StatePoint(object): def summary(self): return self._summary - @property - def with_summary(self): - return False if self.summary is False else True - @sparse.setter def sparse(self, sparse): """Convert tally data from NumPy arrays to SciPy list of lists (LIL) From 1e89fd53e6b5536b53ed23e2482a92a6e5fdcbff Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Thu, 28 Jan 2016 13:50:11 -0500 Subject: [PATCH 4/6] Fixed typo in imports for statepoint.py --- openmc/statepoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index b7af1a961..f5b5b2e72 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -1,4 +1,4 @@ -mport sys +import sys import re import numpy as np From 3cbea749cb7919a826bcc73f5fe1edbddcc2e497 Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Thu, 28 Jan 2016 13:54:38 -0500 Subject: [PATCH 5/6] Now clear any old tallies in MGXS.load_from_statepoint(...) --- openmc/mgxs/mgxs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index d1f3d4b06..f24127458 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -612,6 +612,11 @@ class MGXS(object): filters = [] filter_bins = [] + # Clear any tallies previously loaded from a statepoint + self._tallies = None + self._xs_tally = None + self._rxn_rate_tally = None + # Find, slice and store Tallies from StatePoint # The tally slicing is needed if tally merging was used for tally_type, tally in self.tallies.items(): From 0e2db9afee6d9bf35a5b5618e01b67c48b2449b5 Mon Sep 17 00:00:00 2001 From: "wbinventor@gmail.com" Date: Thu, 28 Jan 2016 14:42:07 -0500 Subject: [PATCH 6/6] Renamed cross.py to arithmetic.py per suggestion by @paulromano --- openmc/{cross.py => arithmetic.py} | 0 openmc/tallies.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename openmc/{cross.py => arithmetic.py} (100%) diff --git a/openmc/cross.py b/openmc/arithmetic.py similarity index 100% rename from openmc/cross.py rename to openmc/arithmetic.py diff --git a/openmc/tallies.py b/openmc/tallies.py index fb07532a0..3c4d99c73 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -12,7 +12,7 @@ import sys import numpy as np from openmc import Mesh, Filter, Trigger, Nuclide -from openmc.cross import * +from openmc.arithmetic import * from openmc.filter import _FILTER_TYPES import openmc.checkvalue as cv from openmc.clean_xml import *