mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Updating per the latest round of comments. This includes simplifying the notebook significantly, and adding a get_xsdata method to Library.
This commit is contained in:
parent
e9fc744ba5
commit
eb20de6a51
6 changed files with 393 additions and 1551 deletions
File diff suppressed because one or more lines are too long
|
|
@ -8,10 +8,10 @@ OpenMC can be run in continuous-energy mode or multi-group mode, provided the
|
|||
nuclear data is available. In continuous-energy mode, the
|
||||
``cross_sections.xml`` file contains necessary meta-data for each data set,
|
||||
including the name and a file system location where the complete library
|
||||
can be found. In multi-group mode, this ``cross_sections.xml`` file contains
|
||||
can be found. In multi-group mode, this ``mgxs.xml`` file contains
|
||||
this same meta-data describing the nuclide or material, but also contains the
|
||||
group-wise nuclear data. This portion of the manual describes the format of
|
||||
the multi-group data library required to be used in the ``cross_sections.xml``
|
||||
the multi-group data library required to be used in the ``mgxs.xml``
|
||||
file.
|
||||
|
||||
Similar to the other input file types, the multi-group library is provided in
|
||||
|
|
@ -23,7 +23,7 @@ materials.
|
|||
.. _XML: http://www.w3.org/XML/
|
||||
|
||||
------------------------------------------------
|
||||
MGXS Library Specification -- cross_sections.xml
|
||||
MGXS Library Specification -- mgxs.xml
|
||||
------------------------------------------------
|
||||
|
||||
The multi-group library meta-data is contained within the groups_,
|
||||
|
|
|
|||
|
|
@ -348,7 +348,9 @@ class Material(object):
|
|||
del self._nuclides[nuclide._name]
|
||||
|
||||
def add_macroscopic(self, macroscopic):
|
||||
"""Add a macroscopic to the material
|
||||
"""Add a macroscopic to the material. This will also set the
|
||||
density of the material to 1.0, unless it has been otherwise set,
|
||||
as a default for Macroscopic cross sections.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -386,6 +388,14 @@ class Material(object):
|
|||
'Material!'.format(self._id, macroscopic)
|
||||
raise ValueError(msg)
|
||||
|
||||
# Generally speaking, the density for a macroscopic object will
|
||||
# be 1.0. Therefore, lets set density to 1.0 so that the user
|
||||
# doesnt need to set it unless its needed.
|
||||
# Of course, if the user has already set a value of density,
|
||||
# then we will not override it.
|
||||
if self._density is None:
|
||||
self.set_density('macro', 1.0)
|
||||
|
||||
def remove_macroscopic(self, macroscopic):
|
||||
"""Remove a macroscopic from the material
|
||||
|
||||
|
|
|
|||
|
|
@ -722,11 +722,140 @@ class Library(object):
|
|||
# Load and return pickled Library object
|
||||
return pickle.load(open(full_filename, 'rb'))
|
||||
|
||||
def write_mg_library(self, xs_type='macro', domain_names=None, xs_ids=None,
|
||||
filename='mg_cross_sections', directory='./',
|
||||
return_names=False):
|
||||
"""Creates a cross-section data library file for the Multi-Group
|
||||
mode of OpenMC.
|
||||
def get_xsdata(self, domain, domain_name, nuclide='total', xs_type='macro',
|
||||
xs_id='1m', order=-1):
|
||||
"""Generates an openmc.XSdata object describing a multi-group cross section
|
||||
data set for eventual combination in to an openmc.MGXSLibrary object
|
||||
(i.e., the library).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe
|
||||
The domain for spatial homogenization
|
||||
domain_name : str
|
||||
Name to apply to the "xsdata" entry produced by this method
|
||||
nuclide : str
|
||||
A nuclide name string (e.g., 'U-235'). Defaults to 'total' to
|
||||
obtain a material-wise macroscopic cross section.
|
||||
xs_type: {'macro', 'micro'}
|
||||
Provide the macro or micro cross section in units of cm^-1 or
|
||||
barns. Defaults to 'macro'. If the Library object is not tallied by
|
||||
nuclide this will be set to 'macro' regardless.
|
||||
xs_ids : str
|
||||
Cross section set identifier. Defaults to '1m'.
|
||||
order : Scattering order for this dataset entry. Default is -1,
|
||||
which will force the XSdata object to use whatever the maximum
|
||||
order available.
|
||||
|
||||
Returns
|
||||
-------
|
||||
xsdata : openmc.XSdata
|
||||
Multi-Group Cross Section data set object.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the Library object is initialized with insufficient types of
|
||||
cross sections for the Library.
|
||||
|
||||
See also
|
||||
--------
|
||||
Library.create_mg_library(...)
|
||||
|
||||
"""
|
||||
|
||||
cv.check_type('domain', domain, (openmc.Material, openmc.Cell,
|
||||
openmc.Cell))
|
||||
cv.check_type('domain_name', domain_name, basestring)
|
||||
cv.check_type('nuclide', nuclide, basestring)
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
cv.check_type('xs_id', xs_id, basestring)
|
||||
cv.check_type('order', order, Integral)
|
||||
cv.check_greater_than('order', order, -1, equality=True)
|
||||
|
||||
# Make sure statepoint has been loaded
|
||||
if self._sp_filename is None:
|
||||
msg = 'A StatePoint must be loaded before calling ' \
|
||||
'the create_mg_library() function'
|
||||
raise ValueError(msg)
|
||||
|
||||
# If gathering material-specific data, set the xs_type to macro
|
||||
if not self.by_nuclide:
|
||||
xs_type = 'macro'
|
||||
|
||||
# Build & add metadata to XSdata object
|
||||
name = domain_name
|
||||
if nuclide is not 'total':
|
||||
name += '_' + nuclide
|
||||
name += '.' + xs_id
|
||||
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]
|
||||
|
||||
# Now get xs data itself
|
||||
if 'transport' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'transport')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
|
||||
elif 'total' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'total')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
|
||||
if 'absorption' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'absorption')
|
||||
xsdata.set_absorption_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide])
|
||||
if 'fission' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'fission')
|
||||
xsdata.set_fission_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide])
|
||||
if 'kappa-fission' in self.mgxs_types:
|
||||
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:
|
||||
mymgxs = self.get_mgxs(domain, 'chi')
|
||||
xsdata.set_chi_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
|
||||
if 'nu-fission' in self.mgxs_types:
|
||||
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))):
|
||||
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:
|
||||
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:
|
||||
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.
|
||||
if 'total' in self.mgxs_types:
|
||||
xsdata._absorption = \
|
||||
np.subtract(xsdata.total,
|
||||
np.sum(xsdata.scatter[0, :, :], axis=1))
|
||||
|
||||
return xsdata
|
||||
|
||||
def create_mg_library(self, xs_type='macro', domain_names=None,
|
||||
xs_ids=None):
|
||||
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
|
||||
Multi-Group mode of OpenMC.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -735,28 +864,18 @@ class Library(object):
|
|||
barns. Defaults to 'macro'. If the Library object is not tallied by
|
||||
nuclide this will be set to 'macro' regardless.
|
||||
domain_names : Iterable of str
|
||||
List of names to apply to the xsdata entries in the
|
||||
List of names to apply to the "xsdata" entries in the
|
||||
resultant mgxs data file. Defaults to 'set1', 'set2', ...
|
||||
xs_ids : str or Iterable of str
|
||||
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 '1m'.
|
||||
filename : str
|
||||
Filename for the pickle file. Defaults to 'mg_cross_sections'.
|
||||
directory : str
|
||||
Directory for the pickle file. Defaults to './' (the
|
||||
current working directory).
|
||||
return_names : bool
|
||||
Flag to indicate if the user would like the names of the
|
||||
materials generated by this function returned with completion.
|
||||
Defaults to False, indicating that no names will be returned.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mat_names : Iterable of str
|
||||
Iterable of material names generated during this routine and
|
||||
applies to the cross section library. Note this is returned if
|
||||
the return_names parameter is provided.
|
||||
mgxs_file : openmc.MGXSLibrary
|
||||
Multi-Group Cross Section File that is ready to be printed to the
|
||||
file of choice by the user.
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
@ -774,10 +893,9 @@ class Library(object):
|
|||
# multi-group cross section types
|
||||
self.check_library_for_openmc_mgxs()
|
||||
|
||||
# Check the provided parameters
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
if domain_names is not None:
|
||||
cv.check_iterable_type('domain_names', filename, basestring)
|
||||
cv.check_iterable_type('domain_names', domain_names, basestring)
|
||||
if xs_ids is not None:
|
||||
if isinstance(xs_ids, basestring):
|
||||
# If we only have a string lets convert it now to a list
|
||||
|
|
@ -787,25 +905,11 @@ class Library(object):
|
|||
cv.check_iterable_type('xs_ids', xs_ids, basestring)
|
||||
else:
|
||||
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 gathering material-specific data, set the xs_type to macro
|
||||
if not self.by_nuclide:
|
||||
xs_type = 'macro'
|
||||
|
||||
# Make directory if it does not exist and build our filename
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
full_filename = os.path.join(directory, filename + '.xml')
|
||||
full_filename = full_filename.replace(' ', '-')
|
||||
|
||||
# Initialize file
|
||||
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
|
||||
|
||||
|
|
@ -813,13 +917,10 @@ class Library(object):
|
|||
# support for higher orders are included in openmc.mgxs
|
||||
order = 0
|
||||
|
||||
# Build XSdata objects
|
||||
# Build storage for our XSdata objects
|
||||
xsdatas = []
|
||||
|
||||
mat_names = {}
|
||||
for i, domain in enumerate(self.domains):
|
||||
|
||||
mat_names[domain.id] = {}
|
||||
if self.by_nuclide:
|
||||
nuclides = list(domain.get_all_nuclides().keys())
|
||||
else:
|
||||
|
|
@ -832,99 +933,23 @@ class Library(object):
|
|||
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]
|
||||
|
||||
nuclide = [nuclide]
|
||||
# Now get xs data itself
|
||||
if 'transport' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'transport')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
elif 'total' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'total')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'absorption' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'absorption')
|
||||
xsdata.set_absorption_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'fission' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'fission')
|
||||
xsdata.set_fission_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'kappa-fission' in self.mgxs_types:
|
||||
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:
|
||||
mymgxs = self.get_mgxs(domain, 'chi')
|
||||
xsdata.set_chi_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=nuclide)
|
||||
if 'nu-fission' in self.mgxs_types:
|
||||
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))):
|
||||
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:
|
||||
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:
|
||||
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.
|
||||
if 'total' in self.mgxs_types:
|
||||
xsdata._absorption = \
|
||||
np.subtract(xsdata.total,
|
||||
np.sum(xsdata.scatter[0, :, :],
|
||||
axis=1))
|
||||
xsdata = self.get_xsdata(domain, name, nuclide=nuclide,
|
||||
xs_type=xs_type, xs_id=xs_ids[i],
|
||||
order=order)
|
||||
|
||||
xsdatas.append(xsdata)
|
||||
|
||||
# Add XSdatas to file
|
||||
mgxs_file.add_xsdatas(xsdatas)
|
||||
|
||||
# Finally, write the file
|
||||
mgxs_file.export_to_xml(full_filename)
|
||||
|
||||
if return_names:
|
||||
return mat_names
|
||||
return mgxs_file
|
||||
|
||||
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.
|
||||
"""This routine will check the MGXS Types within a Library
|
||||
to ensure the MGXS types provided can be used to create
|
||||
a MGXS Library for OpenMC's Multi-Group mode.
|
||||
|
||||
The rules to check include:
|
||||
- Either total or transport should be present.
|
||||
- Both can be available if one wants, but we should
|
||||
|
|
@ -943,7 +968,7 @@ class Library(object):
|
|||
|
||||
See also
|
||||
--------
|
||||
Library.write_mg_library(...)
|
||||
Library.create_mg_library(...)
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -420,7 +420,8 @@ class XSdata(object):
|
|||
enable = tabular_legendre['enable']
|
||||
check_type('enable', enable, bool)
|
||||
else:
|
||||
msg = 'enable must be provided in tabular_legendre'
|
||||
msg = 'The tabular_legendre dict must include a value keyed by ' \
|
||||
'"enable"'
|
||||
raise ValueError(msg)
|
||||
if 'num_points' in tabular_legendre:
|
||||
num_points = tabular_legendre['num_points']
|
||||
|
|
@ -448,217 +449,77 @@ class XSdata(object):
|
|||
|
||||
@total.setter
|
||||
def total(self, total):
|
||||
"""This method sets the total cross section by performing a
|
||||
deep-copy of the provided ndarray. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
total: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('total', total, np.ndarray, expected_iter_type=Real)
|
||||
# Check the dimensions of the data
|
||||
check_value('total shape', total.shape, self.vector_shape)
|
||||
|
||||
self._total = np.copy(total)
|
||||
self._total = total
|
||||
|
||||
@absorption.setter
|
||||
def absorption(self, absorption):
|
||||
"""This method sets the absorption cross section by performing a
|
||||
deep-copy of the provided ndarray. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
absorption: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('absorption', absorption, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
# Check the dimensions of the data
|
||||
check_value('absorption shape', absorption.shape, self.vector_shape)
|
||||
|
||||
self._absorption = np.copy(absorption)
|
||||
self._absorption = absorption
|
||||
|
||||
@fission.setter
|
||||
def fission(self, fission):
|
||||
"""This method sets the fission cross section by performing a
|
||||
deep-copy of the provided ndarray. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('fission', fission, np.ndarray,
|
||||
expected_iter_type=Real)
|
||||
# Check the dimensions of the data
|
||||
check_value('fission shape', fission.shape, self.vector_shape)
|
||||
|
||||
self._fission = np.copy(fission)
|
||||
self._fission = 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. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
kappa_fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('kappa_fission', fission, np.ndarray,
|
||||
check_type('kappa_fission', kappa_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)
|
||||
self._kappa_fission = kappa_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. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
chi: ndarray
|
||||
Array of group-wise chi values to apply
|
||||
|
||||
"""
|
||||
|
||||
if self._use_chi is not None:
|
||||
if not self._use_chi:
|
||||
msg = 'Providing chi when nu_fission already provided as a' \
|
||||
'matrix'
|
||||
raise ValueError(msg)
|
||||
|
||||
# check we have a numpy list
|
||||
check_type('chi', chi, np.ndarray, expected_iter_type=Real)
|
||||
# Check the dimensions of the data
|
||||
check_value('chi shape', chi.shape, self.vector_shape)
|
||||
|
||||
self._chi = np.copy(chi)
|
||||
self._chi = chi
|
||||
|
||||
if self._use_chi is not None:
|
||||
self._use_chi = True
|
||||
|
||||
@scatter.setter
|
||||
def scatter(self, scatter):
|
||||
"""This method sets the scattering matrix cross sections
|
||||
by performing a deep-copy of the provided ndarray.
|
||||
If the angular representation is "isotropic" the shape of
|
||||
the input array must be the number of scattering orders, the
|
||||
number of energy groups, and the number of energy groups. If
|
||||
the angular representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles, number of scattering orders, energy groups, and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scatter : ndarrays
|
||||
Array of cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
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.pn_matrix_shape)
|
||||
|
||||
self._scatter = np.copy(scatter)
|
||||
self._scatter = scatter
|
||||
|
||||
@multiplicity.setter
|
||||
def multiplicity(self, multiplicity):
|
||||
"""This method sets the scattering multiplicity matrix cross sections
|
||||
by performing a deep-copy of the provided ndarray. Multiplicity,
|
||||
in OpenMC parlance, is a factor used to account for the production
|
||||
of neutrons introduced by scattering multiplication reactions, i.e.,
|
||||
(n,xn) events. In this sense, the multiplication matrix is simply
|
||||
defined as the ratio of the nu-scatter and scatter matrices.
|
||||
If the angular representation is "isotropic" the shape of
|
||||
the input array must be the number of energy groups and the number
|
||||
of energy groups. If the angular representation is "angle" then the
|
||||
shape of the input array must be the number of polar angles,
|
||||
number azimuthal angles, number of scattering orders, energy groups,
|
||||
and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
multiplicity : ndarrays
|
||||
Array of scattering multiplications to apply
|
||||
|
||||
"""
|
||||
|
||||
# check we have a numpy list
|
||||
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)
|
||||
self._multiplicity = 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. If the angular
|
||||
representation is "isotropic" the shape of the input array
|
||||
must be the number of energy groups. If the angular
|
||||
representation is "angle" then the shape of the input
|
||||
array must be the number of polar angles, number azimuthal
|
||||
angles and energy groups.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nu_fission: ndarray
|
||||
Array of group-wise cross sections to apply
|
||||
|
||||
"""
|
||||
|
||||
# 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.
|
||||
|
|
@ -669,12 +530,10 @@ 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, check we have a numpy list
|
||||
check_type('nu_fission', nu_fission, np.ndarray,
|
||||
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)
|
||||
|
|
@ -682,16 +541,16 @@ class XSdata(object):
|
|||
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
|
||||
# Find out if we have a nu-fission matrix or vector
|
||||
# and set a flag to allow other methods to check this later.
|
||||
if nu_fission.shape == self.vector_shape:
|
||||
self._use_chi = True
|
||||
else:
|
||||
self._use_chi = False
|
||||
|
||||
self._nu_fission = np.copy(nu_fission)
|
||||
self._nu_fission = nu_fission
|
||||
if np.sum(self._nu_fission) > 0.0:
|
||||
self._fissionable = True
|
||||
|
||||
|
|
@ -716,11 +575,7 @@ class XSdata(object):
|
|||
|
||||
check_type('total', total, (openmc.mgxs.TotalXS,
|
||||
openmc.mgxs.TransportXS))
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -750,12 +605,8 @@ class XSdata(object):
|
|||
"""
|
||||
|
||||
check_type('absorption', absorption, openmc.mgxs.AbsorptionXS)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -785,12 +636,8 @@ class XSdata(object):
|
|||
"""
|
||||
|
||||
check_type('fission', fission, openmc.mgxs.FissionXS)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -824,12 +671,8 @@ class XSdata(object):
|
|||
# a fission matrix and therefore if this path is pursued, we know
|
||||
# chi must be used.
|
||||
check_type('nu_fission', nu_fission, openmc.mgxs.NuFissionXS)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -866,12 +709,8 @@ class XSdata(object):
|
|||
"""
|
||||
|
||||
check_type('k_fission', k_fission, openmc.mgxs.KappaFissionXS)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -906,11 +745,7 @@ class XSdata(object):
|
|||
raise ValueError(msg)
|
||||
|
||||
check_type('chi', chi, openmc.mgxs.Chi)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -944,12 +779,8 @@ class XSdata(object):
|
|||
"""
|
||||
|
||||
check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS)
|
||||
|
||||
# Make sure passed MGXS object contains correct group structure
|
||||
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'])
|
||||
|
||||
|
|
@ -990,14 +821,10 @@ class XSdata(object):
|
|||
|
||||
check_type('nuscatter', nuscatter, openmc.mgxs.NuScatterMatrixXS)
|
||||
check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS)
|
||||
|
||||
# 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,
|
||||
|
|
@ -1153,14 +980,10 @@ class MGXSLibrary(object):
|
|||
MGXS information to add
|
||||
|
||||
"""
|
||||
|
||||
# Check the type
|
||||
if not isinstance(xsdata, XSdata):
|
||||
msg = 'Unable to add a non-XSdata "{0}" to the ' \
|
||||
'MGXSLibrary instance'.format(xsdata)
|
||||
raise ValueError(msg)
|
||||
|
||||
# Make sure energy groups match.
|
||||
if xsdata.energy_groups != self._energy_groups:
|
||||
msg = 'Energy groups of XSdata do not match that of MGXSLibrary.'
|
||||
raise ValueError(msg)
|
||||
|
|
@ -1176,8 +999,6 @@ class MGXSLibrary(object):
|
|||
XSdatas to add
|
||||
|
||||
"""
|
||||
|
||||
# Check we have an iterable of XSdatas
|
||||
check_iterable_type('xsdatas', xsdatas, XSdata)
|
||||
|
||||
for xsdata in xsdatas:
|
||||
|
|
@ -1222,14 +1043,14 @@ class MGXSLibrary(object):
|
|||
xml_element = xsdata._get_xsdata_xml()
|
||||
self._cross_sections_file.append(xml_element)
|
||||
|
||||
def export_to_xml(self, filename='mg_cross_sections.xml'):
|
||||
"""Create an mg_cross_sections.xml file that can be used for a
|
||||
def export_to_xml(self, filename='mgxs.xml'):
|
||||
"""Create an mgxs.xml file that can be used for a
|
||||
simulation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str, optional
|
||||
filename of file, default is mg_cross_sections.xml
|
||||
filename of file, default is mgxs.xml
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ contains
|
|||
else
|
||||
call get_environment_variable("OPENMC_MG_CROSS_SECTIONS", env_variable)
|
||||
if (len_trim(env_variable) == 0) then
|
||||
call fatal_error("No cross_sections.xml file was specified in &
|
||||
call fatal_error("No mgxs.xml file was specified in &
|
||||
&settings.xml or in the OPENMC_MG_CROSS_SECTIONS environment &
|
||||
&variable. OpenMC needs such a file to identify where to &
|
||||
&find the cross section libraries. Please consult the user's &
|
||||
|
|
@ -4537,24 +4537,24 @@ contains
|
|||
subroutine read_mg_cross_sections_xml()
|
||||
|
||||
integer :: i ! loop index
|
||||
logical :: file_exists ! does cross_sections.xml exist?
|
||||
logical :: file_exists ! does mgxs.xml exist?
|
||||
type(XsListing), pointer :: listing => null()
|
||||
type(Node), pointer :: doc => null()
|
||||
type(Node), pointer :: node_xsdata => null()
|
||||
type(NodeList), pointer :: node_xsdata_list => null()
|
||||
real(8), allocatable :: rev_energy_bins(:)
|
||||
|
||||
! Check if cross_sections.xml exists
|
||||
! Check if mgxs.xml exists
|
||||
inquire(FILE=path_cross_sections, EXIST=file_exists)
|
||||
if (.not. file_exists) then
|
||||
! Could not find cross_sections.xml file
|
||||
! Could not find mgxs.xml file
|
||||
call fatal_error("Cross sections XML file '" &
|
||||
// trim(path_cross_sections) // "' does not exist!")
|
||||
end if
|
||||
|
||||
call write_message("Reading cross sections XML file...", 5)
|
||||
|
||||
! Parse cross_sections.xml file
|
||||
! Parse mgxs.xml file
|
||||
call open_xmldoc(doc, path_cross_sections)
|
||||
|
||||
if (check_for_node(doc, "groups")) then
|
||||
|
|
@ -4602,7 +4602,7 @@ contains
|
|||
! Allocate xs_listings array
|
||||
if (n_listings == 0) then
|
||||
call fatal_error("At least one <xsdata> element must be present in &
|
||||
&cross_sections.xml file!")
|
||||
&mgxs.xml file!")
|
||||
else
|
||||
allocate(xs_listings(n_listings))
|
||||
end if
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue