1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 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>
l2_norm()37 Real StatisticsVector<T>::l2_norm() const
38 {
39   Real normsq = 0.;
40   const dof_id_type n = cast_int<dof_id_type>(this->size());
41   for (dof_id_type i = 0; i != n; ++i)
42     normsq += ((*this)[i] * (*this)[i]);
43 
44   return std::sqrt(normsq);
45 }
46 
47 
48 template <typename T>
minimum()49 T StatisticsVector<T>::minimum() const
50 {
51   LOG_SCOPE ("minimum()", "StatisticsVector");
52 
53   const T min = *(std::min_element(this->begin(), this->end()));
54 
55   return min;
56 }
57 
58 
59 
60 
61 template <typename T>
maximum()62 T StatisticsVector<T>::maximum() const
63 {
64   LOG_SCOPE ("maximum()", "StatisticsVector");
65 
66   const T max = *(std::max_element(this->begin(), this->end()));
67 
68   return max;
69 }
70 
71 
72 
73 
74 template <typename T>
mean()75 Real StatisticsVector<T>::mean() const
76 {
77   LOG_SCOPE ("mean()", "StatisticsVector");
78 
79   const dof_id_type n = cast_int<dof_id_type>(this->size());
80 
81   Real the_mean = 0;
82 
83   for (dof_id_type i=0; i<n; i++)
84     {
85       the_mean += ( static_cast<Real>((*this)[i]) - the_mean ) /
86         static_cast<Real>(i + 1);
87     }
88 
89   return the_mean;
90 }
91 
92 
93 
94 
95 template <typename T>
median()96 Real StatisticsVector<T>::median()
97 {
98   const dof_id_type n = cast_int<dof_id_type>(this->size());
99 
100   if (n == 0)
101     return 0.;
102 
103   LOG_SCOPE ("median()", "StatisticsVector");
104 
105   std::sort(this->begin(), this->end());
106 
107   const dof_id_type lhs = (n-1) / 2;
108   const dof_id_type rhs = n / 2;
109 
110   Real the_median = 0;
111 
112 
113   if (lhs == rhs)
114     {
115       the_median = static_cast<Real>((*this)[lhs]);
116     }
117 
118   else
119     {
120       the_median = ( static_cast<Real>((*this)[lhs]) +
121                      static_cast<Real>((*this)[rhs]) ) / 2.0;
122     }
123 
124   return the_median;
125 }
126 
127 
128 
129 
130 template <typename T>
median()131 Real StatisticsVector<T>::median() const
132 {
133   StatisticsVector<T> sv = (*this);
134 
135   return sv.median();
136 }
137 
138 
139 
140 
141 template <typename T>
variance(const Real mean_in)142 Real StatisticsVector<T>::variance(const Real mean_in) const
143 {
144   const dof_id_type n = cast_int<dof_id_type>(this->size());
145 
146   LOG_SCOPE ("variance()", "StatisticsVector");
147 
148   Real the_variance = 0;
149 
150   for (dof_id_type i=0; i<n; i++)
151     {
152       const Real delta = ( static_cast<Real>((*this)[i]) - mean_in );
153       the_variance += (delta * delta - the_variance) /
154         static_cast<Real>(i + 1);
155     }
156 
157   if (n > 1)
158     the_variance *= static_cast<Real>(n) / static_cast<Real>(n - 1);
159 
160   return the_variance;
161 }
162 
163 
164 template <typename T>
normalize()165 void StatisticsVector<T>::normalize()
166 {
167   const dof_id_type n = cast_int<dof_id_type>(this->size());
168   const Real max = this->maximum();
169 
170   for (dof_id_type i=0; i<n; i++)
171     (*this)[i] = static_cast<T>((*this)[i] / max);
172 }
173 
174 
175 
176 
177 
178 template <typename T>
histogram(std::vector<dof_id_type> & bin_members,unsigned int n_bins)179 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   libmesh_assert (n_bins>0);
184 
185   const dof_id_type n = cast_int<dof_id_type>(this->size());
186 
187   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   Real min      = static_cast<Real>(this->minimum());
192   Real max      = static_cast<Real>(this->maximum());
193   Real bin_size = (max - min) / static_cast<Real>(n_bins);
194 
195   LOG_SCOPE ("histogram()", "StatisticsVector");
196 
197   std::vector<Real> bin_bounds(n_bins+1);
198   for (auto i : index_range(bin_bounds))
199     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   bin_bounds.back() += 1.e-6 * bin_size;
205 
206   // This vector will store the number of members each bin has.
207   bin_members.resize(n_bins);
208 
209   dof_id_type data_index = 0;
210   for (auto j : index_range(bin_members)) // bin vector indexing
211     {
212       // libMesh::out << "(debug) Filling bin " << j << std::endl;
213 
214       for (dof_id_type i=data_index; i<n; i++) // data vector indexing
215         {
216           //libMesh::out << "(debug) Processing index=" << i << std::endl;
217           Real current_val = static_cast<Real>( (*this)[i] );
218 
219           // There may be entries in the vector smaller than the value
220           // reported by this->minimum().  (e.g. inactive elements in an
221           // ErrorVector.)  We just skip entries like that.
222           if (current_val < min)
223             {
224               //     libMesh::out << "(debug) Skipping entry v[" << i << "]="
225               //       << (*this)[i]
226               //       << " which is less than the min value: min="
227               //       << min << std::endl;
228               continue;
229             }
230 
231           if (current_val > bin_bounds[j+1]) // if outside the current bin (bin[j] is bounded
232             // by bin_bounds[j] and bin_bounds[j+1])
233             {
234               // libMesh::out.precision(16);
235               //     libMesh::out.setf(std::ios_base::fixed);
236               //     libMesh::out << "(debug) (*this)[i]= " << (*this)[i]
237               //       << " is greater than bin_bounds[j+1]="
238               //      << bin_bounds[j+1] << std::endl;
239               data_index = i; // start searching here for next bin
240               break; // go to next bin
241             }
242 
243           // Otherwise, increment current bin's count
244           bin_members[j]++;
245           // libMesh::out << "(debug) Binned index=" << i << std::endl;
246         }
247     }
248 
249 #ifdef DEBUG
250   // Check the number of binned entries
251   const dof_id_type n_binned = std::accumulate(bin_members.begin(),
252                                                bin_members.end(),
253                                                static_cast<dof_id_type>(0),
254                                                std::plus<dof_id_type>());
255 
256   if (n != n_binned)
257     {
258       libMesh::out << "Warning: The number of binned entries, n_binned="
259                    << n_binned
260                    << ", did not match the total number of entries, n="
261                    << n << "." << std::endl;
262     }
263 #endif
264 }
265 
266 
267 
268 
269 
270 template <typename T>
plot_histogram(const processor_id_type my_procid,const std::string & filename,unsigned int n_bins)271 void StatisticsVector<T>::plot_histogram(const processor_id_type my_procid,
272                                          const std::string & filename,
273                                          unsigned int n_bins)
274 {
275   // First generate the histogram with the desired number of bins
276   std::vector<dof_id_type> bin_members;
277   this->histogram(bin_members, n_bins);
278 
279   // The max, min and bin size are used to generate x-axis values.
280   T min      = this->minimum();
281   T max      = this->maximum();
282   T bin_size = (max - min) / static_cast<T>(n_bins);
283 
284   // On processor 0: Write histogram to file
285   if (my_procid==0)
286     {
287       std::ofstream out_stream (filename.c_str());
288 
289       out_stream << "clear all\n";
290       out_stream << "clf\n";
291       //out_stream << "x=linspace(" << min << "," << max << "," << n_bins+1 << ");\n";
292 
293       // abscissa values are located at the center of each bin.
294       out_stream << "x=[";
295       for (auto i : index_range(bin_members))
296         {
297           out_stream << min + (Real(i)+0.5)*bin_size << " ";
298         }
299       out_stream << "];\n";
300 
301       out_stream << "y=[";
302       for (auto bmi : bin_members)
303         {
304           out_stream << bmi << " ";
305         }
306       out_stream << "];\n";
307       out_stream << "bar(x,y);\n";
308     }
309 }
310 
311 
312 
313 template <typename T>
histogram(std::vector<dof_id_type> & bin_members,unsigned int n_bins)314 void StatisticsVector<T>::histogram(std::vector<dof_id_type> & bin_members,
315                                     unsigned int n_bins) const
316 {
317   StatisticsVector<T> sv = (*this);
318 
319   return sv.histogram(bin_members, n_bins);
320 }
321 
322 
323 
324 
325 template <typename T>
cut_below(Real cut)326 std::vector<dof_id_type> StatisticsVector<T>::cut_below(Real cut) const
327 {
328   LOG_SCOPE ("cut_below()", "StatisticsVector");
329 
330   const dof_id_type n = cast_int<dof_id_type>(this->size());
331 
332   std::vector<dof_id_type> cut_indices;
333   cut_indices.reserve(n/2);  // Arbitrary
334 
335   for (dof_id_type i=0; i<n; i++)
336     {
337       if ((*this)[i] < cut)
338         {
339           cut_indices.push_back(i);
340         }
341     }
342 
343   return cut_indices;
344 }
345 
346 
347 
348 
349 template <typename T>
cut_above(Real cut)350 std::vector<dof_id_type> StatisticsVector<T>::cut_above(Real cut) const
351 {
352   LOG_SCOPE ("cut_above()", "StatisticsVector");
353 
354   const dof_id_type n = cast_int<dof_id_type>(this->size());
355 
356   std::vector<dof_id_type> cut_indices;
357   cut_indices.reserve(n/2);  // Arbitrary
358 
359   for (dof_id_type i=0; i<n; i++)
360     if ((*this)[i] > cut)
361       cut_indices.push_back(i);
362 
363   return cut_indices;
364 }
365 
366 
367 
368 
369 //------------------------------------------------------------
370 // Explicit Instantiations
371 template class StatisticsVector<float>;
372 template class StatisticsVector<double>;
373 #ifdef LIBMESH_DEFAULT_TRIPLE_PRECISION
374 template class StatisticsVector<long double>;
375 #endif
376 #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
377 template class StatisticsVector<Real>;
378 #endif
379 template class StatisticsVector<int>;
380 template class StatisticsVector<unsigned int>;
381 
382 } // namespace libMesh
383