LCOV - code coverage report
Current view: top level - src/utils - Calculators.C (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #31405 (292dce) with base fef103 Lines: 142 155 91.6 %
Date: 2025-09-04 07:57:52 Functions: 38 39 97.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "Calculators.h"
      11             : 
      12             : namespace StochasticTools
      13             : {
      14             : 
      15             : MultiMooseEnum
      16        2697 : makeCalculatorEnum()
      17             : {
      18             :   return MultiMooseEnum(
      19        5394 :       "min=0 max=1 sum=2 mean=3 stddev=4 norm2=5 ratio=6 stderr=7 median=8 meanabs=9");
      20             : }
      21             : 
      22             : // MEAN ////////////////////////////////////////////////////////////////////////////////////////////
      23             : template <typename InType, typename OutType>
      24             : void
      25    14146398 : Mean<InType, OutType>::initialize()
      26             : {
      27    14146398 :   _count = 0;
      28    14146398 :   _sum = OutType();
      29    14146398 : }
      30             : 
      31             : template <typename InType, typename OutType>
      32             : void
      33   930758340 : Mean<InType, OutType>::update(const typename InType::value_type & val)
      34             : {
      35  1071346788 :   _count++;
      36  1071346788 :   _sum += static_cast<OutType>(val);
      37   930758340 : }
      38             : 
      39             : template <typename InType, typename OutType>
      40             : void
      41    13922110 : Mean<InType, OutType>::finalize(bool is_distributed)
      42             : {
      43    13922110 :   if (is_distributed)
      44             :   {
      45     4097202 :     this->_communicator.sum(_count);
      46     4097202 :     this->_communicator.sum(_sum);
      47             :   }
      48    13922110 :   if (_count > 0)
      49    13922110 :     _sum /= static_cast<OutType>(_count);
      50    13922110 : }
      51             : 
      52             : // MEAN ABS ////////////////////////////////////////////////////////////////////////////////////////
      53             : template <typename InType, typename OutType>
      54             : void
      55   140588448 : MeanAbsoluteValue<InType, OutType>::update(const typename InType::value_type & val)
      56             : {
      57   140588448 :   Mean<InType, OutType>::update(std::abs(val));
      58   140588448 : }
      59             : 
      60             : // SUM /////////////////////////////////////////////////////////////////////////////////////////////
      61             : template <typename InType, typename OutType>
      62             : void
      63      224288 : Sum<InType, OutType>::finalize(bool is_distributed)
      64             : {
      65      224288 :   if (is_distributed)
      66        4193 :     this->_communicator.sum(this->_sum);
      67      224288 : }
      68             : 
      69             : // STDDEV //////////////////////////////////////////////////////////////////////////////////////////
      70             : template <typename InType, typename OutType>
      71             : void
      72    12072671 : StdDev<InType, OutType>::initialize()
      73             : {
      74    12072671 :   _count = 0;
      75    12072671 :   _sum = OutType();
      76    12072671 :   _sum_of_square = OutType();
      77    12072671 : }
      78             : 
      79             : template <typename InType, typename OutType>
      80             : void
      81   903903534 : StdDev<InType, OutType>::update(const typename InType::value_type & val)
      82             : {
      83   903903534 :   _count++;
      84   903903534 :   _sum += static_cast<OutType>(val);
      85   903903534 :   _sum_of_square += MathUtils::pow(static_cast<OutType>(val), 2);
      86   903903534 : }
      87             : 
      88             : template <typename InType, typename OutType>
      89             : void
      90    12072671 : StdDev<InType, OutType>::finalize(bool is_distributed)
      91             : {
      92    12072671 :   if (is_distributed)
      93             :   {
      94     2734154 :     this->_communicator.sum(_count);
      95     2734154 :     this->_communicator.sum(_sum);
      96     2734154 :     this->_communicator.sum(_sum_of_square);
      97             :   }
      98             : 
      99    12072671 :   if (_count <= 1)
     100           0 :     _sum_of_square = 0;
     101             :   else
     102    12072671 :     _sum_of_square = std::sqrt(std::abs(_sum_of_square - _sum * _sum / _count) / (_count - 1));
     103    12072671 : }
     104             : 
     105             : // STDERR //////////////////////////////////////////////////////////////////////////////////////////
     106             : template <typename InType, typename OutType>
     107             : void
     108      264303 : StdErr<InType, OutType>::finalize(bool is_distributed)
     109             : {
     110      264303 :   StdDev<InType, OutType>::finalize(is_distributed);
     111      264303 :   this->_sum_of_square /= std::sqrt(this->_count);
     112      264303 : }
     113             : 
     114             : // RATIO ///////////////////////////////////////////////////////////////////////////////////////////
     115             : template <typename InType, typename OutType>
     116             : void
     117      660920 : Ratio<InType, OutType>::initialize()
     118             : {
     119      660920 :   _min = std::numeric_limits<OutType>::max();
     120      660920 :   _max = std::numeric_limits<OutType>::min();
     121      660920 : }
     122             : 
     123             : template <typename InType, typename OutType>
     124             : void
     125     3305185 : Ratio<InType, OutType>::update(const typename InType::value_type & val)
     126             : {
     127     3305185 :   if (_min > val)
     128     1259288 :     _min = static_cast<OutType>(val);
     129     3305185 :   if (_max < val)
     130     1270039 :     _max = static_cast<OutType>(val);
     131     3305185 : }
     132             : 
     133             : template <typename InType, typename OutType>
     134             : void
     135      660920 : Ratio<InType, OutType>::finalize(bool is_distributed)
     136             : {
     137      660920 :   if (is_distributed)
     138             :   {
     139         657 :     this->_communicator.min(_min);
     140         657 :     this->_communicator.max(_max);
     141             :   }
     142      660920 : }
     143             : 
     144             : // L2NORM //////////////////////////////////////////////////////////////////////////////////////////
     145             : template <typename InType, typename OutType>
     146             : void
     147      220314 : L2Norm<InType, OutType>::initialize()
     148             : {
     149      220314 :   _l2_norm = OutType();
     150      220314 : }
     151             : 
     152             : template <typename InType, typename OutType>
     153             : void
     154     1101765 : L2Norm<InType, OutType>::update(const typename InType::value_type & val)
     155             : {
     156     1101765 :   _l2_norm += MathUtils::pow(static_cast<OutType>(val), 2);
     157     1101765 : }
     158             : 
     159             : template <typename InType, typename OutType>
     160             : void
     161      220314 : L2Norm<InType, OutType>::finalize(bool is_distributed)
     162             : {
     163      220314 :   if (is_distributed)
     164         219 :     this->_communicator.sum(_l2_norm);
     165      220314 :   _l2_norm = std::sqrt(_l2_norm);
     166      220314 : }
     167             : 
     168             : // MEDIAN //////////////////////////////////////////////////////////////////////////////////////////
     169             : template <typename InType, typename OutType>
     170             : void
     171      220193 : Median<InType, OutType>::initialize()
     172             : {
     173      220193 :   _storage.clear();
     174      220193 : }
     175             : 
     176             : template <typename InType, typename OutType>
     177             : void
     178     1100830 : Median<InType, OutType>::update(const typename InType::value_type & val)
     179             : {
     180     1100830 :   _storage.push_back(static_cast<OutType>(val));
     181     1100830 : }
     182             : 
     183             : template <typename InType, typename OutType>
     184             : void
     185      220193 : Median<InType, OutType>::finalize(bool is_distributed)
     186             : {
     187             :   // Make sure we aren't doing anything silly like taking the median of an empty vector
     188      220193 :   _median = OutType();
     189      220193 :   auto count = _storage.size();
     190      220193 :   if (is_distributed)
     191         153 :     this->_communicator.sum(count);
     192      220193 :   if (count == 0)
     193      220085 :     return;
     194             : 
     195      220193 :   if (!is_distributed || this->n_processors() == 1)
     196             :   {
     197      220085 :     std::sort(_storage.begin(), _storage.end());
     198      220085 :     if (count % 2)
     199      220040 :       _median = _storage[count / 2];
     200             :     else
     201          45 :       _median += (_storage[count / 2] + _storage[count / 2 - 1]) / 2;
     202      220085 :     return;
     203             :   }
     204             : 
     205         108 :   dof_id_type kgt = count % 2 ? (count / 2) : (count / 2 - 1);
     206             :   dof_id_type klt = kgt;
     207         324 :   while (true)
     208             :   {
     209             :     // Gather all sizes and figure out current number of values
     210         324 :     std::vector<std::size_t> sz = {_storage.size()};
     211         324 :     this->_communicator.allgather(sz);
     212         324 :     dof_id_type n = std::accumulate(sz.begin(), sz.end(), 0);
     213             : 
     214             :     // Choose the first value for the first processor with values
     215         324 :     for (const auto & i : index_range(sz))
     216         324 :       if (sz[i])
     217             :       {
     218         324 :         if (this->processor_id() == i)
     219         162 :           _median = _storage[0];
     220         324 :         this->_communicator.broadcast(_median, i);
     221             :         break;
     222             :       }
     223             : 
     224             :     // Count number of values greater than, less than, and equal to _median
     225         324 :     std::vector<dof_id_type> m(3, 0);
     226        1134 :     for (const auto & val : _storage)
     227             :     {
     228         810 :       if (_median < val)
     229         648 :         m[0]++;
     230         162 :       else if (val < _median)
     231           0 :         m[1]++;
     232             :     }
     233         324 :     this->_communicator.sum(m);
     234         324 :     m[2] = n - m[0] - m[1];
     235             : 
     236             :     // Remove greater than equal to
     237         324 :     if ((m[0] + m[2]) <= kgt)
     238             :     {
     239           0 :       _storage.erase(std::remove_if(_storage.begin(),
     240             :                                     _storage.end(),
     241           0 :                                     [this](const OutType & val) { return val >= _median; }),
     242             :                      _storage.end());
     243           0 :       kgt -= m[0] + m[2];
     244             :     }
     245             :     // Remove less than equal to
     246         324 :     else if ((m[1] + m[2]) <= klt)
     247             :     {
     248         216 :       _storage.erase(std::remove_if(_storage.begin(),
     249             :                                     _storage.end(),
     250         594 :                                     [this](const OutType & val) { return val <= _median; }),
     251             :                      _storage.end());
     252         216 :       klt -= m[1] + m[2];
     253             :     }
     254             :     // If the number of points is odd, then we've found it
     255         108 :     else if (count % 2)
     256             :       break;
     257             :     // Get average of the two middle numbers
     258             :     else
     259             :     {
     260             :       OutType num2;
     261             :       // Find the next greater than
     262         108 :       if (m[0] > kgt)
     263             :       {
     264         108 :         num2 = std::numeric_limits<OutType>::max();
     265         324 :         for (const auto & val : _storage)
     266         216 :           if (_median < val && val < num2)
     267          54 :             num2 = val;
     268         108 :         this->_communicator.min(num2);
     269             :       }
     270             :       // Find the next less than
     271           0 :       else if (m[1] > klt)
     272             :       {
     273           0 :         num2 = std::numeric_limits<OutType>::min();
     274           0 :         for (const auto & val : _storage)
     275           0 :           if (val < _median && num2 < val)
     276           0 :             num2 += val;
     277           0 :         this->_communicator.max(num2);
     278             :       }
     279             :       // Otherwise we know the other number is equal
     280             :       else
     281           0 :         num2 = _median;
     282             : 
     283         108 :       _median = (_median + num2) / 2;
     284             :       break;
     285             :     }
     286             :   }
     287             : }
     288             : 
     289             : // CalculatorBuilder
     290             : // //////////////////////////////////////////////////////////////////////////////////
     291             : template <typename InType, typename OutType>
     292             : std::unique_ptr<Calculator<InType, OutType>>
     293       12364 : CalculatorBuilder<InType, OutType>::build(const MooseEnumItem & item,
     294             :                                           const libMesh::ParallelObject & other)
     295             : {
     296       12364 :   if (item == "min")
     297         215 :     return std::make_unique<Min<InType, OutType>>(other, item);
     298             : 
     299       12149 :   else if (item == "max")
     300         215 :     return std::make_unique<Max<InType, OutType>>(other, item);
     301             : 
     302       11934 :   else if (item == "sum")
     303        2903 :     return std::make_unique<Sum<InType, OutType>>(other, item);
     304             : 
     305        9031 :   else if (item == "mean" || item == "average") // average is deprecated
     306        4358 :     return std::make_unique<Mean<InType, OutType>>(other, item);
     307             : 
     308        4673 :   else if (item == "stddev")
     309        3889 :     return std::make_unique<StdDev<InType, OutType>>(other, item);
     310             : 
     311         784 :   else if (item == "stderr")
     312         210 :     return std::make_unique<StdErr<InType, OutType>>(other, item);
     313             : 
     314         574 :   else if (item == "norm2")
     315         215 :     return std::make_unique<L2Norm<InType, OutType>>(other, item);
     316             : 
     317         359 :   else if (item == "ratio")
     318         187 :     return std::make_unique<Ratio<InType, OutType>>(other, item);
     319             : 
     320         172 :   else if (item == "median")
     321          70 :     return std::make_unique<Median<InType, OutType>>(other, item);
     322             : 
     323         102 :   else if (item == "meanabs")
     324         102 :     return std::make_unique<MeanAbsoluteValue<InType, OutType>>(other, item);
     325             : 
     326           0 :   ::mooseError("Failed to create Statistics::Calculator object for ", item);
     327             :   return nullptr;
     328             : }
     329             : 
     330             : #define createCalculators(InType, OutType)                                                         \
     331             :   template class Mean<InType, OutType>;                                                            \
     332             :   template class Max<InType, OutType>;                                                             \
     333             :   template class Min<InType, OutType>;                                                             \
     334             :   template class Sum<InType, OutType>;                                                             \
     335             :   template class StdDev<InType, OutType>;                                                          \
     336             :   template class StdErr<InType, OutType>;                                                          \
     337             :   template class Ratio<InType, OutType>;                                                           \
     338             :   template class L2Norm<InType, OutType>;                                                          \
     339             :   template class Median<InType, OutType>;                                                          \
     340             :   template struct CalculatorBuilder<InType, OutType>
     341             : 
     342             : createCalculators(std::vector<Real>, Real);
     343             : createCalculators(std::vector<int>, Real);
     344             : 
     345             : } // StocasticTools namespace

Generated by: LCOV version 1.14