LCOV - code coverage report
Current view: top level - src/postprocessors - TallyRelativeError.C (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: 93e9c4 Lines: 66 72 91.7 %
Date: 2026-07-16 12:06:10 Functions: 3 3 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 "TallyRelativeError.h"
      22             : #include "UserErrorChecking.h"
      23             : 
      24             : registerMooseObject("CardinalApp", TallyRelativeError);
      25             : 
      26             : registerMooseObjectRenamed("CardinalApp",
      27             :                            FissionTallyRelativeError,
      28             :                            "03/01/2023 24:00",
      29             :                            TallyRelativeError);
      30             : 
      31             : InputParameters
      32        1042 : TallyRelativeError::validParams()
      33             : {
      34        1042 :   InputParameters params = GeneralPostprocessor::validParams();
      35        1042 :   params += OpenMCBase::validParams();
      36        2084 :   params.addParam<MooseEnum>("value_type",
      37        2084 :                              getOperationEnum(),
      38             :                              "Whether to give the maximum or minimum tally relative error");
      39             : 
      40        2084 :   params.addParam<MooseEnum>("tally_score",
      41        2084 :                              getSingleTallyScoreEnum(),
      42             :                              "Score to report the relative error. If there is just a single score, "
      43             :                              "this defaults to that value");
      44        2084 :   params.addParam<std::string>(
      45             :       "tally",
      46             :       "The name of the tally to fetch the score variable from. Only required if "
      47             :       "your problem contains multiple tallies which accumulate the same score.");
      48        1042 :   params.addClassDescription("Maximum/minimum tally relative error");
      49        1042 :   return params;
      50           0 : }
      51             : 
      52         328 : TallyRelativeError::TallyRelativeError(const InputParameters & parameters)
      53             :   : GeneralPostprocessor(parameters),
      54             :     TallyInterface(this, parameters),
      55         654 :     _type(getParam<MooseEnum>("value_type").getEnum<operation::OperationEnum>())
      56             : {
      57         652 :   if (isParamValid("tally_score"))
      58         542 :     _score = getScore("tally_score");
      59             :   else
      60             :   {
      61          54 :     if (_openmc_problem->getTallyScores().size() != 1 && !isParamValid("tally_score"))
      62           0 :       paramError("tally_score",
      63             :                  "When multiple scores have been added by tally objects, you must specify a score "
      64             :                  "from which the relative error will be extracted.");
      65             : 
      66          54 :     _score = _openmc_problem->getTallyScores()[0];
      67             :   }
      68             : 
      69             :   // Edge case: multiple scores from linked MeshTally objects.
      70         324 :   const auto scoring_tallies = _openmc_problem->getNumScoringTallies(_score);
      71         324 :   unsigned int linked = 0;
      72             :   unsigned int num_with_score = 0;
      73         784 :   for (auto tally : _openmc_problem->getLocalTallies())
      74             :   {
      75         460 :     if (tally->hasScore(_score))
      76             :     {
      77         430 :       linked = std::max(linked, static_cast<unsigned int>(tally->linkedTallies().size()) + 1);
      78         430 :       num_with_score++;
      79             : 
      80         430 :       _tally = tally.get();
      81             :     }
      82             :   }
      83             : 
      84             :   // User must provide a tally to post-process if there isn't a single non-linked tally per score.
      85         324 :   if (scoring_tallies != linked || scoring_tallies != num_with_score)
      86          54 :     _tally = _openmc_problem->getTally(tallyByScore(_score, "tally"));
      87         318 : }
      88             : 
      89             : Real
      90         318 : TallyRelativeError::getValue() const
      91             : {
      92             :   Real post_processor_value;
      93             :   std::string return_type;
      94         318 :   switch (_type)
      95             :   {
      96         220 :     case operation::max:
      97         220 :       post_processor_value = std::numeric_limits<Real>::min();
      98             :       return_type = "maximum";
      99             :       break;
     100          50 :     case operation::min:
     101          50 :       post_processor_value = std::numeric_limits<Real>::max();
     102             :       return_type = "minimum";
     103             :       break;
     104          48 :     case operation::average:
     105          48 :       post_processor_value = 0.0;
     106             :       return_type = "average";
     107             :       break;
     108           0 :     default:
     109           0 :       mooseError("Unhandled OperationEnum!");
     110             :   }
     111             : 
     112         634 :   std::vector<const TallyBase *> tallies = {_tally};
     113         382 :   for (const auto linked : _tally->linkedTallies())
     114          64 :     tallies.push_back(linked);
     115             : 
     116             :   bool had_hit = false;
     117             : 
     118             :   unsigned int num_values = 0;
     119             :   std::string tally_name;
     120         700 :   for (const auto tally : tallies)
     121             :   {
     122         382 :     const auto t = tally->getWrappedTally();
     123             : 
     124             :     // For linked tallies (e.g. translated mesh tallies), only one tally will add
     125             :     // auxvariables (and therefore have any associated auxvariable names). All
     126             :     // other tallies store data in the first auxvariable in the series.
     127         382 :     if (tally->getAuxVarNames().size() > 0)
     128             :       tally_name = tally->getAuxVarNames()[0];
     129             : 
     130         382 :     auto sum = OMCTensor(t->results_.slice(openmc::tensor::all,
     131         382 :                                            tally->scoreIndex(_score),
     132         382 :                                            static_cast<int>(openmc::TallyResult::SUM)));
     133         382 :     auto sum_sq = OMCTensor(t->results_.slice(openmc::tensor::all,
     134             :                                               tally->scoreIndex(_score),
     135         382 :                                               static_cast<int>(openmc::TallyResult::SUM_SQ)));
     136             : 
     137         382 :     auto rel_err = _openmc_problem->relativeError(sum, sum_sq, t->n_realizations_);
     138       26920 :     for (int i = 0; i < t->n_filter_bins(); ++i)
     139             :     {
     140             :       // tallies without any scores to them will have zero error, which doesn't really make
     141             :       // sense to compare against
     142       26538 :       if (MooseUtils::absoluteFuzzyEqual(sum(i), 0))
     143          10 :         continue;
     144             : 
     145             :       had_hit = true;
     146             : 
     147       26528 :       switch (_type)
     148             :       {
     149       13488 :         case operation::max:
     150       13488 :           post_processor_value = std::max(post_processor_value, rel_err[i]);
     151       13488 :           break;
     152        6776 :         case operation::min:
     153        6776 :           post_processor_value = std::min(post_processor_value, rel_err[i]);
     154        6776 :           break;
     155        6264 :         case operation::average:
     156        6264 :           post_processor_value += rel_err[i];
     157        6264 :           num_values++;
     158        6264 :           break;
     159           0 :         default:
     160           0 :           mooseError("Unhandled OperationEnum!");
     161             :       }
     162             :     }
     163             :   }
     164             : 
     165         318 :   if (_type == operation::average)
     166          48 :     post_processor_value /= num_values;
     167             : 
     168         318 :   if (!had_hit)
     169           6 :     mooseWarning("No events scored to the " + _score + " tally (stored in the AuxVariable named '" +
     170           2 :                  tally_name + "')! The " + return_type +
     171             :                  " relative error is being set to zero because there is nothing to report.");
     172             : 
     173         632 :   return had_hit ? post_processor_value : 0.0;
     174             : }
     175             : 
     176             : #endif

Generated by: LCOV version 1.14