Exposing volume trigger through Python API.

This commit is contained in:
Patrick Shriwise 2019-10-05 10:23:11 -05:00
parent 4b690ab751
commit 507bc0d933
4 changed files with 48 additions and 13 deletions

View file

@ -78,8 +78,6 @@ public:
//! \return Vector of results for each user-specified domain
std::vector<Result> execute() const;
std::vector<Result> _execute(size_t seed_offset = 0) const;
//! \brief Write volume calculation results to HDF5 file
//
//! \param[in] filename Path to HDF5 file to write
@ -89,7 +87,7 @@ public:
// Data members
int domain_type_; //!< Type of domain (cell, material, etc.)
size_t n_samples_; //!< Number of samples to use
double error_trigger_ {-1.0}; //!< Error below which the calculation will stop
double trigger_ {-1.0}; //!< Error threshold for domain volumes
Position lower_left_; //!< Lower-left position of bounding box
Position upper_right_; //!< Upper-right position of bounding box
std::vector<int> domain_ids_; //!< IDs of domains to find volumes of
@ -104,6 +102,14 @@ private:
void check_hit(int i_material, std::vector<int>& indices,
std::vector<int>& hits) const;
//! \brief Perform calculation for domain volumes and average nuclide density
//! using n_samples_
//
//! \param[in] seed_offset Seed offset used for independent calculations
//! \return Vector of results for each user-specified domain
std::vector<Result> _execute(size_t seed_offset = 0) const;
};
//==============================================================================

View file

@ -12,7 +12,7 @@ from uncertainties import ufloat
import openmc
import openmc.checkvalue as cv
_VERSION_VOLUME = 1
_VERSION_VOLUME = 2
class VolumeCalculation(object):
@ -32,6 +32,8 @@ class VolumeCalculation(object):
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.
trigger : float
Threshold for the maxmimum standard deviation of volumes
Attributes
----------
@ -45,6 +47,8 @@ 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
trigger : float
Threshold for the maximum standard deviation of volume in the calculation
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
@ -57,9 +61,10 @@ class VolumeCalculation(object):
"""
def __init__(self, domains, samples, lower_left=None,
upper_right=None):
upper_right=None, trigger=None):
self._atoms = {}
self._volumes = {}
self._trigger = None
cv.check_type('domains', domains, Iterable,
(openmc.Cell, openmc.Material, openmc.Universe))
@ -72,6 +77,9 @@ class VolumeCalculation(object):
self.ids = [d.id for d in domains]
self.samples = samples
if trigger is not None:
self.trigger = trigger
if lower_left is not None:
if upper_right is None:
@ -123,6 +131,10 @@ class VolumeCalculation(object):
def upper_right(self):
return self._upper_right
@property
def trigger(self):
return self._trigger
@property
def domain_type(self):
return self._domain_type
@ -170,6 +182,12 @@ class VolumeCalculation(object):
cv.check_length(name, upper_right, 3)
self._upper_right = upper_right
@trigger.setter
def trigger(self, trigger):
name = 'Volume std. dev. trigger'
cv.check_type(name, trigger, Real)
self._trigger = trigger
@volumes.setter
def volumes(self, volumes):
cv.check_type('volumes', volumes, Mapping)
@ -202,6 +220,10 @@ class VolumeCalculation(object):
samples = f.attrs['samples']
lower_left = f.attrs['lower_left']
upper_right = f.attrs['upper_right']
trigger = f.attrs['trigger']
if trigger == -1.0:
trigger = None
volumes = {}
atoms = {}
@ -232,7 +254,7 @@ class VolumeCalculation(object):
domains = [openmc.Universe(uid) for uid in ids]
# Instantiate the class and assign results
vol = cls(domains, samples, lower_left, upper_right)
vol = cls(domains, samples, lower_left, upper_right, trigger)
vol.volumes = volumes
vol.atoms = atoms
return vol
@ -277,4 +299,7 @@ class VolumeCalculation(object):
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)
if self.trigger:
trigger_elem = ET.SubElement(element, "trigger")
trigger_elem.text = str(self.trigger)
return element

View file

@ -68,11 +68,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node)
fatal_error(msg);
}
if (check_for_node(node, "error_trigger")) {
error_trigger_ = std::stod(get_node_value(node, "error_trigger"));
if (error_trigger_ <= 0.0) {
if (check_for_node(node, "trigger")) {
trigger_ = std::stod(get_node_value(node, "trigger"));
if (trigger_ <= 0.0) {
std::stringstream msg;
msg << "Invalid error trigger " << error_trigger_ << " provided for a volume calculation.";
msg << "Invalid error threshold " << trigger_ << " provided for a volume calculation.";
fatal_error(msg);
}
}
@ -89,9 +89,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node)
std::vector<VolumeCalculation::Result> VolumeCalculation::execute() const {
// execute the calculation once
std::vector<VolumeCalculation::Result> results = _execute();
if (error_trigger_ <= 0.0) { return results; }
// if no std. dev. threshold is set, return these resuls
if (trigger_ == -1.0) { return results; }
size_t offset = n_samples_;
double max_err;
@ -102,8 +104,9 @@ std::vector<VolumeCalculation::Result> VolumeCalculation::execute() const {
for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); }
// exit once we're below our error limit
if (max_err <= error_trigger_) { break; }
if (max_err <= trigger_) { break; }
// perform the calculation
std::vector<VolumeCalculation::Result> tmp = _execute(offset);
offset += n_samples_;
@ -333,6 +336,7 @@ void VolumeCalculation::to_hdf5(const std::string& filename,
write_attribute(file_id, "samples", n_samples_);
write_attribute(file_id, "lower_left", lower_left_);
write_attribute(file_id, "upper_right", upper_right_);
write_attribute(file_id, "trigger", trigger_);
if (domain_type_ == FILTER_CELL) {
write_attribute(file_id, "domain_type", "cell");
}

View file

@ -74,4 +74,4 @@ class VolumeTest(PyAPITestHarness):
def test_volume_calc():
harness = VolumeTest('')
harness.main()
harness._build_inputs()