mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Simplifications as per comments from @wbinventor and @paulromano. Next is updating notebook
This commit is contained in:
parent
3079b5f6df
commit
98a02d5d50
2 changed files with 620 additions and 423 deletions
|
|
@ -15,14 +15,9 @@ import openmc.checkvalue as cv
|
|||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# The following represent the most accurate MGXS generation strategy
|
||||
# for use in the MG mode of OpenMC.
|
||||
OPENMC_MG_MGXS_TYPES = ['transport', 'absorption', 'nu-fission', 'chi',
|
||||
'scatter matrix', 'nu-scatter matrix']
|
||||
|
||||
|
||||
class Library(object):
|
||||
"""A multi-group cross section library for some energy group structure.
|
||||
'''A multi-group cross section library for some energy group structure.
|
||||
|
||||
This class can be used for both OpenMC input generation and tally data
|
||||
post-processing to compute spatially-homogenized and energy-integrated
|
||||
|
|
@ -84,7 +79,7 @@ class Library(object):
|
|||
Whether or not the Library's tallies use SciPy's LIL sparse matrix
|
||||
format for compressed data storage
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
def __init__(self, openmc_geometry, by_nuclide=False,
|
||||
mgxs_types=None, name=''):
|
||||
|
|
@ -252,7 +247,8 @@ class Library(object):
|
|||
|
||||
@domain_type.setter
|
||||
def domain_type(self, domain_type):
|
||||
cv.check_value('domain type', domain_type, tuple(openmc.mgxs.DOMAIN_TYPES))
|
||||
cv.check_value('domain type', domain_type,
|
||||
tuple(openmc.mgxs.DOMAIN_TYPES))
|
||||
self._domain_type = domain_type
|
||||
|
||||
@domains.setter
|
||||
|
|
@ -304,7 +300,7 @@ class Library(object):
|
|||
|
||||
@sparse.setter
|
||||
def sparse(self, sparse):
|
||||
"""Convert tally data from NumPy arrays to SciPy list of lists (LIL)
|
||||
'''Convert tally data from NumPy arrays to SciPy list of lists (LIL)
|
||||
sparse matrices, and vice versa.
|
||||
|
||||
This property may be used to reduce the amount of data in memory during
|
||||
|
|
@ -312,7 +308,7 @@ class Library(object):
|
|||
matrices internally within the Tally object. All tally data access
|
||||
properties and methods will return data as a dense NumPy array.
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
cv.check_type('sparse', sparse, bool)
|
||||
|
||||
|
|
@ -325,14 +321,14 @@ class Library(object):
|
|||
self._sparse = sparse
|
||||
|
||||
def build_library(self):
|
||||
"""Initialize MGXS objects in each domain and for each reaction type
|
||||
'''Initialize MGXS objects in each domain and for each reaction type
|
||||
in the library.
|
||||
|
||||
This routine will populate the all_mgxs instance attribute dictionary
|
||||
with MGXS subclass objects keyed by each domain ID (e.g., Material IDs)
|
||||
and cross section type (e.g., 'nu-fission', 'total', etc.).
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
# Initialize MGXS for each domain and mgxs type and store in dictionary
|
||||
for domain in self.domains:
|
||||
|
|
@ -355,7 +351,7 @@ class Library(object):
|
|||
self.all_mgxs[domain.id][mgxs_type] = mgxs
|
||||
|
||||
def add_to_tallies_file(self, tallies_file, merge=True):
|
||||
"""Add all tallies from all MGXS objects to a tallies file.
|
||||
'''Add all tallies from all MGXS objects to a tallies file.
|
||||
|
||||
NOTE: This assumes that :meth:`Library.build_library` has been called
|
||||
|
||||
|
|
@ -363,12 +359,12 @@ class Library(object):
|
|||
----------
|
||||
tallies_file : openmc.Tallies
|
||||
A Tallies collection to add each MGXS' tallies to generate a
|
||||
"tallies.xml" input file for OpenMC
|
||||
'tallies.xml' input file for OpenMC
|
||||
merge : bool
|
||||
Indicate whether tallies should be merged when possible. Defaults
|
||||
to True.
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
cv.check_type('tallies_file', tallies_file, openmc.Tallies)
|
||||
|
||||
|
|
@ -380,7 +376,7 @@ class Library(object):
|
|||
tallies_file.append(tally, merge=merge)
|
||||
|
||||
def load_from_statepoint(self, statepoint):
|
||||
"""Extracts tallies in an OpenMC StatePoint with the data needed to
|
||||
'''Extracts tallies in an OpenMC StatePoint with the data needed to
|
||||
compute multi-group cross sections.
|
||||
|
||||
This method is needed to compute cross section data from tallies
|
||||
|
|
@ -399,7 +395,7 @@ class Library(object):
|
|||
When this method is called with a statepoint that has not been
|
||||
linked with a summary object.
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
cv.check_type('statepoint', statepoint, openmc.StatePoint)
|
||||
|
||||
|
|
@ -423,7 +419,7 @@ class Library(object):
|
|||
mgxs.sparse = self.sparse
|
||||
|
||||
def get_mgxs(self, domain, mgxs_type):
|
||||
"""Return the MGXS object for some domain and reaction rate type.
|
||||
'''Return the MGXS object for some domain and reaction rate type.
|
||||
|
||||
This routine searches the library for an MGXS object for the spatial
|
||||
domain and reaction rate type requested by the user.
|
||||
|
|
@ -448,7 +444,7 @@ class Library(object):
|
|||
If no MGXS object can be found for the requested domain or
|
||||
multi-group cross section type
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
if self.domain_type == 'material':
|
||||
cv.check_type('domain', domain, (openmc.Material, Integral))
|
||||
|
|
@ -464,7 +460,7 @@ class Library(object):
|
|||
if domain_id == domain.id:
|
||||
break
|
||||
else:
|
||||
msg = 'Unable to find MGXS for {0} "{1}" in ' \
|
||||
msg = 'Unable to find MGXS for "{0}" "{1}" in ' \
|
||||
'library'.format(self.domain_type, domain_id)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
|
|
@ -478,7 +474,7 @@ class Library(object):
|
|||
return self.all_mgxs[domain_id][mgxs_type]
|
||||
|
||||
def get_condensed_library(self, coarse_groups):
|
||||
"""Construct an energy-condensed version of this library.
|
||||
'''Construct an energy-condensed version of this library.
|
||||
|
||||
This routine condenses each of the multi-group cross sections in the
|
||||
library to a coarse energy group structure. NOTE: This routine must
|
||||
|
|
@ -505,7 +501,7 @@ class Library(object):
|
|||
--------
|
||||
MGXS.get_condensed_xs(coarse_groups)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
if self.sp_filename is None:
|
||||
msg = 'Unable to get a condensed coarse group cross section ' \
|
||||
|
|
@ -534,7 +530,7 @@ class Library(object):
|
|||
return condensed_library
|
||||
|
||||
def get_subdomain_avg_library(self):
|
||||
"""Construct a subdomain-averaged version of this library.
|
||||
'''Construct a subdomain-averaged version of this library.
|
||||
|
||||
This routine averages each multi-group cross section across distribcell
|
||||
instances. The method performs spatial homogenization to compute the
|
||||
|
|
@ -557,7 +553,7 @@ class Library(object):
|
|||
--------
|
||||
MGXS.get_subdomain_avg_xs(subdomains)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
if self.sp_filename is None:
|
||||
msg = 'Unable to get a subdomain-averaged cross section ' \
|
||||
|
|
@ -585,7 +581,7 @@ class Library(object):
|
|||
def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs',
|
||||
subdomains='all', nuclides='all', xs_type='macro',
|
||||
row_column='inout'):
|
||||
"""Export the multi-group cross section library to an HDF5 binary file.
|
||||
'''Export the multi-group cross section library to an HDF5 binary file.
|
||||
|
||||
This method constructs an HDF5 file which stores the library's
|
||||
multi-group cross section data. The data is stored in a hierarchy of
|
||||
|
|
@ -628,7 +624,7 @@ class Library(object):
|
|||
--------
|
||||
MGXS.build_hdf5_store(filename, directory, xs_type)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
if self.sp_filename is None:
|
||||
msg = 'Unable to export multi-group cross section library ' \
|
||||
|
|
@ -648,7 +644,7 @@ class Library(object):
|
|||
full_filename = os.path.join(directory, filename)
|
||||
full_filename = full_filename.replace(' ', '-')
|
||||
f = h5py.File(full_filename, 'w')
|
||||
f.attrs["# groups"] = self.num_groups
|
||||
f.attrs['# groups'] = self.num_groups
|
||||
f.close()
|
||||
|
||||
# Export MGXS for each domain and mgxs type to an HDF5 file
|
||||
|
|
@ -663,7 +659,7 @@ class Library(object):
|
|||
nuclides=nuclides, row_column=row_column)
|
||||
|
||||
def dump_to_file(self, filename='mgxs', directory='mgxs'):
|
||||
"""Store this Library object in a pickle binary file.
|
||||
'''Store this Library object in a pickle binary file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -676,7 +672,7 @@ class Library(object):
|
|||
--------
|
||||
Library.load_from_file(filename, directory)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
|
|
@ -693,7 +689,7 @@ class Library(object):
|
|||
|
||||
@staticmethod
|
||||
def load_from_file(filename='mgxs', directory='mgxs'):
|
||||
"""Load a Library object from a pickle binary file.
|
||||
'''Load a Library object from a pickle binary file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -711,7 +707,7 @@ class Library(object):
|
|||
--------
|
||||
Library.dump_to_file(mgxs_lib, filename, directory)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
|
|
@ -729,7 +725,7 @@ class Library(object):
|
|||
def write_mg_library(self, xs_type='macro', domain_names=None, xs_ids=None,
|
||||
filename='mg_cross_sections', directory='./',
|
||||
return_names=True):
|
||||
"""Creates a cross-section data library file for the Multi-Group
|
||||
'''Creates a cross-section data library file for the Multi-Group
|
||||
mode of OpenMC.
|
||||
|
||||
Parameters
|
||||
|
|
@ -740,11 +736,11 @@ class Library(object):
|
|||
nuclide this will be set to 'macro' regardless.
|
||||
domain_names : Iterable of str
|
||||
List of names to apply to the xsdata entries in the
|
||||
resultant mgxs data file. Defaults to "set1", "set2", ...
|
||||
resultant mgxs data file. Defaults to 'set1', 'set2', ...
|
||||
xs_ids : str or Iterable of str
|
||||
Cross section set identifier (i.e., "71c") for all
|
||||
Cross section set identifier (i.e., '71c') for all
|
||||
data sets (if only str) or for each individual one
|
||||
(if iterable of str). Defaults to '1g'
|
||||
(if iterable of str). Defaults to '1m'.
|
||||
filename : str
|
||||
Filename for the pickle file. Defaults to 'mg_cross_sections'.
|
||||
directory : str
|
||||
|
|
@ -772,7 +768,11 @@ class Library(object):
|
|||
--------
|
||||
Library.dump_to_file(mgxs_lib, filename, directory)
|
||||
|
||||
"""
|
||||
'''
|
||||
|
||||
# Check to ensure the Library contains the correct
|
||||
# multi-group cross section types
|
||||
self.check_library_for_openmc_mgxs()
|
||||
|
||||
# Check the provided parameters
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
|
|
@ -786,14 +786,18 @@ class Library(object):
|
|||
else:
|
||||
cv.check_iterable_type('xs_ids', xs_ids, basestring)
|
||||
else:
|
||||
xs_ids = ['1g' for i in range(len(self.domains))]
|
||||
xs_ids = ['1m' for i in range(len(self.domains))]
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
|
||||
# Make sure statepoint has been loaded
|
||||
if self._sp_filename is None:
|
||||
msg = 'A StatePoint must be loaded before calling ' \
|
||||
'the write_mg_library() function'
|
||||
raise ValueError(msg)
|
||||
|
||||
# Construct the collection of the nuclides to report
|
||||
if self.by_nuclide:
|
||||
nuclides = self.all_mgxs[1][self.mgxs_types[-1]].get_all_nuclides()
|
||||
else:
|
||||
if not self.by_nuclide:
|
||||
xs_type = 'macro'
|
||||
|
||||
# Make directory if it does not exist and build our filename
|
||||
|
|
@ -813,213 +817,98 @@ class Library(object):
|
|||
xsdatas = []
|
||||
|
||||
mat_names = {}
|
||||
for i in range(len(self.domains)):
|
||||
for i, domain in enumerate(self.domains):
|
||||
|
||||
id = self.domains[i].id
|
||||
if not self.by_nuclide:
|
||||
mat_names[domain.id] = {}
|
||||
if self.by_nuclide:
|
||||
nuclides = list(domain.get_all_nuclides().keys())
|
||||
else:
|
||||
nuclides = ['total']
|
||||
for nuclide in nuclides:
|
||||
# Build & add metadata to XSdata object
|
||||
# (Use i here because k in nuclides will add chars to this)
|
||||
if domain_names is None:
|
||||
name = 'set' + str(i + 1)
|
||||
else:
|
||||
name = domain_names[i]
|
||||
if nuclide is not 'total':
|
||||
name += '_' + nuclide
|
||||
name += '.' + xs_ids[i]
|
||||
|
||||
# Store the name
|
||||
mat_names[domain.id][nuclide] = name
|
||||
|
||||
xsdata = openmc.XSdata(name, self.energy_groups)
|
||||
xsdata.order = order
|
||||
if nuclide is not 'total':
|
||||
xsdata.zaid = self._nuclides[nuclide][0]
|
||||
xsdata.awr = self._nuclides[nuclide][1]
|
||||
|
||||
mat_names[id] = name
|
||||
|
||||
nuclide = [nuclide]
|
||||
# Now get xs data itself
|
||||
if 'transport' in self.mgxs_types:
|
||||
if self.correction == 'P0':
|
||||
xsdata.set_total(self.all_mgxs[id]['transport'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
else:
|
||||
msg = "The use of a transport cross section " + \
|
||||
"requires the correction attribute to be" + \
|
||||
"set to 'P0' to produce valid cross " + \
|
||||
"section libraries"
|
||||
raise ValueError(msg)
|
||||
mymgxs = self.get_mgxs(domain, 'transport')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
elif 'total' in self.mgxs_types:
|
||||
xsdata.set_total(self.all_mgxs[id]['total'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'total')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'absorption' in self.mgxs_types:
|
||||
xsdata.set_absorption(self.all_mgxs[id]['absorption'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'absorption')
|
||||
xsdata.set_absorption_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'fission' in self.mgxs_types:
|
||||
xsdata.set_fission(self.all_mgxs[id]['fission'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'fission')
|
||||
xsdata.set_fission_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'kappa-fission' in self.mgxs_types:
|
||||
xsdata.set_k_fission(self.all_mgxs[id]['kappa-fission'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'kappa-fission')
|
||||
xsdata.set_kappa_fission_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'chi' in self.mgxs_types:
|
||||
xsdata.set_chi(self.all_mgxs[id]['chi'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'chi')
|
||||
xsdata.set_chi_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'nu-fission' in self.mgxs_types:
|
||||
xsdata.set_nu_fission(self.all_mgxs[id]['nu-fission'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,))
|
||||
mymgxs = self.get_mgxs(domain, 'nu-fission')
|
||||
xsdata.set_nu_fission_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
# multiplicity requires scatter and nu-scatter
|
||||
if ((('scatter matrix' in self.mgxs_types) and
|
||||
('nu-scatter matrix' in self.mgxs_types))):
|
||||
xsdata.set_multiplicity(
|
||||
self.all_mgxs[id]['nu-scatter matrix'],
|
||||
self.all_mgxs[id]['scatter matrix'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
xsdata.multiplicity = np.nan_to_num(xsdata.multiplicity)
|
||||
scatt_mgxs = self.get_mgxs(domain,
|
||||
'scatter matrix')
|
||||
nuscatt_mgxs = self.get_mgxs(domain,
|
||||
'nu-scatter matrix')
|
||||
xsdata.set_multiplicity_mgxs(nuscatt_mgxs, scatt_mgxs,
|
||||
xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
using_multiplicity = True
|
||||
else:
|
||||
using_multiplicity = False
|
||||
|
||||
if using_multiplicity:
|
||||
xsdata.set_scatter(self.all_mgxs[id]['nu-scatter matrix'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,))
|
||||
nuscatt_mgxs = self.get_mgxs(domain,
|
||||
'nu-scatter matrix')
|
||||
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
else:
|
||||
if 'nu-scatter matrix' in self.mgxs_types:
|
||||
xsdata.set_scatter(
|
||||
self.all_mgxs[id]['nu-scatter matrix'],
|
||||
xs_type=xs_type, subdomains=(id,))
|
||||
nuscatt_mgxs = self.get_mgxs(domain,
|
||||
'nu-scatter matrix')
|
||||
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
|
||||
# Since we are not using multiplicity, then
|
||||
# scattering multiplication (nu-scatter) must be
|
||||
# accounted for approximately by using an adjusted
|
||||
# absorption cross section.
|
||||
# We can not do this with a transport x/s so check
|
||||
# for that.
|
||||
if 'total' in self.mgxs_types:
|
||||
xsdata.absorption = \
|
||||
np.subtract(xsdata.total,
|
||||
np.sum(xsdata.scatter[0, :, :],
|
||||
axis=1))
|
||||
else:
|
||||
msg = "Absorption cross section must be " + \
|
||||
"provided if using a transport cross" + \
|
||||
" section and while not providing a " + \
|
||||
"scattering matrix"
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
msg = "No nu-scatter matrix data was provided. " + \
|
||||
"This means neutron balance cannot be " + \
|
||||
"achieved since (n,xn) multiplication is " + \
|
||||
"ignored."
|
||||
warn(msg)
|
||||
xsdata.set_scatter(self.all_mgxs[id]['scatter matrix'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,))
|
||||
|
||||
xsdatas.append(xsdata)
|
||||
else:
|
||||
mat_names[id] = {}
|
||||
for nuclide in nuclides:
|
||||
# Build & add metadata to XSdata object
|
||||
if domain_names is None:
|
||||
name = 'set' + str(i + 1)
|
||||
else:
|
||||
name = domain_names[i]
|
||||
name += '_' + nuclide
|
||||
name += '.' + xs_ids[i]
|
||||
|
||||
mat_names[id][nuclide] = name
|
||||
|
||||
xsdata = openmc.XSdata(name, self.energy_groups)
|
||||
xsdata.order = order
|
||||
xsdata.zaid = self._nuclides[nuclide][0]
|
||||
xsdata.awr = self._nuclides[nuclide][1]
|
||||
|
||||
# Now get xs data itself
|
||||
if 'transport' in self.mgxs_types:
|
||||
if self.correction == 'P0':
|
||||
xsdata.set_total(self.all_mgxs[id]['transport'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
else:
|
||||
msg = "The use of a transport cross section " + \
|
||||
"requires the correction attribute to be" + \
|
||||
"set to 'P0' to produce valid cross " + \
|
||||
"section libraries"
|
||||
raise ValueError(msg)
|
||||
elif 'total' in self.mgxs_types:
|
||||
xsdata.set_total(self.all_mgxs[id]['total'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
if 'absorption' in self.mgxs_types:
|
||||
xsdata.set_absorption(self.all_mgxs[id]['absorption'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
if 'fission' in self.mgxs_types:
|
||||
xsdata.set_fission(self.all_mgxs[id]['fission'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
if 'kappa-fission' in self.mgxs_types:
|
||||
xsdata.set_k_fission(
|
||||
self.all_mgxs[id]['kappa-fission'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
if 'chi' in self.mgxs_types:
|
||||
xsdata.set_chi(self.all_mgxs[id]['chi'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
if 'nu-fission' in self.mgxs_types:
|
||||
xsdata.set_nu_fission(self.all_mgxs[id]['nu-fission'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
# multiplicity requires scatter and nu-scatter
|
||||
if ((('scatter matrix' in self.mgxs_types) and
|
||||
('nu-scatter matrix' in self.mgxs_types))):
|
||||
xsdata.set_multiplicity(
|
||||
self.all_mgxs[id]['nu-scatter matrix'],
|
||||
self.all_mgxs[id]['scatter matrix'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
xsdata.multiplicity = \
|
||||
np.nan_to_num(xsdata.multiplicity)
|
||||
using_multiplicity = True
|
||||
else:
|
||||
using_multiplicity = False
|
||||
|
||||
if using_multiplicity:
|
||||
xsdata.set_scatter(
|
||||
self.all_mgxs[id]['nu-scatter matrix'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
else:
|
||||
if 'nu-scatter matrix' in self.mgxs_types:
|
||||
xsdata.set_scatter(
|
||||
self.all_mgxs[id]['nu-scatter matrix'],
|
||||
xs_type=xs_type, subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
# Since we are not using multiplicity, then
|
||||
# scattering multiplication (nu-scatter) must be
|
||||
# accounted for approximately by using an adjusted
|
||||
# absorption cross section.
|
||||
if 'total' in self.mgxs_types:
|
||||
xsdata.absorption = \
|
||||
np.subtract(xsdata.total,
|
||||
np.sum(xsdata.scatter[0, :, :],
|
||||
axis=1))
|
||||
else:
|
||||
msg = "Absorption cross section must be " + \
|
||||
"provided if using a transport cross" + \
|
||||
" section and while not providing a " + \
|
||||
"scattering matrix"
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
msg = "No nu-scatter matrix data was provided. " +\
|
||||
"This means neutron balance cannot be " + \
|
||||
"achieved since (n,xn) multiplication is " +\
|
||||
"ignored."
|
||||
warn(msg)
|
||||
xsdata.set_scatter(
|
||||
self.all_mgxs[id]['scatter matrix'],
|
||||
xs_type=xs_type,
|
||||
subdomains=(id,),
|
||||
nuclides=[nuclide])
|
||||
|
||||
xsdatas.append(xsdata)
|
||||
|
||||
# Add XSdatas to file
|
||||
mgxs_file.add_xsdatas(xsdatas)
|
||||
|
|
@ -1029,3 +918,68 @@ class Library(object):
|
|||
|
||||
if return_names:
|
||||
return mat_names
|
||||
|
||||
def check_library_for_openmc_mgxs(self):
|
||||
"""This routine will check the MGXS Types within the provided
|
||||
Library to ensure the data types provided can be used to create
|
||||
a MGXS Library for OpenMC's Multi-Group mode via the
|
||||
`Library.write_mg_library` method.
|
||||
The rules to check include:
|
||||
- Fission is not required as a fixed source problem could be
|
||||
the target.
|
||||
- Absorption is required.
|
||||
- A nu-scatter matrix is required.
|
||||
- Having both nu-scatter (of any order) and scatter
|
||||
(at least isotropic) matrices is preferred
|
||||
- If only nu-scatter, need total (not transport), to
|
||||
be used in adjusting absorption
|
||||
(i.e., reduced_abs = tot - nuscatt)
|
||||
- Either total or transport should be present.
|
||||
- Both can be available if one wants, but we should
|
||||
use whatever corresponds to Library.correction (if P0: transport)
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the Library object is initialized with insufficient types of
|
||||
cross sections for the Library.
|
||||
|
||||
See also
|
||||
--------
|
||||
Library.write_mg_library(...)
|
||||
|
||||
"""
|
||||
|
||||
error_flag = False
|
||||
# Ensure absorption is present
|
||||
if 'absorption' not in self.mgxs_types:
|
||||
error_flag = True
|
||||
msg = 'Absorption MGXS type is required but not provided.'
|
||||
warn(msg)
|
||||
# Ensure nu-scattering matrix is required
|
||||
if 'nu-scatter matrix' not in self.mgxs_types:
|
||||
error_flag = True
|
||||
msg = 'Nu-Scatter Matrix MGXS type is required but not provided.'
|
||||
warn(msg)
|
||||
else:
|
||||
# Ok, now see the status of scatter
|
||||
if 'scatter matrix' not in self.mgxs_types:
|
||||
# We dont have both nu-scatter and scatter, therefore
|
||||
# we need total, and not transport.
|
||||
if 'total' not in self.mgxs_types:
|
||||
error_flag = True
|
||||
msg = 'Total MGXS type is required if a ' \
|
||||
'scattering matrix is not provided.'
|
||||
warn(msg)
|
||||
# Total or transport can be present, but if using
|
||||
# self.correction=="P0", then we should use transport.
|
||||
if (((self.correction is "P0") and
|
||||
('transport' not in self.mgxs_types))):
|
||||
error_flag = True
|
||||
msg = 'Transport MGXS type is required since a "P0" correction ' \
|
||||
'is applied, but a Transport MGXS is not provided.'
|
||||
warn(msg)
|
||||
|
||||
if error_flag:
|
||||
msg = "Invalid MGXS configuration encountered."
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
|
|
@ -122,12 +122,23 @@ class XSdata(object):
|
|||
Legendre polynomial form). Dict contains two keys: 'enable' and
|
||||
'num_points'. 'enable' is a boolean and 'num_points' is the
|
||||
number of points to use, if 'enable' is True.
|
||||
representation : {'isotropic', 'angle'}
|
||||
Method used in generating the MGXS (isotropic or angle-dependent flux
|
||||
weighting).
|
||||
num_azimuthal : int
|
||||
Number of equal width angular bins that the azimuthal angular domain is
|
||||
subdivided into. This only applies when ``representation`` is "angle".
|
||||
num_polar : int
|
||||
Number of equal width angular bins that the polar angular domain is
|
||||
subdivided into. This only applies when ``representation`` is "angle".
|
||||
vector_shape : iterable of int
|
||||
Dimensionality of vector multi-group cross sections (e.g., the total
|
||||
cross section). The return result depends on the value of
|
||||
``representation``.
|
||||
matrix_shape : iterable of int
|
||||
Dimensionality of matrix multi-group cross sections (e.g., the
|
||||
scattering matrix cross section). The return result depends on the
|
||||
value of ``representation``.
|
||||
total : numpy.ndarray
|
||||
Group-wise total cross section ordered by increasing group index (i.e.,
|
||||
fast to thermal). If ``representation`` is "isotropic", then the length
|
||||
|
|
@ -173,7 +184,7 @@ class XSdata(object):
|
|||
azimuthal angles times the number of polar angles, with the
|
||||
inner-dimension being groups, intermediate-dimension being azimuthal
|
||||
angles and outer-dimension being the polar angles.
|
||||
k_fission : numpy.ndarray
|
||||
kappa_fission : numpy.ndarray
|
||||
Group-wise kappa-fission cross section ordered by increasing group
|
||||
index (i.e., fast to thermal). If ``representation`` is "isotropic",
|
||||
then the length of this list should equal the number of groups in the
|
||||
|
|
@ -225,7 +236,7 @@ class XSdata(object):
|
|||
self._multiplicity = None
|
||||
self._fission = None
|
||||
self._nu_fission = None
|
||||
self._k_fission = None
|
||||
self._kappa_fission = None
|
||||
self._chi = None
|
||||
self._use_chi = None
|
||||
|
||||
|
|
@ -302,8 +313,8 @@ class XSdata(object):
|
|||
return self._nu_fission
|
||||
|
||||
@property
|
||||
def k_fission(self):
|
||||
return self._k_fission
|
||||
def kappa_fission(self):
|
||||
return self._kappa_fission
|
||||
|
||||
@property
|
||||
def chi(self):
|
||||
|
|
@ -317,6 +328,24 @@ class XSdata(object):
|
|||
else:
|
||||
return self._order
|
||||
|
||||
@property
|
||||
def vector_shape(self):
|
||||
if self.representation is 'isotropic':
|
||||
return (self.energy_groups.num_groups,)
|
||||
elif self.representation is 'angle':
|
||||
return (self.num_polar, self.num_azimuthal,
|
||||
self.energy_groups.num_groups)
|
||||
|
||||
@property
|
||||
def matrix_shape(self):
|
||||
if self.representation is 'isotropic':
|
||||
return (self.energy_groups.num_groups,
|
||||
self.energy_groups.num_groups)
|
||||
elif self.representation is 'angle':
|
||||
return (self.num_polar, self.num_azimuthal,
|
||||
self.energy_groups.num_groups,
|
||||
self.energy_groups.num_groups)
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
check_type('name for XSdata', name, basestring)
|
||||
|
|
@ -326,6 +355,11 @@ class XSdata(object):
|
|||
def energy_groups(self, energy_groups):
|
||||
# Check validity of energy_groups
|
||||
check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups)
|
||||
|
||||
if energy_group.group_edges is None:
|
||||
msg = 'Unable to assign an EnergyGroups object ' + \
|
||||
'with uninitialized group edges'
|
||||
raise ValueError(msg)
|
||||
self._energy_groups = energy_groups
|
||||
|
||||
@representation.setter
|
||||
|
|
@ -414,141 +448,196 @@ class XSdata(object):
|
|||
|
||||
@total.setter
|
||||
def total(self, total):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,)
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
"""This method sets the total cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
total: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('total', total, np.ndarray, expected_iter_type=Real)
|
||||
if total.shape == shape:
|
||||
self._total = np.copy(total)
|
||||
else:
|
||||
msg = 'Shape of provided total "{0}" does not match shape ' \
|
||||
'required, "{1}"'.format(total.shape, shape)
|
||||
raise ValueError(msg)
|
||||
# Check the dimensions of the data
|
||||
check_value('total shape', total.shape, self.vector_shape)
|
||||
|
||||
self._total = np.copy(total)
|
||||
|
||||
@absorption.setter
|
||||
def absorption(self, absorption):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,)
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
"""This method sets the absorption cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
absorption: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# check we have a numpy list
|
||||
check_type('absorption', absorption, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
if absorption.shape == shape:
|
||||
self._absorption = np.copy(absorption)
|
||||
else:
|
||||
msg = 'Shape of provided absorption "{0}" does not match shape ' \
|
||||
'required, "{1}"'.format(absorption.shape, shape)
|
||||
raise ValueError(msg)
|
||||
# Check the dimensions of the data
|
||||
check_value('absorption shape', absorption.shape, self.vector_shape)
|
||||
|
||||
self._absorption = np.copy(absorption)
|
||||
|
||||
@fission.setter
|
||||
def fission(self, fission):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,)
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
# check we have a numpy list
|
||||
check_type('fission', fission, np.ndarray, expected_iter_type=Real)
|
||||
if fission.shape == shape:
|
||||
self._fission = np.copy(fission)
|
||||
if np.sum(self._fission) > 0.0:
|
||||
self._fissionable = True
|
||||
else:
|
||||
msg = 'Shape of provided fission "{0}" does not match shape ' \
|
||||
'required, "{1}"'.format(fission.shape, shape)
|
||||
raise ValueError(msg)
|
||||
"""This method sets the fission cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
@k_fission.setter
|
||||
def k_fission(self, k_fission):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,)
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
Parameters
|
||||
----------
|
||||
fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# check we have a numpy list
|
||||
check_type('k_fission', k_fission, np.ndarray,
|
||||
check_type('fission', fission, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
if k_fission.shape == shape:
|
||||
self._k_fission = np.copy(k_fission)
|
||||
if np.sum(self._k_fission) > 0.0:
|
||||
self._fissionable = True
|
||||
else:
|
||||
msg = 'Shape of provided k_fission "{0}" does not match ' \
|
||||
'shape required, "{1}"'.format(k_fission.shape, shape)
|
||||
raise ValueError(msg)
|
||||
# Check the dimensions of the data
|
||||
check_value('fission shape', fission.shape, self.vector_shape)
|
||||
|
||||
self._fission = np.copy(fission)
|
||||
|
||||
if np.sum(self._fission) > 0.0:
|
||||
self._fissionable = True
|
||||
|
||||
@kappa_fission.setter
|
||||
def kappa_fission(self, kappa_fission):
|
||||
"""This method sets the kappa_fission cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
kappa_fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# check we have a numpy list
|
||||
check_type('kappa_fission', fission, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
# Check the dimensions of the data
|
||||
check_value('kappa fission shape', kappa_fission.shape,
|
||||
self.vector_shape)
|
||||
|
||||
self._kappa_fission = np.copy(fission)
|
||||
|
||||
if np.sum(self._kappa_fission) > 0.0:
|
||||
self._fissionable = True
|
||||
|
||||
@chi.setter
|
||||
def chi(self, chi):
|
||||
"""This method sets the chi cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
chi: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if self._use_chi is not None:
|
||||
if not self._use_chi:
|
||||
msg = 'Providing chi when nu_fission already provided as matrix!'
|
||||
msg = 'Providing chi when nu_fission already provided as a' \
|
||||
'matrix'
|
||||
raise ValueError(msg)
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,)
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
# check we have a numpy list
|
||||
check_type('chi', chi, np.ndarray, expected_iter_type=Real)
|
||||
if chi.shape == shape:
|
||||
self._chi = np.copy(chi)
|
||||
else:
|
||||
msg = 'Shape of provided chi "{0}" does not match shape ' \
|
||||
'required, "{1}"'.format(chi.shape, shape)
|
||||
raise ValueError(msg)
|
||||
# Check the dimensions of the data
|
||||
check_value('chi shape', chi.shape, self.vector_shape)
|
||||
|
||||
self._chi = np.copy(chi)
|
||||
|
||||
if self._use_chi is not None:
|
||||
self._use_chi = True
|
||||
|
||||
@scatter.setter
|
||||
def scatter(self, scatter):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self.num_orders, self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
max_depth = 3
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal, self.num_orders,
|
||||
self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
max_depth = 5
|
||||
"""This method sets the scattering matrix cross sections
|
||||
by performing a deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scatter : ndarrays
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# check we have a numpy list
|
||||
check_iterable_type('scatter', scatter, expected_type=Real,
|
||||
max_depth=max_depth)
|
||||
if scatter.shape == shape:
|
||||
self._scatter = np.copy(scatter)
|
||||
else:
|
||||
msg = 'Shape of provided scatter "{0}" does not match shape ' \
|
||||
'required, "{1}"'.format(scatter.shape, shape)
|
||||
raise ValueError(msg)
|
||||
check_type('scatter', scatter, np.ndarray, expected_iter_type=Real,
|
||||
max_depth=len(scatter.shape))
|
||||
# Check the dimensions of the data
|
||||
check_value('scatter shape', scatter.shape, self.matrix_shape)
|
||||
|
||||
self._scatter = np.copy(scatter)
|
||||
|
||||
@multiplicity.setter
|
||||
def multiplicity(self, multiplicity):
|
||||
if self._representation is 'isotropic':
|
||||
shape = (self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
max_depth = 2
|
||||
elif self._representation is 'angle':
|
||||
shape = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
max_depth = 4
|
||||
"""This method sets the scattering multiplicity matrix cross sections
|
||||
by performing a deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
multiplicity : ndarrays
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# check we have a numpy list
|
||||
check_iterable_type('multiplicity', multiplicity, expected_type=Real,
|
||||
max_depth=max_depth)
|
||||
if multiplicity.shape == shape:
|
||||
self._multiplicity = np.copy(multiplicity)
|
||||
else:
|
||||
msg = 'Shape of provided multiplicity "{0}" does not match shape' \
|
||||
' required, "{1}"'.format(multiplicity.shape, shape)
|
||||
raise ValueError(msg)
|
||||
check_type('multiplicity', multiplicity, np.ndarray,
|
||||
expected_iter_type=Real, max_depth=len(multiplicity.shape))
|
||||
# Check the dimensions of the data
|
||||
check_value('multiplicity shape', multiplicity.shape,
|
||||
self.matrix_shape)
|
||||
|
||||
self._multiplicity = np.copy(multiplicity)
|
||||
|
||||
@nu_fission.setter
|
||||
def nu_fission(self, nu_fission):
|
||||
"""This method sets the nu_fission cross section by performing a
|
||||
deep-copy of the provided ndarray.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nu_fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# The NuFissionXS class does not have the capability to produce
|
||||
# a fission matrix and therefore if this path is pursued, we know
|
||||
# chi must be used.
|
||||
|
|
@ -559,47 +648,54 @@ class XSdata(object):
|
|||
# chi already has been set. If not, we just check that this is OK
|
||||
# and set the use_chi flag accordingly
|
||||
|
||||
# First lets set our dimensions here since they get used repeatedly
|
||||
# throughout this code.
|
||||
if self._representation is 'isotropic':
|
||||
shape_vec = (self._energy_groups.num_groups,)
|
||||
shape_mat = (self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
elif self._representation is 'angle':
|
||||
shape_vec = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups)
|
||||
shape_mat = (self._num_polar, self._num_azimuthal,
|
||||
self._energy_groups.num_groups,
|
||||
self._energy_groups.num_groups)
|
||||
|
||||
# Begin by checking the case when chi has already been given and
|
||||
# thus the rules for filling in nu_fission are set.
|
||||
if self._use_chi is not None:
|
||||
if self._use_chi:
|
||||
shape = shape_vec
|
||||
else:
|
||||
shape = shape_mat
|
||||
if nu_fission.shape != shape:
|
||||
msg = 'Invalid Shape of Nu_fission!'
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
# Get shape of nu_fission to determine if we need chi or not
|
||||
if nu_fission.shape == shape_vec:
|
||||
self._use_chi = True
|
||||
elif nu_fission.shape == shape_mat:
|
||||
self._use_chi = False
|
||||
else:
|
||||
msg = 'Invalid Shape of Nu_fission!'
|
||||
raise ValueError(msg)
|
||||
|
||||
# check we have a numpy list
|
||||
# First, check we have a numpy list
|
||||
check_type('nu_fission', nu_fission, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
expected_iter_type=Real, max_depth=len(nu_fission.shape))
|
||||
|
||||
if self._use_chi is not None:
|
||||
# Check the dimensions of the data
|
||||
if self._use_chi:
|
||||
check_value('nu_fission shape', nu_fission.shape,
|
||||
self.vector_shape)
|
||||
else:
|
||||
check_value('nu_fission shape', nu_fission.shape,
|
||||
self.matrix_shape)
|
||||
else:
|
||||
# Make sure the dimensions are at least right
|
||||
check_value('nu_fission shape', nu_fission.shape,
|
||||
(self.vector_shape, self.matrix_shape))
|
||||
# Then find out which one we have so we can set use_chi
|
||||
if nu_fission.shape == self.vector_shape:
|
||||
self._use_chi = True
|
||||
else:
|
||||
self._use_chi = False
|
||||
|
||||
self._nu_fission = np.copy(nu_fission)
|
||||
if np.sum(self._nu_fission) > 0.0:
|
||||
self._fissionable = True
|
||||
|
||||
def set_total(self, total, subdomain, nuclide='sum', xs_type='macro'):
|
||||
def set_total_mgxs(self, total, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.TotalXS or
|
||||
openmc.mgxs.TransportXS to be used to set the total cross section
|
||||
for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
total: {openmc.mgxs.TotalXS, openmc.mgxs.TransportXS}
|
||||
MGXS Object containing the total or transport cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(total, (openmc.mgxs.TotalXS,
|
||||
openmc.mgxs.TransportXS)):
|
||||
msg = 'Method must be passed an openmc.mgxs.TotalXS or ' \
|
||||
|
|
@ -607,59 +703,119 @@ class XSdata(object):
|
|||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != total.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', total.energy_groups, [self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', total.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._total = total.get_xs(subdomain=subdomains, nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
self._total = total.get_xs(nuclides=nuclide, xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
|
||||
def set_absorption(self, absorption, subdomain, nuclide='sum',
|
||||
xs_type='macro'):
|
||||
def set_absorption_mgxs(self, absorption, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.AbsorptionXS
|
||||
to be used to set the absorption cross section for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
absorption: openmc.mgxs.AbsorptionXS
|
||||
MGXS Object containing the absorption cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(absorption, openmc.mgxs.AbsorptionXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.AbsorptionXS'
|
||||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != absorption.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', absorption.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', absorption.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._absorption = absorption.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
self._absorption = absorption.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
|
||||
def set_fission(self, fission, subdomain, nuclide='sum', xs_type='macro'):
|
||||
def set_fission_mgxs(self, fission, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.FissionXS
|
||||
to be used to set the fission cross section for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fission: openmc.mgxs.FissionXS
|
||||
MGXS Object containing the fission cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(fission, openmc.mgxs.FissionXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.FissionXS'
|
||||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != fission.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', fission.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', fission.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._fission = fission.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
self._fission = fission.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
|
||||
def set_nu_fission(self, nu_fission, subdomain, nuclide='sum',
|
||||
xs_type='macro'):
|
||||
def set_nu_fission_mgxs(self, nu_fission, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.NuFissionXS
|
||||
to be used to set the nu-fission cross section for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nu_fission: openmc.mgxs.NuFissionXS
|
||||
MGXS Object containing the nu-fission cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
# The NuFissionXS class does not have the capability to produce
|
||||
# a fission matrix and therefore if this path is pursued, we know
|
||||
# chi must be used.
|
||||
|
|
@ -668,14 +824,15 @@ class XSdata(object):
|
|||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != nu_fission.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', nu_fission.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', nu_fission.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._nu_fission = nu_fission.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
self._nu_fission = nu_fission.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
|
|
@ -686,27 +843,68 @@ class XSdata(object):
|
|||
if np.sum(self._nu_fission) > 0.0:
|
||||
self._fissionable = True
|
||||
|
||||
def set_k_fission(self, k_fission, subdomain, nuclide='sum',
|
||||
xs_type='macro'):
|
||||
def set_kappa_fission_mgxs(self, k_fission, nuclide='total',
|
||||
xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.KappaFissionXS
|
||||
to be used to set the kappa-fission cross section for this XSdata
|
||||
object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
kappa_fission: openmc.mgxs.KappaFissionXS
|
||||
MGXS Object containing the kappa-fission cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(k_fission, openmc.mgxs.KappaFissionXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.KappaFissionXS'
|
||||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != k_fission.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', k_fission.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', k_fission.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._k_fission = k_fission.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
self._kappa_fission = k_fission.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
|
||||
def set_chi(self, chi, subdomain, nuclide='sum', xs_type='macro'):
|
||||
def set_chi_mgxs(self, chi, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.Chi
|
||||
to be used to set chi for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
chi: openmc.mgxs.Chi
|
||||
MGXS Object containing chi for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if self._use_chi is not None:
|
||||
if not self._use_chi:
|
||||
msg = 'Providing chi when nu_fission already provided as a ' \
|
||||
|
|
@ -718,14 +916,14 @@ class XSdata(object):
|
|||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != chi.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', chi.energy_groups, [self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', chi.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._chi = chi.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
self._chi = chi.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
|
|
@ -734,55 +932,102 @@ class XSdata(object):
|
|||
if self._use_chi is not None:
|
||||
self._use_chi = True
|
||||
|
||||
def set_scatter(self, scatter, subdomain, nuclide='sum', xs_type='macro'):
|
||||
def set_scatter_mgxs(self, scatter, nuclide='total', xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.ScatterMatrixXS
|
||||
to be used to set the scatter matrix cross section for this XSdata
|
||||
object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scatter: openmc.mgxs.ScatterMatrixXS
|
||||
MGXS Object containing the scatter matrix cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(scatter, openmc.mgxs.ScatterMatrixXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.ScatterMatrixXS'
|
||||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
if self.energy_groups != scatter.energy_groups:
|
||||
msg = 'Group structure of provided data does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
check_value('energy_groups', scatter.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', scatter.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
self._scatter = scatter.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
self._scatter = scatter.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
|
||||
def set_multiplicity(self, multiplicity, scatter, subdomain,
|
||||
nuclide='sum', xs_type='macro'):
|
||||
if not isinstance(multiplicity, openmc.mgxs.ScatterMatrixXS):
|
||||
def set_multiplicity_mgxs(self, nuscatter, scatter, nuclide='total',
|
||||
xs_type='macro'):
|
||||
"""This method allows for an openmc.mgxs.NuScatterMatrixXS and
|
||||
openmc.mgxs.ScatterMatrixXS to be used to set the scattering
|
||||
multiplicity for this XSdata object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuscatter: openmc.mgxs.NuScatterMatrixXS
|
||||
MGXS Object containing the nu-scattering matrix cross section
|
||||
for the domain of interest.
|
||||
scatter: openmc.mgxs.ScatterMatrixXS
|
||||
MGXS Object containing the scattering matrix cross section
|
||||
for the domain of interest.
|
||||
nuclide : str
|
||||
Individual nuclide (or 'total' if obtaining material-wise data)
|
||||
to gather data for. Defaults to 'total'.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When invalid parameters are passed.
|
||||
"""
|
||||
if not isinstance(nuscatter, openmc.mgxs.NuScatterMatrixXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.ScatterMatrixXS'
|
||||
raise TypeError(msg)
|
||||
if not isinstance(scatter, openmc.mgxs.ScatterMatrixXS):
|
||||
msg = 'Method must be passed an openmc.mgxs.ScatterMatrixXS'
|
||||
raise TypeError(msg)
|
||||
|
||||
# Make sure passed MGXS objects contain correct group structure
|
||||
if self.energy_groups != multiplicity.energy_groups:
|
||||
msg = 'Group structure of "multiplicity" does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
if self.energy_groups != scatter.energy_groups:
|
||||
msg = 'Group structure of "scatter" does not match' \
|
||||
' group structure of XSdata object'
|
||||
raise ValueError(msg)
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
check_value('energy_groups', nuscatter.energy_groups,
|
||||
[self.energy_groups])
|
||||
check_value('energy_groups', scatter.energy_groups,
|
||||
[self.energy_groups])
|
||||
|
||||
# Make sure passed MGXS object has correct domain type
|
||||
check_value('domain_type', nuscatter.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
check_value('domain_type', scatter.domain_type,
|
||||
['universe', 'cell', 'material'])
|
||||
|
||||
if self._representation is 'isotropic':
|
||||
nuscatt = multiplicity.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
scatt = scatter.get_xs(subdomains=subdomain,
|
||||
nuclides=nuclide,
|
||||
nuscatt = nuscatter.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
scatt = scatter.get_xs(nuclides=nuclide,
|
||||
xs_type=xs_type)
|
||||
self._multiplicity = np.divide(nuscatt, scatt)
|
||||
elif self._representation is 'angle':
|
||||
msg = 'Angular-Dependent MGXS have not yet been implemented'
|
||||
raise ValueError(msg)
|
||||
self._multiplicity = np.nan_to_num(self._multiplicity)
|
||||
|
||||
def _get_xsdata_xml(self):
|
||||
element = ET.Element('xsdata')
|
||||
|
|
@ -858,9 +1103,9 @@ class XSdata(object):
|
|||
subelement = ET.SubElement(element, 'fission')
|
||||
subelement.text = ndarray_to_string(self._fission)
|
||||
|
||||
if self._k_fission is not None:
|
||||
if self._kappa_fission is not None:
|
||||
subelement = ET.SubElement(element, 'k_fission')
|
||||
subelement.text = ndarray_to_string(self._k_fission)
|
||||
subelement.text = ndarray_to_string(self._kappa_fission)
|
||||
|
||||
if self._nu_fission is not None:
|
||||
subelement = ET.SubElement(element, 'nu_fission')
|
||||
|
|
@ -947,10 +1192,8 @@ class MGXSLibrary(object):
|
|||
|
||||
"""
|
||||
|
||||
if not isinstance(xsdatas, Iterable):
|
||||
msg = 'Unable to create OpenMC xsdatas.xml file from "{0}" which' \
|
||||
' is not iterable'.format(xsdatas)
|
||||
raise ValueError(msg)
|
||||
# Check we have an iterable of XSdatas
|
||||
check_iterable_type('xsdatas', xsdatas, XSdata)
|
||||
|
||||
for xsdata in xsdatas:
|
||||
self.add_xsdata(xsdata)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue