Removed Tally.summation(...) routine in place of explicit tally summations in openmc.mgxs module for subdomain averaging

This commit is contained in:
Will Boyd 2015-09-26 17:12:03 -04:00
parent d0a85cd082
commit 02c30fd5de
3 changed files with 47 additions and 101 deletions

View file

@ -318,6 +318,7 @@ class Filter(object):
boolean
Whether or not the other filter is a subset of this filter
"""
if not isinstance(other, Filter):
return False
elif self.type != other.type:
@ -325,8 +326,8 @@ class Filter(object):
elif self.type in ['energy', 'energyout']:
return np.all(self.bins == other.bins)
for bin in other.bins:
if bin not in self.bins:
for bin in self.bins:
if bin not in other.bins:
return False
return True

View file

@ -403,7 +403,9 @@ class MultiGroupXS(object):
def get_subdomain_avg_xs(self, subdomains='all'):
"""Construct a subdomain-averaged version of this cross-section.
This is primarily useful for averaging across distribcell instances.
This is primarily useful for averaging across distribcell instances or
mesh cells. This routine performs spatial homogenization to compute the
scalar flux-weighted average cross-section across the subdomains.
Parameters
----------
@ -440,17 +442,49 @@ class MultiGroupXS(object):
# Clone this MultiGroupXS to initialize the subdomain-averaged version
avg_xs = copy.deepcopy(self)
# Reset subdomain indices and offsets for distribcell domains
# If domain is distribcell, make subdomain-averaged a 'cell' domain
if self.domain_type == 'distribcell':
avg_xs.domain_type = 'cell'
avg_xs._offset = 0
# TODO: Implement this for mesh tallies
elif self.domain_type == 'mesh':
raise NotImplementedError('Average mesh xs are not yet implemented')
# Overwrite tallies with new subdomain-averaged versions
avg_xs._tallies = {}
for tally_type, tally in self.tallies.items():
tally_sum = tally.summation(filter_type=self.domain_type,
filter_bins=subdomains)
tally_sum /= len(subdomains)
avg_xs.tallies[tally_type] = tally_sum
# Average each of the tallies across subdomains
for tally_type, tally in avg_xs.tallies.items():
# Make condensed tally derived and null out sum, sum_sq
tally._derived = True
tally._sum = None
tally._sum_sq = None
# Get tally data arrays reshaped with one dimension per filter
mean = tally.get_reshaped_data(value='mean')
std_dev = tally.get_reshaped_data(value='std_dev')
# Get the mean of the mean, std. dev. across requested subdomains
mean = np.mean(mean[subdomains, ...], axis=0)
std_dev = np.mean(std_dev[subdomains, ...]**2, axis=0)
std_dev = np.sqrt(std_dev)
# If domain is distribcell, make subdomain-averaged a 'cell' domain
domain_filter = tally.find_filter(self._domain_type)
if domain_filter.type == 'distribcell':
domain_filter.type = 'cell'
domain_filter.num_bins = 1
# TODO: Implement this for mesh tallies
elif domain_filter.type == 'mesh':
raise NotImplementedError('Average mesh xs are not yet implemented')
# Reshape averaged data arrays with one dimension for all filters
new_shape = \
(tally.num_filter_bins, tally.num_nuclides, tally.num_score_bins,)
mean = np.reshape(mean, new_shape)
std_dev = np.reshape(std_dev, new_shape)
# Override tally's data with the new condensed data
tally._mean = mean
tally._std_dev = std_dev
# Compute the subdomain-averaged multi-group cross-section
avg_xs.compute_xs()
@ -733,6 +767,7 @@ class MultiGroupXS(object):
df = self.get_pandas_dataframe()
# Capitalize column label strings
df.columns = df.columns.astype(str)
df.columns = map(str.title, df.columns)
# Export the data using Pandas IO API

View file

@ -2316,96 +2316,6 @@ class Tally(object):
return new_tally
def summation(self, scores=[], filter_type=None,
filter_bins=[], nuclides=[]):
"""Build a sliced tally for the specified filter bins, nuclides, scores.
This method constructs a new tally to encapsulate a subset of the data
represented by this tally. The subset of data to include in the tally
slice is determined by the scores, filter bins and nuclides specified
in the input parameters.
Parameters
----------
scores : list
A list of one or more score strings to sum 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 sum across
filter_bins : Iterable of Integral or tuple
A list of the filter bins corresponding to the filters 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
A list of nuclide name strings to sum across
(e.g., ['U-235', 'U-238']; default is [])
Returns
-------
Tally
A new tally which encapsulates the sum of data requested.
"""
# If user did not specify any scores, do not sum across scores
if len(scores) == 0:
scores = [[]]
# Sum across any scores specified by the user
else:
scores = [[score] for score in scores]
# If user did not specify any nuclides, do not sum across nuclides
if len(nuclides) == 0:
nuclides = [[]]
# Sum across any nuclides specified by the user
else:
nuclides = [[nuclide] for nuclide in nuclides]
# Sum across any filter bins specified by the user
if filter_type in FILTER_TYPES.values():
filter_bins = [[(filter_bin,)] for filter_bin in filter_bins]
filters = [[filter_type]]
# If user did not specify a filter type, do not sum across filter bins
else:
filter_bins = [[]]
filters = [[]]
# Initialize Tally sum
tally_sum = 0
# Iterate over all Tally slice operands in summation
prod = [scores, filters, filter_bins, nuclides]
summed_filters = defaultdict(list)
for scores, filters, filter_bins, nuclides in itertools.product(*prod):
tally_slice = self.get_slice(scores, filters, filter_bins, nuclides)
# Remove filters summed across to avoid bulky CrossFilters
if filter_type:
filter = tally_slice.find_filter(filter_type)
tally_slice.remove_filter(filter)
summed_filters[filter_type].append(filter)
# Accumulate this Tally slice into the Tally sum
tally_sum += tally_slice
# FIXME: test if this works for filter
for filter_type in summed_filters:
filters = summed_filters[filter_type]
for i in range(1, len(filters)):
filters[i] = CrossFilter(filters[i-1], filters[i], '+')
tally_sum.add_filter(filters[-1])
return tally_sum
def tile_filter(self, new_filter):
"""Combines filters, scores and nuclides with another tally.