mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Merge pull request #643 from nelsonag/mgxs_integration
Integrated generation of Multi-Group Cross Section libraries with openmc.mgxs.Library
This commit is contained in:
commit
2c4e1ed1f2
13 changed files with 2585 additions and 268 deletions
1461
docs/source/pythonapi/examples/mgxs-part-iv.ipynb
Normal file
1461
docs/source/pythonapi/examples/mgxs-part-iv.ipynb
Normal file
File diff suppressed because one or more lines are too long
13
docs/source/pythonapi/examples/mgxs-part-iv.rst
Normal file
13
docs/source/pythonapi/examples/mgxs-part-iv.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.. _notebook_mgxs_part_iv:
|
||||
|
||||
====================================================
|
||||
MGXS Part IV: Multi-Group Mode Cross-Section Library
|
||||
====================================================
|
||||
|
||||
.. only:: html
|
||||
|
||||
.. notebook:: mgxs-part-iv.ipynb
|
||||
|
||||
.. only:: latex
|
||||
|
||||
IPython notebooks must be viewed in the online HTML documentation.
|
||||
|
|
@ -26,6 +26,7 @@ Example Jupyter Notebooks
|
|||
examples/mgxs-part-i
|
||||
examples/mgxs-part-ii
|
||||
examples/mgxs-part-iii
|
||||
examples/mgxs-part-iv
|
||||
|
||||
------------------------------------
|
||||
:mod:`openmc` -- Basic Functionality
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -22,9 +22,9 @@ 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_,
|
||||
group_structure_, and inverse_velocities_ elements.
|
||||
|
|
@ -33,7 +33,7 @@ The actual multi-group data itself is contained within the xsdata_ element.
|
|||
.. _groups:
|
||||
|
||||
``<groups>`` Element
|
||||
----------------------------------
|
||||
--------------------
|
||||
|
||||
The ``<groups>`` element has no attributes and simply provides the number of
|
||||
energy groups contained within the library.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import numpy as np
|
||||
import openmc
|
||||
import openmc.mgxs
|
||||
|
||||
|
|
@ -12,7 +11,7 @@ inactive = 10
|
|||
particles = 1000
|
||||
|
||||
###############################################################################
|
||||
# Exporting to OpenMC mg_cross_sections.xml file
|
||||
# Exporting to OpenMC mgxs.xml file
|
||||
###############################################################################
|
||||
|
||||
# Instantiate the energy group data
|
||||
|
|
@ -22,45 +21,43 @@ groups = openmc.mgxs.EnergyGroups(group_edges=[1E-11, 0.0635E-6, 10.0E-6,
|
|||
# Instantiate the 7-group (C5G7) cross section data
|
||||
uo2_xsdata = openmc.XSdata('UO2.300K', groups)
|
||||
uo2_xsdata.order = 0
|
||||
uo2_xsdata.total = np.array([0.1779492, 0.3298048, 0.4803882, 0.5543674,
|
||||
0.3118013, 0.3951678, 0.5644058])
|
||||
uo2_xsdata.absorption = np.array([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
|
||||
3.0020E-02, 1.1126E-01, 2.8278E-01])
|
||||
scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]
|
||||
uo2_xsdata.scatter = np.array(scatter[:][:])
|
||||
uo2_xsdata.fission = np.array([7.21206E-03, 8.19301E-04, 6.45320E-03,
|
||||
1.85648E-02, 1.78084E-02, 8.30348E-02,
|
||||
2.16004E-01])
|
||||
uo2_xsdata.nu_fission = np.array([2.005998E-02, 2.027303E-03, 1.570599E-02,
|
||||
4.518301E-02, 4.334208E-02, 2.020901E-01,
|
||||
5.257105E-01])
|
||||
uo2_xsdata.chi = np.array([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07,
|
||||
0.0000E+00, 0.0000E+00, 0.0000E+00])
|
||||
uo2_xsdata.total = [0.1779492, 0.3298048, 0.4803882, 0.5543674,
|
||||
0.3118013, 0.3951678, 0.5644058]
|
||||
uo2_xsdata.absorption = [8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
|
||||
3.0020E-02, 1.1126E-01, 2.8278E-01]
|
||||
uo2_xsdata.scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]
|
||||
uo2_xsdata.fission = [7.21206E-03, 8.19301E-04, 6.45320E-03,
|
||||
1.85648E-02, 1.78084E-02, 8.30348E-02,
|
||||
2.16004E-01]
|
||||
uo2_xsdata.nu_fission = [2.005998E-02, 2.027303E-03, 1.570599E-02,
|
||||
4.518301E-02, 4.334208E-02, 2.020901E-01,
|
||||
5.257105E-01]
|
||||
uo2_xsdata.chi = [5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07,
|
||||
0.0000E+00, 0.0000E+00, 0.0000E+00]
|
||||
|
||||
h2o_xsdata = openmc.XSdata('LWTR.300K', groups)
|
||||
h2o_xsdata.order = 0
|
||||
h2o_xsdata.total = np.array([0.15920605, 0.412969593, 0.59030986, 0.58435,
|
||||
0.718, 1.2544497, 2.650379])
|
||||
h2o_xsdata.absorption = np.array([6.0105E-04, 1.5793E-05, 3.3716E-04,
|
||||
1.9406E-03, 5.7416E-03, 1.5001E-02,
|
||||
3.7239E-02])
|
||||
scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
|
||||
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]
|
||||
h2o_xsdata.scatter = np.array(scatter)
|
||||
h2o_xsdata.total = [0.15920605, 0.412969593, 0.59030986, 0.58435,
|
||||
0.718, 1.2544497, 2.650379]
|
||||
h2o_xsdata.absorption = [6.0105E-04, 1.5793E-05, 3.3716E-04,
|
||||
1.9406E-03, 5.7416E-03, 1.5001E-02,
|
||||
3.7239E-02]
|
||||
h2o_xsdata.scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
|
||||
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]
|
||||
|
||||
mg_cross_sections_file = openmc.MGXSLibrary(groups)
|
||||
mg_cross_sections_file.add_xsdatas([uo2_xsdata,h2o_xsdata])
|
||||
mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata])
|
||||
mg_cross_sections_file.export_to_xml()
|
||||
|
||||
|
||||
|
|
@ -134,7 +131,7 @@ geometry.export_to_xml()
|
|||
# Instantiate a Settings object, set all runtime parameters, and export to XML
|
||||
settings_file = openmc.Settings()
|
||||
settings_file.energy_mode = "multi-group"
|
||||
settings_file.cross_sections = "./mg_cross_sections.xml"
|
||||
settings_file.cross_sections = "./mgxs.xml"
|
||||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import pickle
|
|||
import warnings
|
||||
from numbers import Integral
|
||||
from collections import OrderedDict
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.mgxs
|
||||
|
|
@ -254,7 +257,7 @@ 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, openmc.mgxs.DOMAIN_TYPES)
|
||||
self._domain_type = domain_type
|
||||
|
||||
@domains.setter
|
||||
|
|
@ -386,7 +389,7 @@ 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.
|
||||
|
|
@ -433,6 +436,7 @@ class Library(object):
|
|||
|
||||
self._sp_filename = statepoint._f.filename
|
||||
self._openmc_geometry = statepoint.summary.openmc_geometry
|
||||
self._nuclides = statepoint.summary.nuclides
|
||||
|
||||
if statepoint.run_mode == 'k-eigenvalue':
|
||||
self._keff = statepoint.k_combined[0]
|
||||
|
|
@ -456,7 +460,7 @@ class Library(object):
|
|||
----------
|
||||
domain : Material or Cell or Universe or Integral
|
||||
The material, cell, or universe object of interest (or its ID)
|
||||
mgxs_type : {'total', 'transport', 'absorption', 'capture', 'fission', 'nu-fission', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'chi'}
|
||||
mgxs_type : {'total', 'transport', 'nu-transport', 'absorption', 'capture', 'fission', 'nu-fission', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'chi'}
|
||||
The type of multi-group cross section object to return
|
||||
|
||||
Returns
|
||||
|
|
@ -486,7 +490,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:
|
||||
|
|
@ -670,7 +674,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
|
||||
|
|
@ -747,3 +751,395 @@ class Library(object):
|
|||
|
||||
# Load and return pickled Library object
|
||||
return pickle.load(open(full_filename, 'rb'))
|
||||
|
||||
def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro',
|
||||
xs_id='1m', order=None):
|
||||
"""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
|
||||
xsdata_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 data entry. Default is None,
|
||||
which will set the XSdata object to use the order of the
|
||||
Library.
|
||||
|
||||
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('xsdata_name', xsdata_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, (type(None), Integral))
|
||||
if order is not None:
|
||||
cv.check_greater_than('order', order, 0, equality=True)
|
||||
cv.check_less_than('order', order, 10, 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 = xsdata_name
|
||||
if nuclide is not 'total':
|
||||
name += '_' + nuclide
|
||||
name += '.' + xs_id
|
||||
xsdata = openmc.XSdata(name, self.energy_groups)
|
||||
|
||||
if order is None:
|
||||
# Set the order to the Library's order (the defualt behavior)
|
||||
xsdata.order = self.legendre_order
|
||||
else:
|
||||
# Set the order of the xsdata object to the minimum of
|
||||
# the provided order or the Library's order.
|
||||
xsdata.order = min(order, self.legendre_order)
|
||||
|
||||
if nuclide is not 'total':
|
||||
xsdata.zaid = self._nuclides[nuclide][0]
|
||||
xsdata.awr = self._nuclides[nuclide][1]
|
||||
|
||||
# Now get xs data itself
|
||||
if 'nu-transport' in self.mgxs_types and self.correction == 'P0':
|
||||
mymgxs = self.get_mgxs(domain, 'nu-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', xsdata_names=None,
|
||||
xs_ids=None):
|
||||
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
|
||||
Multi-Group mode of OpenMC.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
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.
|
||||
xsdata_names : Iterable of str
|
||||
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'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mgxs_file : openmc.MGXSLibrary
|
||||
Multi-Group Cross Section File that is ready to be printed to the
|
||||
file of choice by the user.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the Library object is initialized with insufficient types of
|
||||
cross sections for the Library.
|
||||
|
||||
See also
|
||||
--------
|
||||
Library.dump_to_file()
|
||||
|
||||
"""
|
||||
|
||||
# Check to ensure the Library contains the correct
|
||||
# multi-group cross section types
|
||||
self.check_library_for_openmc_mgxs()
|
||||
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
if xsdata_names is not None:
|
||||
cv.check_iterable_type('xsdata_names', xsdata_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
|
||||
# of strings.
|
||||
xs_ids = [xs_ids for i in range(len(self.domains))]
|
||||
else:
|
||||
cv.check_iterable_type('xs_ids', xs_ids, basestring)
|
||||
else:
|
||||
xs_ids = ['1m' for i in range(len(self.domains))]
|
||||
|
||||
# If gathering material-specific data, set the xs_type to macro
|
||||
if not self.by_nuclide:
|
||||
xs_type = 'macro'
|
||||
|
||||
# Initialize file
|
||||
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
|
||||
|
||||
# Create the xsdata object and add it to the mgxs_file
|
||||
for i, domain in enumerate(self.domains):
|
||||
if self.by_nuclide:
|
||||
nuclides = list(domain.get_all_nuclides().keys())
|
||||
else:
|
||||
nuclides = ['total']
|
||||
for nuclide in nuclides:
|
||||
# Build & add metadata to XSdata object
|
||||
if xsdata_names is None:
|
||||
xsdata_name = 'set' + str(i + 1)
|
||||
else:
|
||||
xsdata_name = xsdata_names[i]
|
||||
if nuclide is not 'total':
|
||||
xsdata_name += '_' + nuclide
|
||||
|
||||
xsdata = self.get_xsdata(domain, xsdata_name, nuclide=nuclide,
|
||||
xs_type=xs_type, xs_id=xs_ids[i])
|
||||
|
||||
mgxs_file.add_xsdata(xsdata)
|
||||
|
||||
return mgxs_file
|
||||
|
||||
def create_mg_library_and_materials(self, xsdata_names=None, xs_ids=None,
|
||||
material_ids=None):
|
||||
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
|
||||
Multi-Group mode of OpenMC as well as the associated openmc.Materials
|
||||
objects. This method cannot be used for Library objects with
|
||||
`Library.by_nuclide == True` since the materials to output would be
|
||||
problem dependent and thus any Materials object produced by this method
|
||||
would not be useful.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xsdata_names : Iterable of str
|
||||
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'.
|
||||
material_ids : None or Iterable of Integral
|
||||
An optional list of material IDs to pass to the materials in
|
||||
materials_file. Defaults to `None` implying the materials will be
|
||||
given an ID number which matches the index of the domain in
|
||||
`self.domains`
|
||||
|
||||
Returns
|
||||
-------
|
||||
mgxs_file : openmc.MGXSLibrary
|
||||
Multi-Group Cross Section File that is ready to be printed to the
|
||||
file of choice by the user.
|
||||
materials_file : openmc.Materials
|
||||
Materials file ready to be printed with all the macroscopic data
|
||||
present within this Library.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the Library object is initialized with insufficient types of
|
||||
cross sections for the Library.
|
||||
|
||||
See also
|
||||
--------
|
||||
Library.create_mg_library()
|
||||
Library.dump_to_file()
|
||||
|
||||
"""
|
||||
|
||||
# Check to ensure the Library contains the correct
|
||||
# multi-group cross section types
|
||||
self.check_library_for_openmc_mgxs()
|
||||
|
||||
if xsdata_names is not None:
|
||||
cv.check_iterable_type('xsdata_names', xsdata_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
|
||||
# of strings.
|
||||
xs_ids = [xs_ids for i in range(len(self.domains))]
|
||||
else:
|
||||
cv.check_iterable_type('xs_ids', xs_ids, basestring)
|
||||
else:
|
||||
xs_ids = ['1m' for i in range(len(self.domains))]
|
||||
if material_ids is not None:
|
||||
cv.check_iterable_type('material_ids', material_ids, Integral)
|
||||
xs_type = 'macro'
|
||||
|
||||
# Initialize files
|
||||
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
|
||||
|
||||
materials = []
|
||||
macroscopics = []
|
||||
nuclide = 'total'
|
||||
# Create the xsdata object and add it to the mgxs_file
|
||||
for i, domain in enumerate(self.domains):
|
||||
# Build & add metadata to XSdata object
|
||||
if xsdata_names is None:
|
||||
xsdata_name = 'set' + str(i + 1)
|
||||
else:
|
||||
xsdata_name = xsdata_names[i]
|
||||
|
||||
xsdata = self.get_xsdata(domain, xsdata_name, nuclide=nuclide,
|
||||
xs_type=xs_type, xs_id=xs_ids[i])
|
||||
|
||||
mgxs_file.add_xsdata(xsdata)
|
||||
|
||||
macroscopics.append(openmc.Macroscopic(name=xsdata_name,
|
||||
xs=xs_ids[i]))
|
||||
if material_ids is not None:
|
||||
mat_id = material_ids[i]
|
||||
else:
|
||||
mat_id = i
|
||||
materials.append(openmc.Material(name=xsdata_name + '.' +
|
||||
xs_ids[i], material_id=mat_id))
|
||||
materials[-1].add_macroscopic(macroscopics[-1])
|
||||
|
||||
materials_file = openmc.Materials(materials)
|
||||
|
||||
return (mgxs_file, materials_file)
|
||||
|
||||
def check_library_for_openmc_mgxs(self):
|
||||
"""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
|
||||
use whatever corresponds to Library.correction (if P0: transport)
|
||||
|
||||
- Absorption and total (or transport) are required.
|
||||
- A nu-fission cross section and chi values are not required as a
|
||||
fixed source problem could be the target.
|
||||
- Fission and kappa-fission are not required as they are only
|
||||
needed to support tallies the user may wish to request.
|
||||
- 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)
|
||||
|
||||
See also
|
||||
--------
|
||||
Library.create_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
|
||||
('nu-transport' not in self.mgxs_types))):
|
||||
error_flag = True
|
||||
msg = 'A "nu-transport" MGXS type is required since a "P0" ' \
|
||||
'correction is applied, but a "nu-transport" MGXS is ' \
|
||||
'not provided.'
|
||||
warn(msg)
|
||||
elif (((self.correction is None) and
|
||||
('total' not in self.mgxs_types))):
|
||||
error_flag = True
|
||||
msg = '"total" MGXS type is required, but not provided.'
|
||||
warn(msg)
|
||||
|
||||
if error_flag:
|
||||
msg = 'Invalid MGXS configuration encountered.'
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ class MGXS(object):
|
|||
|
||||
@domain_type.setter
|
||||
def domain_type(self, domain_type):
|
||||
cv.check_value('domain type', domain_type, tuple(DOMAIN_TYPES))
|
||||
cv.check_value('domain type', domain_type, DOMAIN_TYPES)
|
||||
self._domain_type = domain_type
|
||||
|
||||
@energy_groups.setter
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -70,9 +70,10 @@ class Settings(object):
|
|||
deviation.
|
||||
cross_sections : str
|
||||
Indicates the path to an XML cross section listing file (usually named
|
||||
cross_sections.xml). If it is not set, the :envvar:`CROSS_SECTIONS`
|
||||
environment variable will be used for continuous-energy calculations
|
||||
and :envvar:`MG_CROSS_SECTIONS` will be used for multi-group
|
||||
cross_sections.xml). If it is not set, the
|
||||
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for
|
||||
continuous-energy calculations and
|
||||
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
|
||||
calculations to find the path to the XML cross section file.
|
||||
energy_grid : {'nuclide', 'logarithm', 'material-union'}
|
||||
Set the method used to search energy grids.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ class Summary(object):
|
|||
self._opencg_geometry = None
|
||||
|
||||
self._read_metadata()
|
||||
self._read_nuclides()
|
||||
self._read_geometry()
|
||||
self._read_tallies()
|
||||
self._f.close()
|
||||
|
||||
@property
|
||||
def openmc_geometry(self):
|
||||
|
|
@ -55,8 +57,8 @@ class Summary(object):
|
|||
def _read_metadata(self):
|
||||
# Read OpenMC version
|
||||
self.version = [self._f['version_major'].value,
|
||||
self._f['version_minor'].value,
|
||||
self._f['version_release'].value]
|
||||
self._f['version_minor'].value,
|
||||
self._f['version_release'].value]
|
||||
# Read date and time
|
||||
self.date_and_time = self._f['date_and_time'][...]
|
||||
|
||||
|
|
@ -71,6 +73,17 @@ class Summary(object):
|
|||
self.gen_per_batch = self._f['gen_per_batch'].value
|
||||
self.n_procs = self._f['n_procs'].value
|
||||
|
||||
def _read_nuclides(self):
|
||||
self.nuclides = {}
|
||||
n_nuclides = self._f['nuclides/n_nuclides_total'].value
|
||||
names = self._f['nuclides/names'].value
|
||||
awrs = self._f['nuclides/awrs'].value
|
||||
zaids = self._f['nuclides/zaids'].value
|
||||
for n in range(n_nuclides):
|
||||
name = names[n].decode()
|
||||
name = name[:name.find('.')]
|
||||
self.nuclides[name] = (zaids[n], awrs[n])
|
||||
|
||||
def _read_geometry(self):
|
||||
# Read in and initialize the Materials and Geometry
|
||||
self._read_materials()
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
|
|
@ -4523,24 +4523,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
|
||||
|
|
@ -4588,7 +4588,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
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ contains
|
|||
"description", "Number of generations per batch")
|
||||
end if
|
||||
|
||||
call write_nuclides(file_id)
|
||||
call write_geometry(file_id)
|
||||
call write_materials(file_id)
|
||||
if (n_tallies > 0) then
|
||||
|
|
@ -105,6 +106,49 @@ contains
|
|||
|
||||
end subroutine write_header
|
||||
|
||||
!===============================================================================
|
||||
! WRITE_NUCLIDES
|
||||
!===============================================================================
|
||||
|
||||
subroutine write_nuclides(file_id)
|
||||
integer(HID_T), intent(in) :: file_id
|
||||
integer(HID_T) :: nuclide_group
|
||||
integer :: i
|
||||
character(12), allocatable :: nucnames(:)
|
||||
real(8), allocatable :: awrs(:)
|
||||
integer, allocatable :: zaids(:)
|
||||
|
||||
! Write useful data from nuclide objects
|
||||
nuclide_group = create_group(file_id, "nuclides")
|
||||
call write_dataset(nuclide_group, "n_nuclides_total", n_nuclides_total)
|
||||
|
||||
! Build array of nuclide names, awrs, and zaids
|
||||
allocate(nucnames(n_nuclides_total))
|
||||
allocate(awrs(n_nuclides_total))
|
||||
allocate(zaids(n_nuclides_total))
|
||||
do i = 1, n_nuclides_total
|
||||
if (run_CE) then
|
||||
nucnames(i) = xs_listings(nuclides(i) % listing) % alias
|
||||
awrs(i) = nuclides(i) % awr
|
||||
zaids(i) = nuclides(i) % zaid
|
||||
else
|
||||
nucnames(i) = xs_listings(nuclides_MG(i) % obj % listing) % alias
|
||||
awrs(i) = nuclides_MG(i) % obj % awr
|
||||
zaids(i) = nuclides_MG(i) % obj % zaid
|
||||
end if
|
||||
end do
|
||||
|
||||
! Write nuclide names, awrs and zaids
|
||||
call write_dataset(nuclide_group, "names", nucnames)
|
||||
call write_dataset(nuclide_group, "awrs", awrs)
|
||||
call write_dataset(nuclide_group, "zaids", zaids)
|
||||
|
||||
call close_group(nuclide_group)
|
||||
|
||||
deallocate(nucnames, awrs, zaids)
|
||||
|
||||
end subroutine write_nuclides
|
||||
|
||||
!===============================================================================
|
||||
! WRITE_GEOMETRY
|
||||
!===============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue