Refactored MGXS computation as on-the-fly through xs_tally property

This commit is contained in:
wbinventor@gmail.com 2016-01-12 16:08:30 -05:00
parent 0efa01413f
commit 9be0ff54dd

View file

@ -89,13 +89,13 @@ class MGXS(object):
compute the cross section
tallies : OrderedDict
OpenMC tallies needed to compute the multi-group cross section
xs_tally : Tally
Derived tally for the multi-group cross section. This attribute
is None unless the multi-group cross section has been computed.
rxn_rate_tally : Tally
Derived tally for the reaction rate tally used in the numerator to
compute the multi-group cross section. This attribute is None
unless the multi-group cross section has been computed.
xs_tally : Tally
Derived tally for the multi-group cross section. This attribute
is None unless the multi-group cross section has been computed.
num_subdomains : Integral
The number of subdomains is unity for 'material', 'cell' and 'universe'
domain types. When the This is equal to the number of cell instances
@ -127,8 +127,8 @@ class MGXS(object):
self._energy_groups = None
self._tally_trigger = None
self._tallies = None
self._xs_tally = None
self._rxn_rate_tally = None
self._xs_tally = None
self._sparse = False
self.name = name
@ -154,8 +154,8 @@ class MGXS(object):
clone._domain_type = self.domain_type
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo)
clone._xs_tally = copy.deepcopy(self.xs_tally, memo)
clone._rxn_rate_tally = copy.deepcopy(self.rxn_rate_tally, memo)
clone._rxn_rate_tally = copy.deepcopy(self._rxn_rate_tally, memo)
clone._xs_tally = copy.deepcopy(self._xs_tally, memo)
clone._sparse = self.sparse
clone._tallies = OrderedDict()
@ -206,14 +206,25 @@ class MGXS(object):
def tallies(self):
return self._tallies
@property
def xs_tally(self):
return self._xs_tally
@property
def rxn_rate_tally(self):
return self._rxn_rate_tally
@property
def xs_tally(self):
"""Computes multi-group cross section using OpenMC tally arithmetic."""
if self._xs_tally is None:
if self.tallies is None:
msg = 'Unable to get xs_tally since tallies have ' \
'not been loaded from a statepoint'
raise ValueError(msg)
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
self._compute_xs()
return self._xs_tally
@property
def sparse(self):
return self._sparse
@ -283,9 +294,9 @@ class MGXS(object):
cv.check_type('sparse', sparse, bool)
# Sparsify or densify the derived MGXS tallies and the base tallies
if self.xs_tally:
if self._xs_tally:
self.xs_tally.sparse = sparse
if self.rxn_rate_tally:
if self._rxn_rate_tally:
self.rxn_rate_tally.sparse = sparse
for tally_name in self.tallies:
@ -521,8 +532,7 @@ class MGXS(object):
else:
self.tallies[key].add_nuclide('total')
@abc.abstractmethod
def compute_xs(self):
def _compute_xs(self):
"""Performs generic cleanup after a subclass' uses tally arithmetic to
compute a multi-group cross section as a derived tally.
@ -613,9 +623,6 @@ class MGXS(object):
sp_tally.sparse = self.sparse
self.tallies[tally_type] = sp_tally
# Compute the cross section from the tallies
self.compute_xs()
def get_xs(self, groups='all', subdomains='all', nuclides='all',
xs_type='macro', order_groups='increasing', value='mean'):
"""Returns an array of multi-group cross sections.
@ -659,10 +666,6 @@ class MGXS(object):
"""
if self.xs_tally is None:
msg = 'Unable to get cross section since it has not been computed'
raise ValueError(msg)
cv.check_value('value', value, ['mean', 'std_dev', 'rel_err'])
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
@ -747,11 +750,6 @@ class MGXS(object):
"""
if self.xs_tally is None:
msg = 'Unable to get a condensed coarse group cross section ' \
'since the fine group cross section has not been computed'
raise ValueError(msg)
cv.check_type('coarse_groups', coarse_groups, EnergyGroups)
cv.check_less_than('coarse groups', coarse_groups.num_groups,
self.num_groups, equality=True)
@ -762,8 +760,10 @@ class MGXS(object):
# Clone this MGXS to initialize the condensed version
condensed_xs = copy.deepcopy(self)
condensed_xs.sparse = False
condensed_xs.energy_groups = coarse_groups
condensed_xs._rxn_rate_tally = None
condensed_xs._xs_tally = None
condensed_xs._sparse = False
condensed_xs._energy_groups = coarse_groups
# Build energy indices to sum across
energy_indices = []
@ -809,7 +809,6 @@ class MGXS(object):
tally._std_dev = std_dev
# Compute the energy condensed multi-group cross section
condensed_xs.compute_xs()
condensed_xs.sparse = self.sparse
return condensed_xs
@ -838,11 +837,6 @@ class MGXS(object):
"""
if self.xs_tally is None:
msg = 'Unable to get subdomain-averaged cross section since the ' \
'subdomain-distributed cross section has not been computed'
raise ValueError(msg)
# Construct a collection of the subdomain filter bins to average across
if subdomains != 'all':
cv.check_iterable_type('subdomains', subdomains, Integral)
@ -853,7 +847,9 @@ class MGXS(object):
# Clone this MGXS to initialize the subdomain-averaged version
avg_xs = copy.deepcopy(self)
avg_xs.sparse = False
avg_xs._rxn_rate_tally = None
avg_xs._xs_tally = None
avg_xs._sparse = False
# If domain is distribcell, make the new domain 'cell'
if self.domain_type == 'distribcell':
@ -891,7 +887,6 @@ class MGXS(object):
tally._std_dev = std_dev
# Compute the subdomain-averaged multi-group cross section
avg_xs.compute_xs()
avg_xs.sparse = self.sparse
return avg_xs
@ -943,7 +938,7 @@ class MGXS(object):
string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id)
# If cross section data has not been computed, only print string header
if self.xs_tally is None:
if self.tallies is None:
print(string)
return
@ -1030,11 +1025,6 @@ class MGXS(object):
"""
if self.xs_tally is None:
msg = 'Unable to get build HDF5 store since the ' \
'cross section has not been computed'
raise ValueError(msg)
import h5py
# Make directory if it does not exist
@ -1232,11 +1222,6 @@ class MGXS(object):
"""
if self.xs_tally is None:
msg = 'Unable to get Pandas DataFrame since the ' \
'cross section has not been computed'
raise ValueError(msg)
if groups != 'all':
cv.check_iterable_type('groups', groups, Integral)
if nuclides != 'all' and nuclides != 'sum':
@ -1357,14 +1342,12 @@ class TotalXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group total cross sections using OpenMC
tally arithmetic.
"""
self._rxn_rate_tally = self.tallies['total']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(TotalXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['total']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class TransportXS(MGXS):
@ -1405,18 +1388,21 @@ class TransportXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group transport cross sections using OpenMC
tally arithmetic."""
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
scatter_p1 = copy.deepcopy(self.tallies['scatter-P1'])
# Use tally slicing to remove scatter-P0 data from scatter-P1 tally
scatter_p1 = self.tallies['scatter-P1']
self.tallies['scatter-P1'] = scatter_p1.get_slice(scores=['scatter-P1'])
self.tallies['scatter-P1'].filters[-1].type = 'energy'
# Use tally slicing to remove scatter-P0 data from scatter-P1 tally
self.tallies['scatter-P1'] = \
scatter_p1.get_slice(scores=['scatter-P1'])
self._rxn_rate_tally = self.tallies['total'] - self.tallies['scatter-P1']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(TransportXS, self).compute_xs()
self.tallies['scatter-P1'].filters[-1].type = 'energy'
self._rxn_rate_tally = \
self.tallies['total'] - self.tallies['scatter-P1']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class AbsorptionXS(MGXS):
@ -1456,13 +1442,12 @@ class AbsorptionXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group absorption cross sections using OpenMC
tally arithmetic."""
self._rxn_rate_tally = self.tallies['absorption']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(AbsorptionXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['absorption']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class CaptureXS(MGXS):
@ -1509,13 +1494,13 @@ class CaptureXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group capture cross sections using OpenMC
tally arithmetic."""
self._rxn_rate_tally = self.tallies['absorption'] - self.tallies['fission']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(CaptureXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = \
self.tallies['absorption'] - self.tallies['fission']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class FissionXS(MGXS):
@ -1555,13 +1540,12 @@ class FissionXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group fission cross sections using OpenMC
tally arithmetic."""
self._rxn_rate_tally = self.tallies['fission']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(FissionXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['fission']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class NuFissionXS(MGXS):
@ -1601,13 +1585,12 @@ class NuFissionXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the multi-group nu-fission cross sections using OpenMC
tally arithmetic."""
self._rxn_rate_tally = self.tallies['nu-fission']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(NuFissionXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['nu-fission']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class ScatterXS(MGXS):
@ -1647,13 +1630,12 @@ class ScatterXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the scattering multi-group cross sections using
OpenMC tally arithmetic."""
self._rxn_rate_tally = self.tallies['scatter']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(ScatterXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['scatter']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class NuScatterXS(MGXS):
@ -1693,13 +1675,12 @@ class NuScatterXS(MGXS):
return self._tallies
def compute_xs(self):
"""Computes the nu-scattering multi-group cross section using OpenMC
tally arithmetic."""
self._rxn_rate_tally = self.tallies['nu-scatter']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(NuScatterXS, self).compute_xs()
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['nu-scatter']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
class ScatterMatrixXS(MGXS):
@ -1766,23 +1747,22 @@ class ScatterMatrixXS(MGXS):
cv.check_value('correction', correction, ('P0', None))
self._correction = correction
def compute_xs(self):
"""Computes the multi-group scattering matrix using OpenMC
tally arithmetic."""
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
# If using P0 correction subtract scatter-P1 from the diagonal
if self.correction == 'P0':
scatter_p1 = self.tallies['scatter-P1']
scatter_p1 = scatter_p1.get_slice(scores=['scatter-P1'])
energy_filter = self.tallies['scatter'].find_filter('energy')
energy_filter = copy.deepcopy(energy_filter)
scatter_p1 = scatter_p1.diagonalize_filter(energy_filter)
self._rxn_rate_tally = self.tallies['scatter'] - scatter_p1
else:
self._rxn_rate_tally = self.tallies['scatter']
self._rxn_rate_tally.sparse = self.sparse
# If using P0 correction subtract scatter-P1 from the diagonal
if self.correction == 'P0':
scatter_p1 = self.tallies['scatter-P1']
scatter_p1 = scatter_p1.get_slice(scores=['scatter-P1'])
energy_filter = self.tallies['scatter'].find_filter('energy')
energy_filter = copy.deepcopy(energy_filter)
scatter_p1 = scatter_p1.diagonalize_filter(energy_filter)
self._rxn_rate_tally = self.tallies['scatter'] - scatter_p1
else:
self._rxn_rate_tally = self.tallies['scatter']
self._xs_tally = self.rxn_rate_tally / self.tallies['flux']
super(ScatterMatrixXS, self).compute_xs()
return self._rxn_rate_tally
def get_xs(self, in_groups='all', out_groups='all',
subdomains='all', nuclides='all', xs_type='macro',
@ -1830,10 +1810,6 @@ class ScatterMatrixXS(MGXS):
"""
if self.xs_tally is None:
msg = 'Unable to get cross section since it has not been computed'
raise ValueError(msg)
cv.check_value('value', value, ['mean', 'std_dev', 'rel_err'])
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
@ -1966,7 +1942,7 @@ class ScatterMatrixXS(MGXS):
string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id)
# If cross section data has not been computed, only print string header
if self.xs_tally is None:
if self.tallies is None:
print(string)
return
@ -2110,25 +2086,32 @@ class Chi(MGXS):
return self._tallies
def compute_xs(self):
@property
def rxn_rate_tally(self):
if self._rxn_rate_tally is None:
self._rxn_rate_tally = self.tallies['nu-fission-out']
self._rxn_rate_tally.sparse = self.sparse
return self._rxn_rate_tally
@property
def xs_tally(self):
"""Computes chi fission spectrum using OpenMC tally arithmetic."""
# Retrieve the fission production tallies
nu_fission_in = self.tallies['nu-fission-in']
nu_fission_out = self.tallies['nu-fission-out']
if self._xs_tally is None:
nu_fission_in = self.tallies['nu-fission-in']
# Remove coarse energy filter to keep it out of tally arithmetic
energy_filter = nu_fission_in.find_filter('energy')
nu_fission_in.remove_filter(energy_filter)
# Remove coarse energy filter to keep it out of tally arithmetic
energy_filter = nu_fission_in.find_filter('energy')
nu_fission_in.remove_filter(energy_filter)
# Compute chi
self._rxn_rate_tally = nu_fission_out
self._xs_tally = self.rxn_rate_tally / nu_fission_in
# Compute chi
self._xs_tally = self.rxn_rate_tally / nu_fission_in
super(Chi, self)._compute_xs()
# Add the coarse energy filter back to the nu-fission tally
nu_fission_in.add_filter(energy_filter)
# Add the coarse energy filter back to the nu-fission tally
nu_fission_in.add_filter(energy_filter)
super(Chi, self).compute_xs()
return self._xs_tally
def get_xs(self, groups='all', subdomains='all', nuclides='all',
xs_type='macro', order_groups='increasing', value='mean'):
@ -2173,10 +2156,6 @@ class Chi(MGXS):
"""
if self.xs_tally is None:
msg = 'Unable to get cross section since it has not been computed'
raise ValueError(msg)
cv.check_value('value', value, ['mean', 'std_dev', 'rel_err'])
cv.check_value('xs_type', xs_type, ['macro', 'micro'])