mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
Implemented new openmc.mgxs.Library class
This commit is contained in:
parent
41a9ede627
commit
32f67d3d0a
5 changed files with 692 additions and 53 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +1,3 @@
|
|||
from groups import EnergyGroups
|
||||
from mgxs import *
|
||||
from library import Library
|
||||
from mgxs import *
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from collections import Iterable
|
||||
from numbers import Real, Integral
|
||||
from numbers import Real
|
||||
import copy
|
||||
import sys
|
||||
|
||||
|
|
|
|||
286
openmc/mgxs/library.py
Normal file
286
openmc/mgxs/library.py
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
import sys
|
||||
import copy
|
||||
from numbers import Integral
|
||||
|
||||
import openmc
|
||||
import openmc.mgxs
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Library(object):
|
||||
|
||||
def __init__(self, openmc_geometry, by_nuclide=False,
|
||||
mgxs_types=None, name=''):
|
||||
|
||||
self._name = ''
|
||||
self._openmc_geometry = None
|
||||
self._by_nuclide = None
|
||||
self._mgxs_types = []
|
||||
self._domain_type = None
|
||||
self._energy_groups = None
|
||||
self._all_mgxs = {}
|
||||
|
||||
self.name = name
|
||||
self.openmc_geometry = openmc_geometry
|
||||
self.by_nuclide = by_nuclide
|
||||
|
||||
if mgxs_types is not None:
|
||||
self.mgxs_types = mgxs_types
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
existing = memo.get(id(self))
|
||||
|
||||
# If this is the first time we have tried to copy this object, copy it
|
||||
if existing is None:
|
||||
clone = type(self).__new__(type(self))
|
||||
clone._name = self.name
|
||||
clone._openmc_geometry = self.openmc_geometry
|
||||
clone._by_nuclide = self.by_nuclide
|
||||
clone._mgxs_types = self.mgxs_types
|
||||
clone._domain_type = self.domain_type
|
||||
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
|
||||
clone._all_mgxs = self.all_mgxs
|
||||
|
||||
clone._all_mgxs = {}
|
||||
for domain in self.domains:
|
||||
clone.all_mgxs[domain.id] = {}
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = copy.deepcopy(self.all_mgxs[domain.id][mgxs_type])
|
||||
clone.all_mgxs[domain.id][mgxs_type] = mgxs
|
||||
|
||||
memo[id(self)] = clone
|
||||
|
||||
return clone
|
||||
|
||||
# If this object has been copied before, return the first copy made
|
||||
else:
|
||||
return existing
|
||||
|
||||
@property
|
||||
def openmc_geometry(self):
|
||||
return self._openmc_geometry
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def mgxs_types(self):
|
||||
return self._mgxs_types
|
||||
|
||||
@property
|
||||
def by_nuclide(self):
|
||||
return self._by_nuclide
|
||||
|
||||
@property
|
||||
def domains(self):
|
||||
if self.domain_type is None:
|
||||
raise ValueError('Unable to get all domains without a domain type')
|
||||
|
||||
if self.domain_type == 'material':
|
||||
return self.openmc_geometry.get_all_materials()
|
||||
elif self.domain_type == 'cell' or self.domain_type == 'distribcell':
|
||||
return self.openmc_geometry.get_all_material_cells()
|
||||
elif self.domain_type == 'universe':
|
||||
return self.openmc_geometry.get_all_universes()
|
||||
|
||||
@property
|
||||
def domain_type(self):
|
||||
return self._domain_type
|
||||
|
||||
@property
|
||||
def energy_groups(self):
|
||||
return self._energy_groups
|
||||
|
||||
@property
|
||||
def num_groups(self):
|
||||
return self.energy_groups.num_groups
|
||||
|
||||
@property
|
||||
def all_mgxs(self):
|
||||
return self._all_mgxs
|
||||
|
||||
@openmc_geometry.setter
|
||||
def openmc_geometry(self, openmc_geometry):
|
||||
cv.check_type('openmc_geometry', openmc_geometry, openmc.Geometry)
|
||||
self._openmc_geometry = openmc_geometry
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@mgxs_types.setter
|
||||
def mgxs_types(self, mgxs_types):
|
||||
if mgxs_types == 'all':
|
||||
self._mgxs_types = openmc.mgxs.MGXS_TYPES
|
||||
else:
|
||||
cv.check_iterable_type('mgxs_types', mgxs_types, basestring)
|
||||
for mgxs_type in mgxs_types:
|
||||
cv.check_value('mgxs_type', mgxs_type, openmc.mgxs.MGXS_TYPES)
|
||||
self._mgxs_types = mgxs_types
|
||||
|
||||
@by_nuclide.setter
|
||||
def by_nuclide(self, by_nuclide):
|
||||
cv.check_type('by_nuclide', by_nuclide, bool)
|
||||
self._by_nuclide = by_nuclide
|
||||
|
||||
@domain_type.setter
|
||||
def domain_type(self, domain_type):
|
||||
cv.check_value('domain type', domain_type, tuple(openmc.mgxs.DOMAIN_TYPES))
|
||||
self._domain_type = domain_type
|
||||
|
||||
@energy_groups.setter
|
||||
def energy_groups(self, energy_groups):
|
||||
cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups)
|
||||
self._energy_groups = energy_groups
|
||||
|
||||
def build_library(self):
|
||||
"""
|
||||
"""
|
||||
|
||||
# Initialize MGXS for each domain and mgxs type and store in dictionary
|
||||
for domain in self.domains:
|
||||
self.all_mgxs[domain.id] = {}
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = openmc.mgxs.MGXS.get_mgxs(mgxs_type, name=self.name)
|
||||
mgxs.domain = domain
|
||||
mgxs.domain_type = self.domain_type
|
||||
mgxs.energy_groups = self.energy_groups
|
||||
mgxs.by_nuclide = self.by_nuclide
|
||||
mgxs.create_tallies()
|
||||
self.all_mgxs[domain.id][mgxs_type] = mgxs
|
||||
|
||||
def add_to_tallies_file(self, tallies_file):
|
||||
"""
|
||||
|
||||
NOTE: This assumes that build_library() has been called
|
||||
|
||||
:param tallies_file:
|
||||
:return:
|
||||
"""
|
||||
|
||||
cv.check_type('tallies_file', tallies_file, openmc.TalliesFile)
|
||||
|
||||
# Add tallies from each MGXS for each domain and mgxs type
|
||||
for domain in self.domains:
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = self.get_mgxs(domain, mgxs_type)
|
||||
for tally_id, tally in mgxs.tallies.items():
|
||||
tallies_file.add_tally(tally, merge=True)
|
||||
|
||||
def load_from_statepoint(self, statepoint):
|
||||
"""
|
||||
|
||||
:param statepoint:
|
||||
:return:
|
||||
"""
|
||||
|
||||
cv.check_type('statepoint', statepoint, openmc.StatePoint)
|
||||
|
||||
# Load tallies for each MGXS for each domain and mgxs type
|
||||
for domain in self.domains:
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = self.get_mgxs(domain, mgxs_type)
|
||||
mgxs.load_from_statepoint(statepoint)
|
||||
mgxs.compute_xs()
|
||||
|
||||
def get_mgxs(self, domain, mgxs_type):
|
||||
"""
|
||||
|
||||
:param domain:
|
||||
:param mgxs_type:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if self.domain_type == 'material':
|
||||
cv.check_type('domain', domain, (openmc.Material, Integral))
|
||||
elif self.domain_type == 'cell' or self.domain_type == 'distribcell':
|
||||
cv.check_type('domain', domain, (openmc.Cell, Integral))
|
||||
elif self.domain_type == 'universe':
|
||||
cv.check_type('domain', domain, (openmc.Universe, Integral))
|
||||
|
||||
# Check that requested domain is included in library
|
||||
if cv._isinstance(domain, Integral):
|
||||
domain_id = domain
|
||||
for domain in self.domains:
|
||||
if domain_id == domain.id:
|
||||
break
|
||||
else:
|
||||
msg = 'Unable to find MGXS for {0} "{1}" in ' \
|
||||
'library'.format(self.domain_type, domain)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
domain_id = domain.id
|
||||
|
||||
# Check that requested domain is included in library
|
||||
if mgxs_type not in self.mgxs_types:
|
||||
msg = 'Unable to find MGXS type "{0}"'.format(mgxs_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
return self.all_mgxs[domain_id][mgxs_type]
|
||||
|
||||
def get_condensed_library(self, coarse_groups):
|
||||
"""
|
||||
|
||||
:param coarse_groups:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if self.energy_groups is None:
|
||||
msg = 'Unable to get a condensed coarse group cross section ' \
|
||||
'library since the fine energy groups have not yet been set'
|
||||
raise ValueError(msg)
|
||||
|
||||
cv.check_type('coarse_groups', coarse_groups, openmc.mgxs.EnergyGroups)
|
||||
cv.check_less_than('coarse groups', coarse_groups.num_groups,
|
||||
self.num_groups, equality=True)
|
||||
cv.check_value('upper coarse energy', coarse_groups.group_edges[-1],
|
||||
[self.energy_groups.group_edges[-1]])
|
||||
cv.check_value('lower coarse energy', coarse_groups.group_edges[0],
|
||||
[self.energy_groups.group_edges[0]])
|
||||
|
||||
# Clone this Library to initialize the condensed version
|
||||
condensed_library = copy.deepcopy(self)
|
||||
condensed_library.energy_groups = coarse_groups
|
||||
|
||||
# Condense the MGXS for each domain and mgxs type
|
||||
for domain in self.domains:
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = condensed_library.get_mgxs(domain, mgxs_type)
|
||||
condensed_mgxs = mgxs.get_condensed_xs(coarse_groups)
|
||||
condensed_library.all_mgxs[domain.id][mgxs_type] = condensed_mgxs
|
||||
|
||||
return condensed_library
|
||||
|
||||
def build_hdf5_store(self, filename='mgxs', directory='mgxs', xs_type='macro'):
|
||||
"""Export the multi-group cross section library to an HDF5 binary file.
|
||||
|
||||
This method constructs an HDF5 file which stores the multi-group
|
||||
cross section data. The data is stored in a hierarchy of HDF5 groups
|
||||
from the domain type, domain id, subdomain id (for distribcell domains),
|
||||
nuclides and cross section types. Two datasets for the mean and standard
|
||||
deviation are stored for each subdomain entry in the HDF5 file.
|
||||
|
||||
NOTE: This requires the h5py Python package.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Filename for the HDF5 file (default is 'mgxs')
|
||||
directory : str
|
||||
Directory for the HDF5 file (default is 'mgxs')
|
||||
xs_type: {'macro', 'micro'}
|
||||
Store the macro or micro cross section in units of cm^-1 or barns
|
||||
|
||||
"""
|
||||
|
||||
# Load tallies for each MGXS for each domain and mgxs type
|
||||
for domain in self.domains:
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = self.all_mgxs[domain.id][mgxs_type]
|
||||
mgxs.build_hdf5_store(filename, directory, xs_type)
|
||||
|
|
@ -32,7 +32,7 @@ MGXS_TYPES = ['total',
|
|||
|
||||
# Supported domain types
|
||||
# TODO: Implement Mesh domains
|
||||
_DOMAIN_TYPES = ['cell',
|
||||
DOMAIN_TYPES = ['cell',
|
||||
'distribcell',
|
||||
'universe',
|
||||
'material']
|
||||
|
|
@ -80,8 +80,6 @@ class MGXS(object):
|
|||
Domain type for spatial homogenization
|
||||
energy_groups : EnergyGroups
|
||||
Energy group structure for energy condensation
|
||||
num_groups : Integral
|
||||
Number of energy groups
|
||||
tallies : dict
|
||||
OpenMC tallies needed to compute the multi-group cross section
|
||||
xs_tally : Tally
|
||||
|
|
@ -102,8 +100,7 @@ class MGXS(object):
|
|||
self._domain = None
|
||||
self._domain_type = None
|
||||
self._energy_groups = None
|
||||
self._num_groups = None
|
||||
self._tallies = dict()
|
||||
self._tallies = {}
|
||||
self._xs_tally = None
|
||||
|
||||
self.name = name
|
||||
|
|
@ -128,10 +125,9 @@ class MGXS(object):
|
|||
clone._domain = self.domain
|
||||
clone._domain_type = self.domain_type
|
||||
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
|
||||
clone._num_groups = self.num_groups
|
||||
clone._xs_tally = copy.deepcopy(self.xs_tally, memo)
|
||||
|
||||
clone._tallies = dict()
|
||||
clone._tallies = {}
|
||||
for tally_type, tally in self.tallies.items():
|
||||
clone.tallies[tally_type] = copy.deepcopy(tally, memo)
|
||||
|
||||
|
|
@ -169,7 +165,7 @@ class MGXS(object):
|
|||
|
||||
@property
|
||||
def num_groups(self):
|
||||
return self._num_groups
|
||||
return self.energy_groups.num_groups
|
||||
|
||||
@property
|
||||
def tallies(self):
|
||||
|
|
@ -185,16 +181,6 @@ class MGXS(object):
|
|||
domain_filter = tally.find_filter(self.domain_type)
|
||||
return domain_filter.num_bins
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@by_nuclide.setter
|
||||
def by_nuclide(self, by_nuclide):
|
||||
cv.check_type('by_nuclide', by_nuclide, bool)
|
||||
self._by_nuclide = by_nuclide
|
||||
|
||||
@property
|
||||
def num_nuclides(self):
|
||||
if self.by_nuclide:
|
||||
|
|
@ -209,6 +195,16 @@ class MGXS(object):
|
|||
else:
|
||||
return 'sum'
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@by_nuclide.setter
|
||||
def by_nuclide(self, by_nuclide):
|
||||
cv.check_type('by_nuclide', by_nuclide, bool)
|
||||
self._by_nuclide = by_nuclide
|
||||
|
||||
@domain.setter
|
||||
def domain(self, domain):
|
||||
cv.check_type('domain', domain, tuple(_DOMAINS))
|
||||
|
|
@ -216,14 +212,13 @@ 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, tuple(DOMAIN_TYPES))
|
||||
self._domain_type = domain_type
|
||||
|
||||
@energy_groups.setter
|
||||
def energy_groups(self, energy_groups):
|
||||
cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups)
|
||||
self._energy_groups = energy_groups
|
||||
self._num_groups = energy_groups.num_groups
|
||||
|
||||
@staticmethod
|
||||
def get_mgxs(mgxs_type, domain=None, domain_type=None,
|
||||
|
|
@ -295,7 +290,7 @@ class MGXS(object):
|
|||
Returns
|
||||
-------
|
||||
list of str
|
||||
A list of the string names for each nuclide in the problem domain
|
||||
A list of the string names for each nuclide in the spatial domain
|
||||
(e.g., ['U-235', 'U-238', 'O-16'])
|
||||
|
||||
Raises
|
||||
|
|
@ -362,7 +357,7 @@ class MGXS(object):
|
|||
-------
|
||||
ndarray of Real
|
||||
An array of the atomic number densities (atom/b-cm) for each of the
|
||||
nuclides in the problem domain
|
||||
nuclides in the spatial domain
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue