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