Add VolumeCalculation object. Update settings.xml RELAX NG schema

This commit is contained in:
Paul Romano 2016-07-28 12:35:15 -05:00
parent 6ef6740ebc
commit cac6ac6f66
5 changed files with 392 additions and 94 deletions

View file

@ -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:

View file

@ -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):

204
openmc/volume.py Normal file
View file

@ -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

View file

@ -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+ } }) &

View file

@ -625,6 +625,68 @@
<data type="positiveInteger"/>
</element>
</optional>
<oneOrMore>
<element name="volume_calc">
<interleave>
<choice>
<element name="cells">
<list>
<oneOrMore>
<data type="positiveInteger"/>
</oneOrMore>
</list>
</element>
<attribute name="cells">
<list>
<oneOrMore>
<data type="positiveInteger"/>
</oneOrMore>
</list>
</attribute>
</choice>
<choice>
<element name="samples">
<data type="positiveInteger"/>
</element>
<attribute name="samples">
<data type="positiveInteger"/>
</attribute>
</choice>
<choice>
<element name="lower_left">
<list>
<oneOrMore>
<data type="double"/>
</oneOrMore>
</list>
</element>
<attribute name="lower_left">
<list>
<oneOrMore>
<data type="double"/>
</oneOrMore>
</list>
</attribute>
</choice>
<choice>
<element name="upper_right">
<list>
<oneOrMore>
<data type="double"/>
</oneOrMore>
</list>
</element>
<attribute name="upper_right">
<list>
<oneOrMore>
<data type="double"/>
</oneOrMore>
</list>
</attribute>
</choice>
</interleave>
</element>
</oneOrMore>
<optional>
<element name="uniform_fs">
<interleave>