mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Added Tally average aggregation operation to Python API
This commit is contained in:
parent
bc0b826249
commit
a6b3eaec9f
2 changed files with 160 additions and 9 deletions
|
|
@ -13,7 +13,7 @@ if sys.version_info[0] >= 3:
|
|||
basestring = str
|
||||
|
||||
# Acceptable tally aggregation operations
|
||||
_TALLY_AGGREGATE_OPS = ['sum', 'mean']
|
||||
_TALLY_AGGREGATE_OPS = ['sum', 'avg']
|
||||
|
||||
|
||||
class AggregateScore(object):
|
||||
|
|
@ -25,7 +25,7 @@ class AggregateScore(object):
|
|||
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
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
Attributes
|
||||
|
|
@ -33,7 +33,7 @@ class AggregateScore(object):
|
|||
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
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
"""
|
||||
|
|
@ -108,7 +108,7 @@ class AggregateNuclide(object):
|
|||
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
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
Attributes
|
||||
|
|
@ -116,7 +116,7 @@ class AggregateNuclide(object):
|
|||
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
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
"""
|
||||
|
|
@ -198,7 +198,7 @@ class AggregateFilter(object):
|
|||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'mean', etc.) used
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
|
||||
Attributes
|
||||
|
|
@ -208,7 +208,7 @@ class AggregateFilter(object):
|
|||
aggregate_filter : filter
|
||||
The filter included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'mean', etc.) used
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
|
|
|
|||
|
|
@ -2758,7 +2758,7 @@ class Tally(object):
|
|||
def summation(self, scores=[], filter_type=None,
|
||||
filter_bins=[], nuclides=[], remove_filter=False):
|
||||
"""Vectorized sum of tally data across scores, filter bins and/or
|
||||
nuclides using tally addition.
|
||||
nuclides using tally aggregation.
|
||||
|
||||
This method constructs a new tally to encapsulate the sum of the data
|
||||
represented by the summation of the data in this tally. The tally data
|
||||
|
|
@ -2800,7 +2800,7 @@ class Tally(object):
|
|||
tally_sum._derived = True
|
||||
tally_sum._estimator = self.estimator
|
||||
tally_sum._num_realizations = self.num_realizations
|
||||
tally_sum.with_batch_statistics = self.with_batch_statistics
|
||||
tally_sum._with_batch_statistics = self.with_batch_statistics
|
||||
tally_sum._with_summary = self.with_summary
|
||||
tally_sum._sp_filename = self._sp_filename
|
||||
tally_sum._results_read = self._results_read
|
||||
|
|
@ -2903,6 +2903,157 @@ class Tally(object):
|
|||
tally_sum.sparse = self.sparse
|
||||
return tally_sum
|
||||
|
||||
def average(self, scores=[], filter_type=None,
|
||||
filter_bins=[], nuclides=[], remove_filter=False):
|
||||
"""Vectorized average of tally data across scores, filter bins and/or
|
||||
nuclides using tally aggregation.
|
||||
|
||||
This method constructs a new tally to encapsulate the average of the
|
||||
data represented by the average of the data in this tally. The tally
|
||||
data average is determined by the scores, filter bins and nuclides
|
||||
specified in the input parameters.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scores : list of str
|
||||
A list of one or more score strings to average across
|
||||
(e.g., ['absorption', 'nu-fission']; default is [])
|
||||
filter_type : str
|
||||
A filter type string (e.g., 'cell', 'energy') corresponding to the
|
||||
filter bins to average across
|
||||
filter_bins : Iterable of Integral or tuple
|
||||
A list of the filter bins corresponding to the filter_type parameter
|
||||
Each bin in the list is the integer ID for 'material', 'surface',
|
||||
'cell', 'cellborn', and 'universe' Filters. Each bin is an integer
|
||||
for the cell instance ID for 'distribcell' Filters. Each bin is a
|
||||
2-tuple of floats for 'energy' and 'energyout' filters corresponding
|
||||
to the energy boundaries of the bin of interest. Each bin is an
|
||||
(x,y,z) 3-tuple for 'mesh' filters corresponding to the mesh cell of
|
||||
interest.
|
||||
nuclides : list of str
|
||||
A list of nuclide name strings to average across
|
||||
(e.g., ['U-235', 'U-238']; default is [])
|
||||
remove_filter : bool
|
||||
If a filter is being averaged over, this bool indicates whether to
|
||||
remove that filter in the returned tally. Default is False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tally
|
||||
A new tally which encapsulates the average of data requested.
|
||||
"""
|
||||
|
||||
# Create new derived Tally for average
|
||||
tally_avg = Tally()
|
||||
tally_avg._derived = True
|
||||
tally_avg._estimator = self.estimator
|
||||
tally_avg._num_realizations = self.num_realizations
|
||||
tally_avg._with_batch_statistics = self.with_batch_statistics
|
||||
tally_avg._with_summary = self.with_summary
|
||||
tally_avg._sp_filename = self._sp_filename
|
||||
tally_avg._results_read = self._results_read
|
||||
|
||||
# Get tally data arrays reshaped with one dimension per filter
|
||||
mean = self.get_reshaped_data(value='mean')
|
||||
std_dev = self.get_reshaped_data(value='std_dev')
|
||||
|
||||
# Average across any filter bins specified by the user
|
||||
if filter_type in _FILTER_TYPES:
|
||||
find_filter = self.find_filter(filter_type)
|
||||
|
||||
# If user did not specify filter bins, average across all bins
|
||||
if len(filter_bins) == 0:
|
||||
bin_indices = np.arange(find_filter.num_bins)
|
||||
|
||||
if filter_type == 'distribcell':
|
||||
filter_bins = np.arange(find_filter.num_bins)
|
||||
else:
|
||||
num_bins = find_filter.num_bins
|
||||
filter_bins = \
|
||||
[(find_filter.get_bin(i)) for i in range(num_bins)]
|
||||
|
||||
# Only average across bins specified by the user
|
||||
else:
|
||||
bin_indices = \
|
||||
[find_filter.get_bin_index(bin) for bin in filter_bins]
|
||||
|
||||
# Average across the bins in the user-specified filter
|
||||
for i, self_filter in enumerate(self.filters):
|
||||
if self_filter.type == filter_type:
|
||||
mean = np.take(mean, indices=bin_indices, axis=i)
|
||||
std_dev = np.take(std_dev, indices=bin_indices, axis=i)
|
||||
mean = np.mean(mean, axis=i, keepdims=True)
|
||||
std_dev = np.mean(std_dev**2, axis=i, keepdims=True)
|
||||
std_dev /= len(bin_indices)
|
||||
std_dev = np.sqrt(std_dev)
|
||||
|
||||
# Add AggregateFilter to the tally avg
|
||||
if not remove_filter:
|
||||
filter_sum = \
|
||||
AggregateFilter(self_filter, filter_bins, 'avg')
|
||||
tally_avg.add_filter(filter_sum)
|
||||
|
||||
# Add a copy of each filter not averaged across to the tally avg
|
||||
else:
|
||||
tally_avg.add_filter(copy.deepcopy(self_filter))
|
||||
|
||||
# Add a copy of this tally's filters to the tally avg
|
||||
else:
|
||||
tally_avg._filters = copy.deepcopy(self.filters)
|
||||
|
||||
# Sum across any nuclides specified by the user
|
||||
if len(nuclides) != 0:
|
||||
nuclide_bins = [self.get_nuclide_index(nuclide) for nuclide in nuclides]
|
||||
axis_index = self.num_filters
|
||||
mean = np.take(mean, indices=nuclide_bins, axis=axis_index)
|
||||
std_dev = np.take(std_dev, indices=nuclide_bins, axis=axis_index)
|
||||
mean = np.mean(mean, axis=axis_index, keepdims=True)
|
||||
std_dev = np.mean(std_dev**2, axis=axis_index, keepdims=True)
|
||||
std_dev /= len(nuclide_bins)
|
||||
std_dev = np.sqrt(std_dev)
|
||||
|
||||
# Add AggregateNuclide to the tally avg
|
||||
nuclide_avg = AggregateNuclide(nuclides, 'avg')
|
||||
tally_avg.add_nuclide(nuclide_avg)
|
||||
|
||||
# Add a copy of this tally's nuclides to the tally avg
|
||||
else:
|
||||
tally_avg._nuclides = copy.deepcopy(self.nuclides)
|
||||
|
||||
# Sum across any scores specified by the user
|
||||
if len(scores) != 0:
|
||||
score_bins = [self.get_score_index(score) for score in scores]
|
||||
axis_index = self.num_filters + 1
|
||||
mean = np.take(mean, indices=score_bins, axis=axis_index)
|
||||
std_dev = np.take(std_dev, indices=score_bins, axis=axis_index)
|
||||
mean = np.sum(mean, axis=axis_index, keepdims=True)
|
||||
std_dev = np.sum(std_dev**2, axis=axis_index, keepdims=True)
|
||||
std_dev /= len(score_bins)
|
||||
std_dev = np.sqrt(std_dev)
|
||||
|
||||
# Add AggregateScore to the tally avg
|
||||
score_sum = AggregateScore(scores, 'avg')
|
||||
tally_avg.add_score(score_sum)
|
||||
|
||||
# Add a copy of this tally's scores to the tally avg
|
||||
else:
|
||||
tally_avg._scores = copy.deepcopy(self.scores)
|
||||
|
||||
# Update the tally avg's filter strides
|
||||
tally_avg._update_filter_strides()
|
||||
|
||||
# Reshape condensed data arrays with one dimension for all filters
|
||||
mean = np.reshape(mean, tally_avg.shape)
|
||||
std_dev = np.reshape(std_dev, tally_avg.shape)
|
||||
|
||||
# Assign tally avg's data with the new arrays
|
||||
tally_avg._mean = mean
|
||||
tally_avg._std_dev = std_dev
|
||||
|
||||
# If original tally was sparse, sparsify the tally average
|
||||
tally_avg.sparse = self.sparse
|
||||
return tally_avg
|
||||
|
||||
def diagonalize_filter(self, new_filter):
|
||||
"""Diagonalize the tally data array along a new axis of filter bins.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue