diff --git a/openmc/__init__.py b/openmc/__init__.py
index 557e13039f..026ccce114 100644
--- a/openmc/__init__.py
+++ b/openmc/__init__.py
@@ -6,6 +6,9 @@ from openmc.nuclide import *
from openmc.macroscopic import *
from openmc.material import *
from openmc.plots import *
+from openmc.region import *
+from openmc.volume import *
+from openmc.source import *
from openmc.settings import *
from openmc.surface import *
from openmc.universe import *
@@ -18,8 +21,6 @@ from openmc.cmfd import *
from openmc.executor import *
from openmc.statepoint import *
from openmc.summary import *
-from openmc.region import *
-from openmc.source import *
from openmc.particle_restart import *
try:
diff --git a/openmc/settings.py b/openmc/settings.py
index b9a93bd114..918f97c7da 100644
--- a/openmc/settings.py
+++ b/openmc/settings.py
@@ -1,4 +1,4 @@
-from collections import Iterable
+from collections import Iterable, MutableSequence
from numbers import Real, Integral
import warnings
from xml.etree import ElementTree as ET
@@ -7,10 +7,8 @@ import sys
import numpy as np
from openmc.clean_xml import clean_xml_indentation
-from openmc.checkvalue import (check_type, check_length, check_value,
- check_greater_than, check_less_than)
-from openmc import Nuclide
-from openmc.source import Source
+import openmc.checkvalue as cv
+from openmc import Nuclide, VolumeCalculation, Source
if sys.version_info[0] >= 3:
basestring = str
@@ -137,6 +135,8 @@ class Settings(object):
resonance cross sections.
resonance_scattering : ResonanceScattering or iterable of ResonanceScattering
The elastic scattering model to use for resonant isotopes
+ volume_calculations : VolumeCalculation or iterable of VolumeCalculation
+ Stochastic volume calculation specifications
"""
@@ -220,6 +220,8 @@ class Settings(object):
self._multipole_active = None
self._resonance_scattering = None
+ self._volume_calculations = cv.CheckedList(VolumeCalculation,
+ 'volume calculations')
@property
def run_mode(self):
@@ -421,6 +423,10 @@ class Settings(object):
def resonance_scattering(self):
return self._resonance_scattering
+ @property
+ def volume_calculations(self):
+ return self._volume_calculations
+
@run_mode.setter
def run_mode(self, run_mode):
if run_mode not in ['eigenvalue', 'fixed source']:
@@ -431,26 +437,26 @@ class Settings(object):
@batches.setter
def batches(self, batches):
- check_type('batches', batches, Integral)
- check_greater_than('batches', batches, 0)
+ cv.check_type('batches', batches, Integral)
+ cv.check_greater_than('batches', batches, 0)
self._batches = batches
@generations_per_batch.setter
def generations_per_batch(self, generations_per_batch):
- check_type('generations per patch', generations_per_batch, Integral)
- check_greater_than('generations per batch', generations_per_batch, 0)
+ cv.check_type('generations per patch', generations_per_batch, Integral)
+ cv.check_greater_than('generations per batch', generations_per_batch, 0)
self._generations_per_batch = generations_per_batch
@inactive.setter
def inactive(self, inactive):
- check_type('inactive batches', inactive, Integral)
- check_greater_than('inactive batches', inactive, 0, True)
+ cv.check_type('inactive batches', inactive, Integral)
+ cv.check_greater_than('inactive batches', inactive, 0, True)
self._inactive = inactive
@particles.setter
def particles(self, particles):
- check_type('particles', particles, Integral)
- check_greater_than('particles', particles, 0)
+ cv.check_type('particles', particles, Integral)
+ cv.check_greater_than('particles', particles, 0)
self._particles = particles
@keff_trigger.setter
@@ -484,14 +490,14 @@ class Settings(object):
@energy_mode.setter
def energy_mode(self, energy_mode):
- check_value('energy mode', energy_mode,
+ cv.check_value('energy mode', energy_mode,
['continuous-energy', 'multi-group'])
self._energy_mode = energy_mode
@max_order.setter
def max_order(self, max_order):
- check_type('maximum scattering order', max_order, Integral)
- check_greater_than('maximum scattering order', max_order, 0, True)
+ cv.check_type('maximum scattering order', max_order, Integral)
+ cv.check_greater_than('maximum scattering order', max_order, 0, True)
self._max_order = max_order
@source.setter
@@ -499,7 +505,7 @@ class Settings(object):
if isinstance(source, Source):
self._source = [source,]
else:
- check_type('source distribution', source, Iterable, Source)
+ cv.check_type('source distribution', source, Iterable, Source)
self._source = source
@output.setter
@@ -525,197 +531,197 @@ class Settings(object):
@output_path.setter
def output_path(self, output_path):
- check_type('output path', output_path, basestring)
+ cv.check_type('output path', output_path, basestring)
self._output_path = output_path
@verbosity.setter
def verbosity(self, verbosity):
- check_type('verbosity', verbosity, Integral)
- check_greater_than('verbosity', verbosity, 1, True)
- check_less_than('verbosity', verbosity, 10, True)
+ cv.check_type('verbosity', verbosity, Integral)
+ cv.check_greater_than('verbosity', verbosity, 1, True)
+ cv.check_less_than('verbosity', verbosity, 10, True)
self._verbosity = verbosity
@statepoint_batches.setter
def statepoint_batches(self, batches):
- check_type('statepoint batches', batches, Iterable, Integral)
+ cv.check_type('statepoint batches', batches, Iterable, Integral)
for batch in batches:
- check_greater_than('statepoint batch', batch, 0)
+ cv.check_greater_than('statepoint batch', batch, 0)
self._statepoint_batches = batches
@statepoint_interval.setter
def statepoint_interval(self, interval):
- check_type('statepoint interval', interval, Integral)
+ cv.check_type('statepoint interval', interval, Integral)
self._statepoint_interval = interval
@sourcepoint_batches.setter
def sourcepoint_batches(self, batches):
- check_type('sourcepoint batches', batches, Iterable, Integral)
+ cv.check_type('sourcepoint batches', batches, Iterable, Integral)
for batch in batches:
- check_greater_than('sourcepoint batch', batch, 0)
+ cv.check_greater_than('sourcepoint batch', batch, 0)
self._sourcepoint_batches = batches
@sourcepoint_interval.setter
def sourcepoint_interval(self, interval):
- check_type('sourcepoint interval', interval, Integral)
+ cv.check_type('sourcepoint interval', interval, Integral)
self._sourcepoint_interval = interval
@sourcepoint_separate.setter
def sourcepoint_separate(self, source_separate):
- check_type('sourcepoint separate', source_separate, bool)
+ cv.check_type('sourcepoint separate', source_separate, bool)
self._sourcepoint_separate = source_separate
@sourcepoint_write.setter
def sourcepoint_write(self, source_write):
- check_type('sourcepoint write', source_write, bool)
+ cv.check_type('sourcepoint write', source_write, bool)
self._sourcepoint_write = source_write
@sourcepoint_overwrite.setter
def sourcepoint_overwrite(self, source_overwrite):
- check_type('sourcepoint overwrite', source_overwrite, bool)
+ cv.check_type('sourcepoint overwrite', source_overwrite, bool)
self._sourcepoint_overwrite = source_overwrite
@confidence_intervals.setter
def confidence_intervals(self, confidence_intervals):
- check_type('confidence interval', confidence_intervals, bool)
+ cv.check_type('confidence interval', confidence_intervals, bool)
self._confidence_intervals = confidence_intervals
@cross_sections.setter
def cross_sections(self, cross_sections):
- check_type('cross sections', cross_sections, basestring)
+ cv.check_type('cross sections', cross_sections, basestring)
self._cross_sections = cross_sections
@multipole_library.setter
def multipole_library(self, multipole_library):
- check_type('cross sections', multipole_library, basestring)
+ cv.check_type('cross sections', multipole_library, basestring)
self._multipole_library = multipole_library
@energy_grid.setter
def energy_grid(self, energy_grid):
- check_value('energy grid', energy_grid,
+ cv.check_value('energy grid', energy_grid,
['nuclide', 'logarithm', 'material-union'])
self._energy_grid = energy_grid
@ptables.setter
def ptables(self, ptables):
- check_type('probability tables', ptables, bool)
+ cv.check_type('probability tables', ptables, bool)
self._ptables = ptables
@run_cmfd.setter
def run_cmfd(self, run_cmfd):
- check_type('run_cmfd', run_cmfd, bool)
+ cv.check_type('run_cmfd', run_cmfd, bool)
self._run_cmfd = run_cmfd
@seed.setter
def seed(self, seed):
- check_type('random number generator seed', seed, Integral)
- check_greater_than('random number generator seed', seed, 0)
+ cv.check_type('random number generator seed', seed, Integral)
+ cv.check_greater_than('random number generator seed', seed, 0)
self._seed = seed
@survival_biasing.setter
def survival_biasing(self, survival_biasing):
- check_type('survival biasing', survival_biasing, bool)
+ cv.check_type('survival biasing', survival_biasing, bool)
self._survival_biasing = survival_biasing
@weight.setter
def weight(self, weight):
- check_type('weight cutoff', weight, Real)
- check_greater_than('weight cutoff', weight, 0.0)
+ cv.check_type('weight cutoff', weight, Real)
+ cv.check_greater_than('weight cutoff', weight, 0.0)
self._weight = weight
@weight_avg.setter
def weight_avg(self, weight_avg):
- check_type('average survival weight', weight_avg, Real)
- check_greater_than('average survival weight', weight_avg, 0.0)
+ cv.check_type('average survival weight', weight_avg, Real)
+ cv.check_greater_than('average survival weight', weight_avg, 0.0)
self._weight_avg = weight_avg
@entropy_dimension.setter
def entropy_dimension(self, dimension):
- check_type('entropy mesh dimension', dimension, Iterable, Integral)
- check_length('entropy mesh dimension', dimension, 3)
+ cv.check_type('entropy mesh dimension', dimension, Iterable, Integral)
+ cv.check_length('entropy mesh dimension', dimension, 3)
self._entropy_dimension = dimension
@entropy_lower_left.setter
def entropy_lower_left(self, lower_left):
- check_type('entropy mesh lower left corner', lower_left,
+ cv.check_type('entropy mesh lower left corner', lower_left,
Iterable, Real)
- check_length('entropy mesh lower left corner', lower_left, 3)
+ cv.check_length('entropy mesh lower left corner', lower_left, 3)
self._entropy_lower_left = lower_left
@entropy_upper_right.setter
def entropy_upper_right(self, upper_right):
- check_type('entropy mesh upper right corner', upper_right,
+ cv.check_type('entropy mesh upper right corner', upper_right,
Iterable, Real)
- check_length('entropy mesh upper right corner', upper_right, 3)
+ cv.check_length('entropy mesh upper right corner', upper_right, 3)
self._entropy_upper_right = upper_right
@trigger_active.setter
def trigger_active(self, trigger_active):
- check_type('trigger active', trigger_active, bool)
+ cv.check_type('trigger active', trigger_active, bool)
self._trigger_active = trigger_active
@trigger_max_batches.setter
def trigger_max_batches(self, trigger_max_batches):
- check_type('trigger maximum batches', trigger_max_batches, Integral)
- check_greater_than('trigger maximum batches', trigger_max_batches, 0)
+ cv.check_type('trigger maximum batches', trigger_max_batches, Integral)
+ cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0)
self._trigger_max_batches = trigger_max_batches
@trigger_batch_interval.setter
def trigger_batch_interval(self, trigger_batch_interval):
- check_type('trigger batch interval', trigger_batch_interval, Integral)
- check_greater_than('trigger batch interval', trigger_batch_interval, 0)
+ cv.check_type('trigger batch interval', trigger_batch_interval, Integral)
+ cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0)
self._trigger_batch_interval = trigger_batch_interval
@no_reduce.setter
def no_reduce(self, no_reduce):
- check_type('no reduction option', no_reduce, bool)
+ cv.check_type('no reduction option', no_reduce, bool)
self._no_reduce = no_reduce
@threads.setter
def threads(self, threads):
- check_type('number of threads', threads, Integral)
- check_greater_than('number of threads', threads, 0)
+ cv.check_type('number of threads', threads, Integral)
+ cv.check_greater_than('number of threads', threads, 0)
self._threads = threads
@trace.setter
def trace(self, trace):
- check_type('trace', trace, Iterable, Integral)
- check_length('trace', trace, 3)
- check_greater_than('trace batch', trace[0], 0)
- check_greater_than('trace generation', trace[1], 0)
- check_greater_than('trace particle', trace[2], 0)
+ cv.check_type('trace', trace, Iterable, Integral)
+ cv.check_length('trace', trace, 3)
+ cv.check_greater_than('trace batch', trace[0], 0)
+ cv.check_greater_than('trace generation', trace[1], 0)
+ cv.check_greater_than('trace particle', trace[2], 0)
self._trace = trace
@track.setter
def track(self, track):
- check_type('track', track, Iterable, Integral)
+ cv.check_type('track', track, Iterable, Integral)
if len(track) % 3 != 0:
msg = 'Unable to set the track to "{0}" since its length is ' \
'not a multiple of 3'.format(track)
raise ValueError(msg)
for t in zip(track[::3], track[1::3], track[2::3]):
- check_greater_than('track batch', t[0], 0)
- check_greater_than('track generation', t[0], 0)
- check_greater_than('track particle', t[0], 0)
+ cv.check_greater_than('track batch', t[0], 0)
+ cv.check_greater_than('track generation', t[0], 0)
+ cv.check_greater_than('track particle', t[0], 0)
self._track = track
@ufs_dimension.setter
def ufs_dimension(self, dimension):
- check_type('UFS mesh dimension', dimension, Iterable, Integral)
- check_length('UFS mesh dimension', dimension, 3)
+ cv.check_type('UFS mesh dimension', dimension, Iterable, Integral)
+ cv.check_length('UFS mesh dimension', dimension, 3)
for dim in dimension:
- check_greater_than('UFS mesh dimension', dim, 1, True)
+ cv.check_greater_than('UFS mesh dimension', dim, 1, True)
self._ufs_dimension = dimension
@ufs_lower_left.setter
def ufs_lower_left(self, lower_left):
- check_type('UFS mesh lower left corner', lower_left, Iterable, Real)
- check_length('UFS mesh lower left corner', lower_left, 3)
+ cv.check_type('UFS mesh lower left corner', lower_left, Iterable, Real)
+ cv.check_length('UFS mesh lower left corner', lower_left, 3)
self._ufs_lower_left = lower_left
@ufs_upper_right.setter
def ufs_upper_right(self, upper_right):
- check_type('UFS mesh upper right corner', upper_right, Iterable, Real)
- check_length('UFS mesh upper right corner', upper_right, 3)
+ cv.check_type('UFS mesh upper right corner', upper_right, Iterable, Real)
+ cv.check_length('UFS mesh upper right corner', upper_right, 3)
self._ufs_upper_right = upper_right
@dd_mesh_dimension.setter
@@ -724,8 +730,8 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD mesh dimension', dimension, Iterable, Integral)
- check_length('DD mesh dimension', dimension, 3)
+ cv.check_type('DD mesh dimension', dimension, Iterable, Integral)
+ cv.check_length('DD mesh dimension', dimension, 3)
self._dd_mesh_dimension = dimension
@@ -735,8 +741,8 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD mesh lower left corner', lower_left, Iterable, Real)
- check_length('DD mesh lower left corner', lower_left, 3)
+ cv.check_type('DD mesh lower left corner', lower_left, Iterable, Real)
+ cv.check_length('DD mesh lower left corner', lower_left, 3)
self._dd_mesh_lower_left = lower_left
@@ -746,8 +752,8 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD mesh upper right corner', upper_right, Iterable, Real)
- check_length('DD mesh upper right corner', upper_right, 3)
+ cv.check_type('DD mesh upper right corner', upper_right, Iterable, Real)
+ cv.check_length('DD mesh upper right corner', upper_right, 3)
self._dd_mesh_upper_right = upper_right
@@ -757,7 +763,7 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD nodemap', nodemap, Iterable)
+ cv.check_type('DD nodemap', nodemap, Iterable)
nodemap = np.array(nodemap).flatten()
@@ -782,7 +788,7 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD allow leakage', allow, bool)
+ cv.check_type('DD allow leakage', allow, bool)
self._dd_allow_leakage = allow
@@ -793,25 +799,34 @@ class Settings(object):
warnings.warn('This feature is not yet implemented in a release '
'version of openmc')
- check_type('DD count interactions', interactions, bool)
+ cv.check_type('DD count interactions', interactions, bool)
self._dd_count_interactions = interactions
@use_windowed_multipole.setter
def use_windowed_multipole(self, active):
- check_type('use_windowed_multipole', active, bool)
+ cv.check_type('use_windowed_multipole', active, bool)
self._multipole_active = active
@resonance_scattering.setter
def resonance_scattering(self, res):
if isinstance(res, Iterable):
- check_type('resonance_scattering', res, Iterable,
+ cv.check_type('resonance_scattering', res, Iterable,
ResonanceScattering)
self._resonance_scattering = res
else:
- check_type('resonance_scattering', res, ResonanceScattering)
+ cv.check_type('resonance_scattering', res, ResonanceScattering)
self._resonance_scattering = [res]
+ @volume_calculations.setter
+ def volume_calculations(self, vol_calcs):
+ name = 'stochastic volume calculations'
+ if not isinstance(vol_calcs, MutableSequence):
+ vol_calcs = [vol_calcs]
+ cv.check_type(name, vol_calcs, MutableSequence)
+ self._volume_calculations = cv.CheckedList(VolumeCalculation,
+ name, vol_calcs)
+
def _create_run_mode_subelement(self):
if self.run_mode == 'eigenvalue':
@@ -873,6 +888,10 @@ class Settings(object):
for source in self.source:
self._settings_file.append(source.to_xml())
+ def _create_volume_calcs_subelement(self):
+ for calc in self.volume_calculations:
+ self._settings_file.append(calc.to_xml())
+
def _create_output_subelement(self):
if self._output is not None:
element = ET.SubElement(self._settings_file, "output")
@@ -1154,6 +1173,7 @@ class Settings(object):
self._create_dd_subelement()
self._create_use_multipole_subelement()
self._create_resonance_scattering_element()
+ self._create_volume_calcs_subelement()
# Clean the indentation in the file to be user-readable
clean_xml_indentation(self._settings_file)
@@ -1216,29 +1236,29 @@ class ResonanceScattering(object):
@nuclide.setter
def nuclide(self, nuc):
- check_type('nuclide', nuc, Nuclide)
+ cv.check_type('nuclide', nuc, Nuclide)
self._nuclide = nuc
@nuclide_0K.setter
def nuclide_0K(self, nuc):
- check_type('nuclide_0K', nuc, Nuclide)
+ cv.check_type('nuclide_0K', nuc, Nuclide)
self._nuclide_0K = nuc
@method.setter
def method(self, m):
- check_value('method', m, ('ARES', 'CXS', 'DBRC', 'WCM'))
+ cv.check_value('method', m, ('ARES', 'CXS', 'DBRC', 'WCM'))
self._method = m
@E_min.setter
def E_min(self, E):
- check_type('E_min', E, Real)
- check_greater_than('E_min', E, 0, True)
+ cv.check_type('E_min', E, Real)
+ cv.check_greater_than('E_min', E, 0, True)
self._E_min = E
@E_max.setter
def E_max(self, E):
- check_type('E_max', E, Real)
- check_greater_than('E_max', E, 0, True)
+ cv.check_type('E_max', E, Real)
+ cv.check_greater_than('E_max', E, 0, True)
self._E_max = E
def create_xml_subelement(self, xml_element):
diff --git a/openmc/volume.py b/openmc/volume.py
new file mode 100644
index 0000000000..511af62ed3
--- /dev/null
+++ b/openmc/volume.py
@@ -0,0 +1,204 @@
+from collections import Iterable, Mapping
+from numbers import Real, Integral
+from xml.etree import ElementTree as ET
+
+import numpy as np
+import pandas as pd
+
+from openmc import Cell, Union
+import openmc.checkvalue as cv
+
+
+class VolumeCalculation(object):
+ """Stochastic volume calculation specifications and results.
+
+ Parameters
+ ----------
+ cells : Iterable of Cell
+ Cells to find volumes of
+ samples : int
+ Number of samples used to generate volume estimates
+ lower_left : Iterable of float
+ Lower-left coordinates of bounding box used to sample points. If this
+ argument is not supplied, an attempt is made to automatically determine
+ a bounding box.
+ upper_right : Iterable of float
+ Upper-right coordinates of bounding box used to sample points. If this
+ argument is not supplied, an attempt is made to automatically determine
+ a bounding box.
+
+ Attributes
+ ----------
+ cell_ids : Iterable of int
+ IDs of cells to find volumes of
+ samples : int
+ Number of samples used to generate volume estimates
+ lower_left : Iterable of float
+ 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 cells and values are
+ dictionaries with calculated volumes and total number of atoms for each
+ nuclide present in the cell.
+ volumes : dict
+ Dictionary whose keys are unique IDs of cells and values are the
+ estimated volumes
+ atoms_dataframe : pandas.DataFrame
+ DataFrame showing the estimated number of atoms for each nuclide present
+ in each cell specified.
+
+ """
+ def __init__(self, cells, samples, lower_left=None,
+ upper_right=None):
+ self._results = None
+
+ cv.check_type('cells', cells, Iterable, Cell)
+ self.cell_ids = [c.id for c in cells]
+ self.samples = samples
+
+ if lower_left is not None:
+ self.lower_left = lower_left
+ if upper_right is None:
+ raise ValueError('Both lower-left and upper-right coordinates '
+ 'should be specified')
+ self.upper_right = upper_right
+ else:
+ ll, ur = Union(*[c.region for c in cells]).bounding_box
+ if np.any(np.isinf(ll)) or np.any(np.isinf(ur)):
+ raise ValueError('Could not automatically determine bounding box '
+ 'for stochastic volume calculation.')
+ else:
+ self.lower_left = ll
+ self.upper_right = ur
+
+ @property
+ def cell_ids(self):
+ return self._cell_ids
+
+ @property
+ def samples(self):
+ return self._samples
+
+ @property
+ def lower_left(self):
+ return self._lower_left
+
+ @property
+ def upper_right(self):
+ return self._upper_right
+
+ @property
+ def results(self):
+ return self._results
+
+ @property
+ def volumes(self):
+ return {uid: results['volume'] for uid, results in self.results.items()}
+
+ @property
+ def atoms_dataframe(self):
+ items = []
+ columns = ['Cell', 'Nuclide', 'Atoms', 'Uncertainty']
+ for cell_id, results in self.results.items():
+ for name, atoms in results['atoms']:
+ items.append((cell_id, name, atoms[0], atoms[1]))
+
+ return pd.DataFrame.from_records(items, columns=columns)
+
+ @cell_ids.setter
+ def cell_ids(self, cell_ids):
+ cv.check_type('cell IDs', cell_ids, Iterable, Real)
+ self._cell_ids = cell_ids
+
+ @samples.setter
+ def samples(self, samples):
+ cv.check_type('number of samples', samples, Integral)
+ cv.check_greater_than('number of samples', samples, 0)
+ self._samples = samples
+
+ @lower_left.setter
+ def lower_left(self, lower_left):
+ name = 'lower-left bounding box coordinates',
+ cv.check_type(name, lower_left, Iterable, Real)
+ cv.check_length(name, lower_left, 3)
+ self._lower_left = lower_left
+
+ @upper_right.setter
+ def upper_right(self, upper_right):
+ name = 'upper-right bounding box coordinates'
+ cv.check_type(name, upper_right, Iterable, Real)
+ 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
+
+ @classmethod
+ def from_hdf5(cls, filename):
+ """Load stochastic volume calculation results from HDF5 file.
+
+ Parameters
+ ----------
+ filename : str
+ Path to volume.h5 file
+
+ Returns
+ -------
+ openmc.VolumeCalculation
+ Results of the stochastic volume calculation
+
+ """
+ import h5py
+
+ with h5py.File(filename, 'r') as f:
+ samples = f.attrs['samples']
+ lower_left = f.attrs['lower_left']
+ upper_right = f.attrs['upper_right']
+
+ results = {}
+ cell_ids = []
+ for obj_name in f:
+ if obj_name.startswith('cell_'):
+ cell_id = int(obj_name[5:])
+ cell_ids.append(cell_id)
+ group = f[obj_name]
+ volume = tuple(group['volume'].value)
+ nucnames = group['nuclides'].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[cell_id] = {'volume': volume, 'atoms': atom_list}
+
+ # Instantiate some throw-away cells that are used by the constructor to
+ # assign IDs
+ cells = [Cell(uid) for uid in cell_ids]
+
+ # Instantiate the class and assign results
+ vol = cls(cells, samples, lower_left, upper_right)
+ vol.results = results
+ return vol
+
+ def to_xml(self):
+ """Return XML representation of the volume calculation
+
+ Returns
+ -------
+ element : xml.etree.ElementTree.Element
+ XML element containing volume calculation data
+
+ """
+ element = ET.Element("volume_calc")
+ cell_elem = ET.SubElement(element, "cells")
+ cell_elem.text = ' '.join(str(uid) for uid in self.cell_ids)
+ samples_elem = ET.SubElement(element, "samples")
+ samples_elem.text = str(self.samples)
+ ll_elem = ET.SubElement(element, "lower_left")
+ ll_elem.text = ' '.join(str(x) for x in self.lower_left)
+ ur_elem = ET.SubElement(element, "upper_right")
+ ur_elem.text = ' '.join(str(x) for x in self.upper_right)
+ return element
diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc
index 46950c63fb..78a32171b9 100644
--- a/src/relaxng/settings.rnc
+++ b/src/relaxng/settings.rnc
@@ -142,6 +142,17 @@ element settings {
element verbosity { xsd:positiveInteger }? &
+ element volume_calc {
+ (element cells { list { xsd:positiveInteger+ } } |
+ attribute cells { list { xsd:positiveInteger+ } }) &
+ (element samples { xsd:positiveInteger } |
+ attribute samples { xsd:positiveInteger }) &
+ (element lower_left { list { xsd:double+ } } |
+ attribute lower_left { list { xsd:double+ } }) &
+ (element upper_right { list { xsd:double+ } } |
+ attribute upper_right { list { xsd:double+ } })
+ }+ &
+
element uniform_fs{
(element dimension { list { xsd:positiveInteger+ } } |
attribute dimension { list { xsd:positiveInteger+ } }) &
diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng
index 0b50f79699..64fe42239d 100644
--- a/src/relaxng/settings.rng
+++ b/src/relaxng/settings.rng
@@ -625,6 +625,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+