LCOV - code coverage report
Current view: top level - src/utils - statistics.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 10 132 7.6 %
Date: 2025-08-19 19:27:09 Functions: 2 60 3.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // C++ includes
      20             : #include <algorithm> // for std::min_element, std::max_element
      21             : #include <fstream> // std::ofstream
      22             : #include <numeric> // std::accumulate
      23             : 
      24             : // Local includes
      25             : #include "libmesh/statistics.h"
      26             : #include "libmesh/int_range.h"
      27             : #include "libmesh/libmesh_logging.h"
      28             : 
      29             : namespace libMesh
      30             : {
      31             : 
      32             : 
      33             : 
      34             : // ------------------------------------------------------------
      35             : // StatisticsVector class member functions
      36             : template <typename T>
      37         921 : Real StatisticsVector<T>::l2_norm() const
      38             : {
      39          26 :   Real normsq = 0.;
      40          52 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
      41      162545 :   for (dof_id_type i = 0; i != n; ++i)
      42      166180 :     normsq += ((*this)[i] * (*this)[i]);
      43             : 
      44         921 :   return std::sqrt(normsq);
      45             : }
      46             : 
      47             : 
      48             : template <typename T>
      49           0 : T StatisticsVector<T>::minimum() const
      50             : {
      51           0 :   LOG_SCOPE ("minimum()", "StatisticsVector");
      52             : 
      53           0 :   const T min = *(std::min_element(this->begin(), this->end()));
      54             : 
      55           0 :   return min;
      56             : }
      57             : 
      58             : 
      59             : 
      60             : 
      61             : template <typename T>
      62         779 : T StatisticsVector<T>::maximum() const
      63             : {
      64          22 :   LOG_SCOPE ("maximum()", "StatisticsVector");
      65             : 
      66         801 :   const T max = *(std::max_element(this->begin(), this->end()));
      67             : 
      68         801 :   return max;
      69             : }
      70             : 
      71             : 
      72             : 
      73             : 
      74             : template <typename T>
      75           0 : Real StatisticsVector<T>::mean() const
      76             : {
      77           0 :   LOG_SCOPE ("mean()", "StatisticsVector");
      78             : 
      79           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
      80             : 
      81           0 :   Real the_mean = 0;
      82             : 
      83           0 :   for (dof_id_type i=0; i<n; i++)
      84             :     {
      85           0 :       the_mean += ( static_cast<Real>((*this)[i]) - the_mean ) /
      86           0 :         static_cast<Real>(i + 1);
      87             :     }
      88             : 
      89           0 :   return the_mean;
      90             : }
      91             : 
      92             : 
      93             : 
      94             : 
      95             : template <typename T>
      96           0 : Real StatisticsVector<T>::median()
      97             : {
      98           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
      99             : 
     100           0 :   if (n == 0)
     101           0 :     return 0.;
     102             : 
     103           0 :   LOG_SCOPE ("median()", "StatisticsVector");
     104             : 
     105           0 :   std::sort(this->begin(), this->end());
     106             : 
     107           0 :   const dof_id_type lhs = (n-1) / 2;
     108           0 :   const dof_id_type rhs = n / 2;
     109             : 
     110           0 :   Real the_median = 0;
     111             : 
     112             : 
     113           0 :   if (lhs == rhs)
     114             :     {
     115           0 :       the_median = static_cast<Real>((*this)[lhs]);
     116             :     }
     117             : 
     118             :   else
     119             :     {
     120           0 :       the_median = ( static_cast<Real>((*this)[lhs]) +
     121           0 :                      static_cast<Real>((*this)[rhs]) ) / 2.0;
     122             :     }
     123             : 
     124           0 :   return the_median;
     125             : }
     126             : 
     127             : 
     128             : 
     129             : 
     130             : template <typename T>
     131           0 : Real StatisticsVector<T>::median() const
     132             : {
     133           0 :   StatisticsVector<T> sv = (*this);
     134             : 
     135           0 :   return sv.median();
     136             : }
     137             : 
     138             : 
     139             : 
     140             : 
     141             : template <typename T>
     142           0 : Real StatisticsVector<T>::variance(const Real mean_in) const
     143             : {
     144           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
     145             : 
     146           0 :   LOG_SCOPE ("variance()", "StatisticsVector");
     147             : 
     148           0 :   Real the_variance = 0;
     149             : 
     150           0 :   for (dof_id_type i=0; i<n; i++)
     151             :     {
     152           0 :       const Real delta = ( static_cast<Real>((*this)[i]) - mean_in );
     153           0 :       the_variance += (delta * delta - the_variance) /
     154           0 :         static_cast<Real>(i + 1);
     155             :     }
     156             : 
     157           0 :   if (n > 1)
     158           0 :     the_variance *= static_cast<Real>(n) / static_cast<Real>(n - 1);
     159             : 
     160           0 :   return the_variance;
     161             : }
     162             : 
     163             : 
     164             : template <typename T>
     165           0 : void StatisticsVector<T>::normalize()
     166             : {
     167           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
     168           0 :   const Real max = this->maximum();
     169             : 
     170           0 :   for (dof_id_type i=0; i<n; i++)
     171           0 :     (*this)[i] = static_cast<T>((*this)[i] / max);
     172           0 : }
     173             : 
     174             : 
     175             : 
     176             : 
     177             : 
     178             : template <typename T>
     179           0 : void StatisticsVector<T>::histogram(std::vector<dof_id_type> & bin_members,
     180             :                                     unsigned int n_bins)
     181             : {
     182             :   // Must have at least 1 bin
     183           0 :   libmesh_assert (n_bins>0);
     184             : 
     185           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
     186             : 
     187           0 :   std::sort(this->begin(), this->end());
     188             : 
     189             :   // The StatisticsVector can hold both integer and float types.
     190             :   // We will define all the bins, etc. using Reals.
     191           0 :   Real min      = static_cast<Real>(this->minimum());
     192           0 :   Real max      = static_cast<Real>(this->maximum());
     193           0 :   Real bin_size = (max - min) / static_cast<Real>(n_bins);
     194             : 
     195           0 :   LOG_SCOPE ("histogram()", "StatisticsVector");
     196             : 
     197           0 :   std::vector<Real> bin_bounds(n_bins+1);
     198           0 :   for (auto i : index_range(bin_bounds))
     199           0 :     bin_bounds[i] = min + Real(i) * bin_size;
     200             : 
     201             :   // Give the last bin boundary a little wiggle room: we don't want
     202             :   // it to be just barely less than the max, otherwise our bin test below
     203             :   // may fail.
     204           0 :   bin_bounds.back() += 1.e-6 * bin_size;
     205             : 
     206             :   // This vector will store the number of members each bin has.
     207           0 :   bin_members.resize(n_bins);
     208             : 
     209             : #ifdef DEBUG
     210             :   // we may not bin all values.
     211             :   // Those we skip on purpose (e.g. inactive elements in an ErrorVector)
     212             :   // should also not appear in the consistency-check below.
     213           0 :   unsigned int unbinned=0;
     214             : #endif
     215             : 
     216           0 :   dof_id_type data_index = 0;
     217           0 :   for (auto j : index_range(bin_members)) // bin vector indexing
     218             :     {
     219             :       // libMesh::out << "(debug) Filling bin " << j << std::endl;
     220             : 
     221           0 :       for (dof_id_type i=data_index; i<n; i++) // data vector indexing
     222             :         {
     223             :           //libMesh::out << "(debug) Processing index=" << i << std::endl;
     224           0 :           Real current_val = static_cast<Real>( (*this)[i] );
     225             : 
     226             :           // There may be entries in the vector smaller than the value
     227             :           // reported by this->minimum().  (e.g. inactive elements in an
     228             :           // ErrorVector.)  We just skip entries like that.
     229           0 :           if (current_val < min)
     230             :             {
     231             : #ifdef DEBUG
     232           0 :                unbinned++;
     233             : #endif
     234             :               //     libMesh::out << "(debug) Skipping entry v[" << i << "]="
     235             :               //       << (*this)[i]
     236             :               //       << " which is less than the min value: min="
     237             :               //       << min << std::endl;
     238           0 :               continue;
     239             :             }
     240             : 
     241           0 :           if (current_val > bin_bounds[j+1]) // if outside the current bin (bin[j] is bounded
     242             :             // by bin_bounds[j] and bin_bounds[j+1])
     243             :             {
     244             :               // libMesh::out.precision(16);
     245             :               //     libMesh::out.setf(std::ios_base::fixed);
     246             :               //     libMesh::out << "(debug) (*this)[i]= " << (*this)[i]
     247             :               //       << " is greater than bin_bounds[j+1]="
     248             :               //      << bin_bounds[j+1] << std::endl;
     249           0 :               data_index = i; // start searching here for next bin
     250           0 :               break; // go to next bin
     251             :             }
     252             : 
     253             :           // Otherwise, increment current bin's count
     254           0 :           bin_members[j]++;
     255             :           // libMesh::out << "(debug) Binned index=" << i << std::endl;
     256             : #ifdef DEBUG
     257           0 :           if (i== n-1) // we read the last 'i' only in the last bin.
     258           0 :              libmesh_assert_equal_to(j, bin_members.size()-1);
     259             : #endif
     260             :         }
     261             :     }
     262             : 
     263             : #ifdef DEBUG
     264             :   // Check the number of binned entries
     265           0 :   const dof_id_type n_binned = std::accumulate(bin_members.begin(),
     266             :                                                bin_members.end(),
     267             :                                                static_cast<dof_id_type>(0),
     268             :                                                std::plus<dof_id_type>());
     269             : 
     270           0 :   if (n-unbinned != n_binned)
     271             :     {
     272           0 :       libMesh::out << "Warning: The number of binned entries, n_binned="
     273           0 :                    << n_binned
     274           0 :                    << ", did not match the total number of binnable entries, n="
     275           0 :                    << n-unbinned << "." << std::endl;
     276             :     }
     277             : #endif
     278           0 : }
     279             : 
     280             : 
     281             : 
     282             : 
     283             : 
     284             : template <typename T>
     285           0 : void StatisticsVector<T>::plot_histogram(const processor_id_type my_procid,
     286             :                                          const std::string & filename,
     287             :                                          unsigned int n_bins)
     288             : {
     289             :   // First generate the histogram with the desired number of bins
     290           0 :   std::vector<dof_id_type> bin_members;
     291           0 :   this->histogram(bin_members, n_bins);
     292             : 
     293             :   // The max, min and bin size are used to generate x-axis values.
     294           0 :   T min      = this->minimum();
     295           0 :   T max      = this->maximum();
     296           0 :   T bin_size = (max - min) / static_cast<T>(n_bins);
     297             : 
     298             :   // On processor 0: Write histogram to file
     299           0 :   if (my_procid==0)
     300             :     {
     301           0 :       std::ofstream out_stream (filename.c_str());
     302             : 
     303           0 :       out_stream << "clear all\n";
     304           0 :       out_stream << "clf\n";
     305             :       //out_stream << "x=linspace(" << min << "," << max << "," << n_bins+1 << ");\n";
     306             : 
     307             :       // abscissa values are located at the center of each bin.
     308           0 :       out_stream << "x=[";
     309           0 :       for (auto i : index_range(bin_members))
     310             :         {
     311           0 :           out_stream << min + (Real(i)+0.5)*bin_size << " ";
     312             :         }
     313           0 :       out_stream << "];\n";
     314             : 
     315           0 :       out_stream << "y=[";
     316           0 :       for (auto bmi : bin_members)
     317             :         {
     318           0 :           out_stream << bmi << " ";
     319             :         }
     320           0 :       out_stream << "];\n";
     321           0 :       out_stream << "bar(x,y);\n";
     322           0 :     }
     323           0 : }
     324             : 
     325             : 
     326             : 
     327             : template <typename T>
     328           0 : void StatisticsVector<T>::histogram(std::vector<dof_id_type> & bin_members,
     329             :                                     unsigned int n_bins) const
     330             : {
     331           0 :   StatisticsVector<T> sv = (*this);
     332             : 
     333           0 :   return sv.histogram(bin_members, n_bins);
     334             : }
     335             : 
     336             : 
     337             : 
     338             : 
     339             : template <typename T>
     340           0 : std::vector<dof_id_type> StatisticsVector<T>::cut_below(Real cut) const
     341             : {
     342           0 :   LOG_SCOPE ("cut_below()", "StatisticsVector");
     343             : 
     344           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
     345             : 
     346           0 :   std::vector<dof_id_type> cut_indices;
     347           0 :   cut_indices.reserve(n/2);  // Arbitrary
     348             : 
     349           0 :   for (dof_id_type i=0; i<n; i++)
     350             :     {
     351           0 :       if ((*this)[i] < cut)
     352             :         {
     353           0 :           cut_indices.push_back(i);
     354             :         }
     355             :     }
     356             : 
     357           0 :   return cut_indices;
     358             : }
     359             : 
     360             : 
     361             : 
     362             : 
     363             : template <typename T>
     364           0 : std::vector<dof_id_type> StatisticsVector<T>::cut_above(Real cut) const
     365             : {
     366           0 :   LOG_SCOPE ("cut_above()", "StatisticsVector");
     367             : 
     368           0 :   const dof_id_type n = cast_int<dof_id_type>(this->size());
     369             : 
     370           0 :   std::vector<dof_id_type> cut_indices;
     371           0 :   cut_indices.reserve(n/2);  // Arbitrary
     372             : 
     373           0 :   for (dof_id_type i=0; i<n; i++)
     374           0 :     if ((*this)[i] > cut)
     375           0 :       cut_indices.push_back(i);
     376             : 
     377           0 :   return cut_indices;
     378             : }
     379             : 
     380             : 
     381             : 
     382             : 
     383             : //------------------------------------------------------------
     384             : // Explicit Instantiations
     385             : template class LIBMESH_EXPORT StatisticsVector<float>;
     386             : template class LIBMESH_EXPORT StatisticsVector<double>;
     387             : #ifdef LIBMESH_DEFAULT_TRIPLE_PRECISION
     388             : template class LIBMESH_EXPORT StatisticsVector<long double>;
     389             : #endif
     390             : #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
     391             : template class LIBMESH_EXPORT StatisticsVector<Real>;
     392             : #endif
     393             : template class LIBMESH_EXPORT StatisticsVector<int>;
     394             : template class LIBMESH_EXPORT StatisticsVector<unsigned int>;
     395             : 
     396             : } // namespace libMesh

Generated by: LCOV version 1.14