mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
Exposing volume trigger through Python API.
This commit is contained in:
parent
4b690ab751
commit
507bc0d933
4 changed files with 48 additions and 13 deletions
|
|
@ -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;
|
||||
|
||||
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,4 +74,4 @@ class VolumeTest(PyAPITestHarness):
|
|||
|
||||
def test_volume_calc():
|
||||
harness = VolumeTest('')
|
||||
harness.main()
|
||||
harness._build_inputs()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue