Added ability to convert the isotropic or angle representation from one to the other for XSdata objects and MGXSLibrary objects

This commit is contained in:
Adam Nelson 2017-01-28 11:34:29 -05:00
parent 6e3f6bf8b1
commit 756a43f1c5
2 changed files with 194 additions and 4 deletions

View file

@ -205,7 +205,7 @@ class MGXS(object):
clone._name = self.name
clone._rxn_type = self.rxn_type
clone._by_nuclide = self.by_nuclide
clone._nuclides = copy.deepcopy(self._nuclides)
clone._nuclides = copy.deepcopy(self._nuclides, memo)
clone._domain = self.domain
clone._domain_type = self.domain_type
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)

View file

@ -1,4 +1,4 @@
from collections import Iterable
import copy
from numbers import Real, Integral
import os
@ -185,6 +185,52 @@ class XSdata(object):
self._inverse_velocity = len(temperatures) * [None]
self._xs_shapes = None
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy this object, copy it
if existing is None:
clone = type(self).__new__(type(self))
clone._name = self.name
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
clone._num_delayed_groups = self.num_delayed_groups
clone._temperatures = copy.deepcopy(self.temperatures, memo)
clone._drepresentation = self.representation
clone._atomic_weight_ratio = self._atomic_weight_ratio
clone._fissionable = self._fissionable
clone._scatter_format = self._scatter_format
clone._order = self._order
clone._num_polar = self._num_polar
clone._num_azimuthal = self._num_azimuthal
clone._total = copy.deepcopy(self._total, memo)
clone._absorption = copy.deepcopy(self._absorption, memo)
clone._scatter_matrix = copy.deepcopy(self._scatter_matrix, memo)
clone._multiplicity_matrix = \
copy.deepcopy(self._multiplicity_matrix, memo)
clone._fission = copy.deepcopy(self._fission, memo)
clone._nu_fission = copy.deepcopy(self._nu_fission, memo)
clone._prompt_nu_fission = \
copy.deepcopy(self._prompt_nu_fission, memo)
clone._delayed_nu_fission = \
copy.deepcopy(self._delayed_nu_fission, memo)
clone._kappa_fission = copy.deepcopy(self._kappa_fission, memo)
clone._chi = copy.deepcopy(self._chi, memo)
clone._chi_prompt = copy.deepcopy(self._chi_prompt, memo)
clone._chi_delayed = copy.deepcopy(self._chi_delayed, memo)
clone._beta = copy.deepcopy(self._beta, memo)
clone._decay_rate = copy.deepcopy(self._decay_rate, memo)
clone._inverse_velocity = \
copy.deepcopy(self._inverse_velocity, memo)
clone._xs_shapes = copy.deepcopy(self._xs_shapes, memo)
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
@property
def name(self):
return self._name
@ -348,7 +394,7 @@ class XSdata(object):
@representation.setter
def representation(self, representation):
# Check it is of valid type.
# Check it is of valid value.
check_value('representation', representation, _REPRESENTATIONS)
self._representation = representation
@ -1622,7 +1668,8 @@ class XSdata(object):
"""
check_type('inverse_velocity', inverse_velocity, openmc.mgxs.InverseVelocity)
check_type('inverse_velocity', inverse_velocity,
openmc.mgxs.InverseVelocity)
check_value('energy_groups', inverse_velocity.energy_groups,
[self.energy_groups])
check_value('domain_type', inverse_velocity.domain_type,
@ -1634,6 +1681,89 @@ class XSdata(object):
self._inverse_velocity[i] = inverse_velocity.get_xs(
nuclides=nuclide, xs_type=xs_type, subdomains=subdomain)
def convert_representation(self, target_representation, num_polar=None,
num_azimuthal=None):
"""Produce a new XSdata object with the same data, but converted to the
new representation
Parameters
----------
target_representation : {'isotropic', 'angle'}
Representation of the MGXS (isotropic or angle-dependent flux
weighting).
num_polar : int, optional
Number of equal width angular bins that the polar angular
domain is subdivided into. This is required when
:param:`target_representation` is "angle".
num_azimuthal : int, optional
Number of equal width angular bins that the azimuthal angular
domain is subdivided into. This is required when
:param:`target_representation` is "angle".
Returns
-------
openmc.XSdata
Multi-group cross section data with the same data as self, but
represented as specified in :param:`target_representation`.
"""
check_value('target_representation', target_representation,
_REPRESENTATIONS)
if target_representation == 'angle':
check_type('num_polar', num_polar, Integral)
check_type('num_azimuthal', num_azimuthal, Integral)
check_greater_than('num_polar', num_polar, 0)
check_greater_than('num_azimuthal', num_azimuthal, 0)
xsdata = copy.deepcopy(self)
if target_representation == self.representation:
# Check to make sure the num_polar and num_azimuthal values match
if target_representation == 'angle':
if num_polar != self.num_polar or num_azimuthal != self.num_azimuthal:
raise NotImplementedError("XSdata.convert_representation "
"cannot translate between "
"`angle` representations with "
"different angle bin structures")
# Nothing to do
return xsdata
types = ['total', 'absorption', 'fission', 'nu_fission',
'scatter_matrix', 'multiplicity_matrix', 'prompt_nu_fission',
'delayed_nu_fission', 'kappa_fission', 'chi', 'chi_prompt',
'chi_delayed', 'beta', 'decay_rate', 'inverse_velocity']
xsdata.representation = target_representation
# We have different actions depending on the representation conversion
if target_representation == 'isotropic':
xsdata.num_polar = None
xsdata.num_azimuthal = None
for i, temp in enumerate(xsdata.temperatures):
for xs in types:
# Get the original data
orig_data = getattr(self, '_' + xs)[i]
# Since we are going from angle to isotropic, the current
# data should be just averaged over the angle bins
new_data = orig_data.mean(axis=(0, 1))
setter = getattr(xsdata, 'set_' + xs)
setter(new_data, temp)
elif target_representation == 'angle':
xsdata.num_polar = num_polar
xsdata.num_azimuthal = num_azimuthal
for i, temp in enumerate(xsdata.temperatures):
for xs in types:
# Get the original data
orig_data = getattr(self, '_' + xs)[i]
# Since we are going from isotropic to angle, the current
# data should be just copied for every polar/azimuthal bin
new_shape = (num_polar, num_azimuthal) + orig_data.shape
new_data = np.resize(orig_data, new_shape)
setter = getattr(xsdata, 'set_' + xs)
setter(new_data, temp)
return xsdata
def to_hdf5(self, file):
"""Write XSdata to an HDF5 file
@ -1995,6 +2125,24 @@ class MGXSLibrary(object):
self.num_delayed_groups = num_delayed_groups
self._xsdatas = []
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy this object, copy it
if existing is None:
clone = type(self).__new__(type(self))
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
clone._num_delayed_groups = self.num_delayed_groups
clone._xsdatas = copy.deepcopy(self.xsdatas, memo)
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
@property
def energy_groups(self):
return self._energy_groups
@ -2099,6 +2247,48 @@ class MGXSLibrary(object):
result = xsdata
return result
def convert_representation(self, target_representation, num_polar=None,
num_azimuthal=None):
"""Produce a new MGXSLibrary object with the same data, but converted
to the new representation
Parameters
----------
target_representation : {'isotropic', 'angle'}
Representation of the MGXS (isotropic or angle-dependent flux
weighting).
num_polar : int, optional
Number of equal width angular bins that the polar angular
domain is subdivided into. This is required when
:param:`target_representation` is "angle".
num_azimuthal : int, optional
Number of equal width angular bins that the azimuthal angular
domain is subdivided into. This is required when
:param:`target_representation` is "angle".
Returns
-------
openmc.MGXSLibrary
Multi-group Library with the same data as self, but represented as
specified in :param:`target_representation`.
"""
check_value('target_representation', target_representation,
_REPRESENTATIONS)
if target_representation == 'angle':
check_type('num_polar', num_polar, Integral)
check_type('num_azimuthal', num_azimuthal, Integral)
check_greater_than('num_polar', num_polar, 0)
check_greater_than('num_azimuthal', num_azimuthal, 0)
library = copy.deepcopy(self)
for i, xsdata in enumerate(self.xsdatas):
library.xsdatas[i] = \
xsdata.convert_representation(target_representation,
num_polar, num_azimuthal)
return library
def export_to_hdf5(self, filename='mgxs.h5'):
"""Create an hdf5 file that can be used for a simulation.