mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Change how volume is stored
This commit is contained in:
parent
acdf287c01
commit
cfb6339698
6 changed files with 114 additions and 68 deletions
|
|
@ -86,9 +86,9 @@ class Cell(object):
|
|||
distribcell_paths : list of str
|
||||
The paths traversed through the CSG tree to reach each distribcell
|
||||
instance
|
||||
volume_information : dict
|
||||
Estimate of the volume and total number of atoms of each nuclide from a
|
||||
stochastic volume calculation. This information is set with the
|
||||
volume : float
|
||||
Volume of the cell in cm^3. This can either be set manually or
|
||||
calculated in a stochastic volume calculation and added via the
|
||||
:meth:`Cell.add_volume_information` method.
|
||||
|
||||
"""
|
||||
|
|
@ -106,7 +106,8 @@ class Cell(object):
|
|||
self._offsets = None
|
||||
self._distribcell_index = None
|
||||
self._distribcell_paths = None
|
||||
self._volume_information = None
|
||||
self._volume = None
|
||||
self._atoms = None
|
||||
|
||||
def __contains__(self, point):
|
||||
if self.region is None:
|
||||
|
|
@ -224,8 +225,8 @@ class Cell(object):
|
|||
return self._distribcell_paths
|
||||
|
||||
@property
|
||||
def volume_information(self):
|
||||
return self._volume_information
|
||||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@id.setter
|
||||
def id(self, cell_id):
|
||||
|
|
@ -326,6 +327,12 @@ class Cell(object):
|
|||
cv.check_type('cell region', region, Region)
|
||||
self._region = region
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
if volume is not None:
|
||||
cv.check_type('cell volume', volume, Real)
|
||||
self._volume = volume
|
||||
|
||||
@distribcell_index.setter
|
||||
def distribcell_index(self, ind):
|
||||
cv.check_type('distribcell index', ind, Integral)
|
||||
|
|
@ -391,10 +398,9 @@ class Cell(object):
|
|||
|
||||
"""
|
||||
if volume_calc.domain_type == 'cell':
|
||||
for cell_id in volume_calc.results:
|
||||
if cell_id == self.id:
|
||||
self._volume_information = volume_calc.results[cell_id]
|
||||
break
|
||||
if self.id in volume_calc.volumes:
|
||||
self._volume = volume_calc.volumes[self.id][0]
|
||||
self._atoms = volume_calc.atoms[self.id]
|
||||
else:
|
||||
raise ValueError('No volume information found for this cell.')
|
||||
else:
|
||||
|
|
@ -446,9 +452,9 @@ class Cell(object):
|
|||
elif self.fill_type == 'void':
|
||||
pass
|
||||
else:
|
||||
if self.volume_information is not None:
|
||||
volume = self.volume_information['volume'][0]
|
||||
for name, atoms in self.volume_information['atoms']:
|
||||
if self._atoms is not None:
|
||||
volume = self.volume
|
||||
for name, atoms in self._atoms.items():
|
||||
nuclide = openmc.Nuclide(name)
|
||||
density = 1.0e-24 * atoms[0]/volume # density in atoms/b-cm
|
||||
nuclides[name] = (nuclide, density)
|
||||
|
|
|
|||
|
|
@ -61,15 +61,15 @@ class Geometry(object):
|
|||
"""
|
||||
if volume_calc.domain_type == 'cell':
|
||||
for cell in self.get_all_cells():
|
||||
if cell.id in volume_calc.results:
|
||||
if cell.id in volume_calc.volumes:
|
||||
cell.add_volume_information(volume_calc)
|
||||
elif volume_calc.domain_type == 'material':
|
||||
for material in self.get_all_materials():
|
||||
if material.id in volume_calc.results:
|
||||
if material.id in volume_calc.volumes:
|
||||
material.add_volume_information(volume_calc)
|
||||
elif volume_calc.domain_type == 'universe':
|
||||
for universe in self.get_all_universes():
|
||||
if universe.id in volume_calc.results:
|
||||
if universe.id in volume_calc.volumes:
|
||||
universe.add_volume_information(volume_calc)
|
||||
|
||||
def export_to_xml(self, path='geometry.xml'):
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ class Material(object):
|
|||
The average molar mass of nuclides in the material in units of grams per
|
||||
mol. For example, UO2 with 3 nuclides will have an average molar mass
|
||||
of 270 / 3 = 90 g / mol.
|
||||
volume_information : dict
|
||||
Estimate of the volume and total number of atoms of each nuclide from a
|
||||
stochastic volume calculation. This information is set with the
|
||||
volume : float
|
||||
Volume of the material in cm^3. This can either be set manually or
|
||||
calculated in a stochastic volume calculation and added via the
|
||||
:meth:`Material.add_volume_information` method.
|
||||
|
||||
"""
|
||||
|
|
@ -86,7 +86,8 @@ class Material(object):
|
|||
self._density = None
|
||||
self._density_units = ''
|
||||
self._depletable = False
|
||||
self._volume_information = None
|
||||
self._volume = None
|
||||
self._atoms = {}
|
||||
|
||||
# A list of tuples (nuclide, percent, percent type)
|
||||
self._nuclides = []
|
||||
|
|
@ -232,8 +233,8 @@ class Material(object):
|
|||
return mass / moles
|
||||
|
||||
@property
|
||||
def volume_information(self):
|
||||
return self._volume_information
|
||||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@id.setter
|
||||
def id(self, material_id):
|
||||
|
|
@ -268,6 +269,12 @@ class Material(object):
|
|||
depletable, bool)
|
||||
self._depletable = depletable
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
if volume is not None:
|
||||
cv.check_type('material volume', volume, Real)
|
||||
self._volume = volume
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, group):
|
||||
"""Create material from HDF5 group
|
||||
|
|
@ -321,10 +328,9 @@ class Material(object):
|
|||
|
||||
"""
|
||||
if volume_calc.domain_type == 'material':
|
||||
for mat_id in volume_calc.results:
|
||||
if mat_id == self.id:
|
||||
self._volume_information = volume_calc.results[mat_id]
|
||||
break
|
||||
if self.id in volume_calc.volumes:
|
||||
self._volume = volume_calc.volumes[self.id]
|
||||
self._atoms = volume_calc.atoms[self.id]
|
||||
else:
|
||||
raise ValueError('No volume information found for this material.')
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from collections import OrderedDict, Iterable
|
||||
from numbers import Integral
|
||||
from numbers import Integral, Real
|
||||
import random
|
||||
import sys
|
||||
|
||||
|
|
@ -42,9 +42,9 @@ class Universe(object):
|
|||
cells : collections.OrderedDict
|
||||
Dictionary whose keys are cell IDs and values are :class:`Cell`
|
||||
instances
|
||||
volume_information : dict
|
||||
Estimate of the volume and total number of atoms of each nuclide from a
|
||||
stochastic volume calculation. This information is set with the
|
||||
volume : float
|
||||
Volume of the universe in cm^3. This can either be set manually or
|
||||
calculated in a stochastic volume calculation and added via the
|
||||
:meth:`Universe.add_volume_information` method.
|
||||
|
||||
"""
|
||||
|
|
@ -53,7 +53,8 @@ class Universe(object):
|
|||
# Initialize Cell class attributes
|
||||
self.id = universe_id
|
||||
self.name = name
|
||||
self._volume_information = None
|
||||
self._volume = None
|
||||
self._atoms = {}
|
||||
|
||||
# Keys - Cell IDs
|
||||
# Values - Cells
|
||||
|
|
@ -105,8 +106,8 @@ class Universe(object):
|
|||
return self._cells
|
||||
|
||||
@property
|
||||
def volume_information(self):
|
||||
return self._volume_information
|
||||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@id.setter
|
||||
def id(self, universe_id):
|
||||
|
|
@ -127,6 +128,12 @@ class Universe(object):
|
|||
else:
|
||||
self._name = ''
|
||||
|
||||
@volume.setter
|
||||
def volume(self, volume):
|
||||
if volume is not None:
|
||||
cv.check_type('universe volume', volume, Real)
|
||||
self._volume = volume
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, group, cells):
|
||||
"""Create universe from HDF5 group
|
||||
|
|
@ -166,10 +173,9 @@ class Universe(object):
|
|||
|
||||
"""
|
||||
if volume_calc.domain_type == 'cell':
|
||||
for univ_id in volume_calc.results:
|
||||
if univ_id == self.id:
|
||||
self._volume_information = volume_calc.results[univ_id]
|
||||
break
|
||||
if self.id in volume_calc.volumes:
|
||||
self._volume = volume_calc.volumes[self.id]
|
||||
self._atoms = volume_calc.atoms[self.id]
|
||||
else:
|
||||
raise ValueError('No volume information found for this universe.')
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from collections import Iterable, Mapping
|
||||
from collections import Iterable, Mapping, OrderedDict
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
from warnings import warn
|
||||
|
|
@ -43,21 +43,21 @@ class VolumeCalculation(object):
|
|||
Lower-left coordinates of bounding box used to sample points
|
||||
upper_right : Iterable of float
|
||||
Upper-right coordinates of bounding box used to sample points
|
||||
results : dict
|
||||
Dictionary whose keys are unique IDs of domains and values are
|
||||
dictionaries with calculated volumes and total number of atoms for each
|
||||
nuclide present in the domain.
|
||||
volumes : dict
|
||||
Dictionary whose keys are unique IDs of domains and values are the
|
||||
estimated volumes
|
||||
atoms : dict
|
||||
Dictionary mapping unique IDs of domains to a mapping of nuclides to
|
||||
total number of atoms for each nuclide present in the domain. For
|
||||
example, {10: {'U235': 1.0e22, 'U238': 5.0e22, ...}}.
|
||||
atoms_dataframe : pandas.DataFrame
|
||||
DataFrame showing the estimated number of atoms for each nuclide present
|
||||
in each domain specified.
|
||||
volumes : dict
|
||||
Dictionary mapping unique IDs of domains to estimated volumes in cm^3.
|
||||
|
||||
"""
|
||||
def __init__(self, domains, samples, lower_left=None,
|
||||
upper_right=None):
|
||||
self._results = None
|
||||
self._atoms = {}
|
||||
self._volumes = {}
|
||||
|
||||
cv.check_type('domains', domains, Iterable,
|
||||
(openmc.Cell, openmc.Material, openmc.Universe))
|
||||
|
|
@ -122,25 +122,25 @@ class VolumeCalculation(object):
|
|||
def upper_right(self):
|
||||
return self._upper_right
|
||||
|
||||
@property
|
||||
def results(self):
|
||||
return self._results
|
||||
|
||||
@property
|
||||
def domain_type(self):
|
||||
return self._domain_type
|
||||
|
||||
@property
|
||||
def atoms(self):
|
||||
return self._atoms
|
||||
|
||||
@property
|
||||
def volumes(self):
|
||||
return {uid: results['volume'] for uid, results in self.results.items()}
|
||||
return self._volumes
|
||||
|
||||
@property
|
||||
def atoms_dataframe(self):
|
||||
items = []
|
||||
columns = [self.domain_type.capitalize(), 'Nuclide', 'Atoms',
|
||||
'Uncertainty']
|
||||
for uid, results in self.results.items():
|
||||
for name, atoms in results['atoms']:
|
||||
for uid, atoms_dict in self.atoms.items():
|
||||
for name, atoms in atoms_dict.items():
|
||||
items.append((uid, name, atoms[0], atoms[1]))
|
||||
|
||||
return pd.DataFrame.from_records(items, columns=columns)
|
||||
|
|
@ -170,10 +170,15 @@ class VolumeCalculation(object):
|
|||
cv.check_length(name, upper_right, 3)
|
||||
self._upper_right = upper_right
|
||||
|
||||
@results.setter
|
||||
def results(self, results):
|
||||
cv.check_type('results', results, Mapping)
|
||||
self._results = results
|
||||
@volumes.setter
|
||||
def volumes(self, volumes):
|
||||
cv.check_type('volumes', volumes, Mapping)
|
||||
self._volumes = volumes
|
||||
|
||||
@atoms.setter
|
||||
def atoms(self, atoms):
|
||||
cv.check_type('atoms', atoms, Mapping)
|
||||
self._atoms = atoms
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, filename):
|
||||
|
|
@ -198,7 +203,8 @@ class VolumeCalculation(object):
|
|||
lower_left = f.attrs['lower_left']
|
||||
upper_right = f.attrs['upper_right']
|
||||
|
||||
results = {}
|
||||
volumes = {}
|
||||
atoms = {}
|
||||
ids = []
|
||||
for obj_name in f:
|
||||
if obj_name.startswith('domain_'):
|
||||
|
|
@ -207,12 +213,13 @@ class VolumeCalculation(object):
|
|||
group = f[obj_name]
|
||||
volume = tuple(group['volume'].value)
|
||||
nucnames = group['nuclides'].value
|
||||
atoms = group['atoms'].value
|
||||
atoms_ = group['atoms'].value
|
||||
|
||||
atom_list = []
|
||||
for name_i, atoms_i in zip(nucnames, atoms):
|
||||
atom_list.append((name_i.decode(), tuple(atoms_i)))
|
||||
results[domain_id] = {'volume': volume, 'atoms': atom_list}
|
||||
atom_dict = OrderedDict()
|
||||
for name_i, atoms_i in zip(nucnames, atoms_):
|
||||
atom_dict[name_i.decode()] = tuple(atoms_i)
|
||||
volumes[domain_id] = volume
|
||||
atoms[domain_id] = atom_dict
|
||||
|
||||
# Instantiate some throw-away domains that are used by the constructor
|
||||
# to assign IDs
|
||||
|
|
@ -225,9 +232,30 @@ class VolumeCalculation(object):
|
|||
|
||||
# Instantiate the class and assign results
|
||||
vol = cls(domains, samples, lower_left, upper_right)
|
||||
vol.results = results
|
||||
vol.volumes = volumes
|
||||
vol.atoms = atoms
|
||||
return vol
|
||||
|
||||
def load_results(self, filename):
|
||||
"""Load stochastic volume calculation results from an HDF5 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to volume.h5 file
|
||||
|
||||
"""
|
||||
results = type(self).from_hdf5(filename)
|
||||
|
||||
# Make sure properties match
|
||||
assert self.domains == results.domains
|
||||
assert self.lower_left == results.lower_left
|
||||
assert self.upper_right == results.upper_right
|
||||
|
||||
# Copy results
|
||||
self.volumes = results.volumes
|
||||
self.atoms = results.atoms
|
||||
|
||||
def to_xml_element(self):
|
||||
"""Return XML representation of the volume calculation
|
||||
|
||||
|
|
|
|||
|
|
@ -62,13 +62,13 @@ class VolumeTest(PyAPITestHarness):
|
|||
outstr += 'Volume calculation {}\n'.format(i)
|
||||
|
||||
# Read volume calculation results
|
||||
vol = openmc.VolumeCalculation.from_hdf5(filename)
|
||||
volume_calc = openmc.VolumeCalculation.from_hdf5(filename)
|
||||
|
||||
# Write cell volumes and total # of atoms for each nuclide
|
||||
for uid, results in sorted(vol.results.items()):
|
||||
for uid, volume in sorted(volume_calc.volumes.items()):
|
||||
outstr += 'Domain {0}: {1[0]:.4f} +/- {1[1]:.4f} cm^3\n'.format(
|
||||
uid, results['volume'])
|
||||
outstr += str(vol.atoms_dataframe) + '\n'
|
||||
uid, volume)
|
||||
outstr += str(volume_calc.atoms_dataframe) + '\n'
|
||||
|
||||
return outstr
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue