LCOV - code coverage report
Current view: top level - src/userobjects - OpenMCVolumeCalculation.C (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: be601f Lines: 72 73 98.6 %
Date: 2025-07-15 20:50:38 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /********************************************************************/
       2             : /*                  SOFTWARE COPYRIGHT NOTIFICATION                 */
       3             : /*                             Cardinal                             */
       4             : /*                                                                  */
       5             : /*                  (c) 2021 UChicago Argonne, LLC                  */
       6             : /*                        ALL RIGHTS RESERVED                       */
       7             : /*                                                                  */
       8             : /*                 Prepared by UChicago Argonne, LLC                */
       9             : /*               Under Contract No. DE-AC02-06CH11357               */
      10             : /*                With the U. S. Department of Energy               */
      11             : /*                                                                  */
      12             : /*             Prepared by Battelle Energy Alliance, LLC            */
      13             : /*               Under Contract No. DE-AC07-05ID14517               */
      14             : /*                With the U. S. Department of Energy               */
      15             : /*                                                                  */
      16             : /*                 See LICENSE for full restrictions                */
      17             : /********************************************************************/
      18             : 
      19             : #ifdef ENABLE_OPENMC_COUPLING
      20             : 
      21             : #include "OpenMCVolumeCalculation.h"
      22             : #include "OpenMCCellAverageProblem.h"
      23             : #include "UserErrorChecking.h"
      24             : 
      25             : registerMooseObject("CardinalApp", OpenMCVolumeCalculation);
      26             : 
      27             : InputParameters
      28         258 : OpenMCVolumeCalculation::validParams()
      29             : {
      30         258 :   InputParameters params = GeneralUserObject::validParams();
      31         258 :   params += OpenMCBase::validParams();
      32         516 :   params.addParam<Point>("lower_left", "Lower left of the bounding box inside of which to "
      33             :     "compute volumes. If not specified, this will default to the lower left of the [Mesh] "
      34             :     "(which will NOT capture any OpenMC geometry that lies outside the [Mesh] extents.");
      35         516 :   params.addParam<Point>("upper_right", "Upper right of the bounding box inside of which to "
      36             :     "compute volumes. If not specified, this will default to the upper right of the [Mesh] "
      37             :     "(which will NOT capture any OpenMC geometry that lies outside the [Mesh] extents.");
      38         516 :   params.addRequiredRangeCheckedParam<unsigned int>("n_samples", "n_samples > 0",
      39             :     "Number of samples to use for the stochastic volume calculation");
      40         516 :   params.addRangeCheckedParam<Real>("trigger_threshold", "trigger_threshold > 0",
      41             :     "Trigger threshold to decide when to terminate the volume calculation");
      42             : 
      43         516 :   MooseEnum trigger("rel_err none", "none");
      44         516 :   params.addParam<MooseEnum>("trigger", getTallyTriggerEnum(),
      45             :     "Type of trigger to apply to decide when to terminate the volume calculation");
      46         258 :   params.addClassDescription("Stochastic volume calculation of the OpenMC cells which map to MOOSE");
      47         258 :   return params;
      48         258 : }
      49             : 
      50         129 : OpenMCVolumeCalculation::OpenMCVolumeCalculation(const InputParameters & parameters)
      51             :   : GeneralUserObject(parameters),
      52             :     OpenMCBase(this, parameters),
      53         129 :     _n_samples(getParam<unsigned int>("n_samples")),
      54         516 :     _trigger(getParam<MooseEnum>("trigger"))
      55             : {
      56         129 :   if (_trigger == "none")
      57         226 :     checkUnusedParam(parameters, "trigger_threshold", "not specifying any triggers");
      58          16 :   else if (_trigger == "rel_err")
      59             :   {
      60          32 :     checkRequiredParam(parameters, "trigger_threshold", "using a trigger");
      61          32 :     _trigger_threshold = getParam<Real>("trigger_threshold");
      62             :   }
      63             :   else
      64           0 :     mooseError("Unhandled trigger enum in OpenMCCellVolumeCalculation!");
      65             : 
      66         129 :   _scaling = _openmc_problem->scaling();
      67             : 
      68         258 :   if (isParamValid("lower_left"))
      69          20 :     _lower_left = getParam<Point>("lower_left");
      70         258 :   if (isParamValid("upper_right"))
      71          16 :     _upper_right = getParam<Point>("upper_right");
      72         129 : }
      73             : openmc::Position
      74         254 : OpenMCVolumeCalculation::position(const Point & pt) const
      75             : {
      76         254 :   openmc::Position p {pt(0), pt(1), pt(2)};
      77         254 :   return p;
      78             : }
      79             : 
      80             : void
      81           2 : OpenMCVolumeCalculation::resetVolumeCalculation()
      82             : {
      83           2 :   auto idx = openmc::model::volume_calcs.begin() + _calc_index;
      84             :   openmc::model::volume_calcs.erase(idx);
      85           2 : }
      86             : 
      87             : void
      88         129 : OpenMCVolumeCalculation::initializeVolumeCalculation()
      89             : {
      90             : 
      91         129 :   BoundingBox box = MeshTools::create_bounding_box(_openmc_problem->getMooseMesh().getMesh());
      92             : 
      93         258 :   if (!isParamValid("lower_left"))
      94         119 :     _lower_left = box.min();
      95         258 :   if (!isParamValid("upper_right"))
      96         121 :     _upper_right = box.max();
      97         129 :   if (_lower_left >= _upper_right)
      98           2 :     paramError("upper_right",
      99             :                "The 'upper_right' (",
     100             :                _upper_right(0),
     101             :                ", ",
     102             :                _upper_right(1),
     103             :                ", ",
     104             :                _upper_right(2),
     105             :                ") "
     106             :                "must be greater than the 'lower_left' (",
     107             :                _lower_left(0),
     108             :                ", ",
     109             :                _lower_left(1),
     110             :                ", ",
     111             :                _lower_left(2),
     112             :                ")!");
     113             : 
     114         127 :   _volume_calc.reset(new openmc::VolumeCalculation());
     115         127 :   _volume_calc->domain_type_ = openmc::VolumeCalculation::TallyDomain::CELL;
     116         127 :   _volume_calc->lower_left_ = position(_lower_left * _scaling);
     117         127 :   _volume_calc->upper_right_ = position(_upper_right * _scaling);
     118         127 :   _volume_calc->n_samples_ = _n_samples;
     119             : 
     120         127 :   if (_trigger == "rel_err")
     121             :   {
     122          16 :     _volume_calc->threshold_ = _trigger_threshold;
     123          16 :     _volume_calc->trigger_type_ = openmc::TriggerMetric::relative_error;
     124             :   }
     125             : 
     126         127 :   auto cell_to_elem = _openmc_problem->cellToElem();
     127             : 
     128             :   std::set<int> ids;
     129             :   _index_to_calc_index.clear();
     130             : 
     131             :   int i = 0;
     132        2239 :   for (const auto & c : cell_to_elem)
     133             :   {
     134        2112 :     auto index = c.first.first;
     135        2112 :     auto id = openmc::model::cells[index]->id_;
     136             : 
     137        2112 :     ids.insert(id);
     138        2112 :     if (!_index_to_calc_index.count(c.first.first))
     139        1526 :       _index_to_calc_index[c.first.first] = i++;
     140             :   }
     141             : 
     142         127 :   std::vector<int> domain_ids(ids.begin(), ids.end());
     143         127 :   _volume_calc->domain_ids_ = domain_ids;
     144         127 :   openmc::model::volume_calcs.push_back(*_volume_calc);
     145         127 :   _calc_index = openmc::model::volume_calcs.size();
     146         127 : }
     147             : 
     148             : void
     149         127 : OpenMCVolumeCalculation::computeVolumes()
     150             : {
     151         127 :   _console << "Running stochastic volume calculation... ";
     152         127 :   _results = _volume_calc->execute();
     153         127 : }
     154             : 
     155             : void
     156        2054 : OpenMCVolumeCalculation::cellVolume(const unsigned int & index, Real & volume, Real & std_dev) const
     157             : {
     158        2054 :   auto calc_index = _index_to_calc_index.at(index);
     159        2054 :   auto n_instances = openmc::model::cells[index]->n_instances_;
     160        2054 :   if (n_instances > 1)
     161         632 :     mooseDoOnce(mooseWarning(
     162             :         "OpenMC's stochastic volume calculation cannot individually measure volumes of cell "
     163             :         "INSTANCES. We assume that no cell instances are clipped by other cells (e.g. they are all "
     164             :         "identical) so that the volume of an individual instance is equal to the cell volume "
     165             :         "divided by number of instances. For most cases, this is correct - but if you have any "
     166             :         "instances which only partially exist in the geometry, this will give INCORRECT volumes."));
     167             : 
     168             :   // means add
     169        2052 :   volume = _results[calc_index].volume[0] / (_scaling * _scaling * _scaling) / n_instances;
     170             : 
     171             :   // but standard deviations only add as the variances
     172        2052 :   std_dev = _results[calc_index].volume[1] / (_scaling * _scaling * _scaling) / std::sqrt(n_instances);
     173        2052 : }
     174             : 
     175             : #endif

Generated by: LCOV version 1.14