deal.II version GIT relicensing-2233-g9bd70d8389 2024-12-08 16:10:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
utilities.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2005 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#include <deal.II/base/config.h>
16
17// It's necessary to include winsock2.h before thread_local_storage.h,
18// because Intel implementation of TBB includes winsock.h,
19// and we'll get a conflict between winsock.h and winsock2.h otherwise.
20#ifdef DEAL_II_MSVC
21# include <winsock2.h>
22#endif
23
25#include <deal.II/base/mpi.h>
26#include <deal.II/base/point.h>
29
30#define BOOST_BIND_GLOBAL_PLACEHOLDERS
31#include <boost/archive/iterators/base64_from_binary.hpp>
32#include <boost/archive/iterators/binary_from_base64.hpp>
33#include <boost/archive/iterators/transform_width.hpp>
34#include <boost/iostreams/copy.hpp>
35#include <boost/lexical_cast.hpp>
36#include <boost/random.hpp>
37#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
38
39#include <algorithm>
40#include <bitset>
41#include <cctype>
42#include <cerrno>
43#include <cmath>
44#include <cstddef>
45#include <cstdio>
46#include <ctime>
47#include <fstream>
48#include <iomanip>
49#include <iostream>
50#include <limits>
51#include <sstream>
52#include <string>
53
54#if defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_GETHOSTNAME)
55# include <unistd.h>
56#endif
57
58#ifndef DEAL_II_MSVC
59# include <cstdlib>
60#endif
61
62
63#ifdef DEAL_II_WITH_TRILINOS
64# ifdef DEAL_II_WITH_MPI
68
69# include <Epetra_MpiComm.h>
70# include <Teuchos_DefaultComm.hpp>
71# endif
72# include <Epetra_SerialComm.h>
73# include <Teuchos_RCP.hpp>
74#endif
75
77
78
79namespace Utilities
80{
82 unsigned int,
83 unsigned int,
84 << "When trying to convert " << arg1 << " to a string with "
85 << arg2 << " digits");
86 DeclException1(ExcInvalidNumber, unsigned int, << "Invalid number " << arg1);
88 std::string,
89 << "Can't convert the string " << arg1
90 << " to the desired type");
91
92
93 std::string
98
99
100 namespace
101 {
102 template <int dim,
103 typename Number,
104 int effective_dim,
105 typename LongDouble,
106 typename Integer>
107 std::vector<std::array<std::uint64_t, effective_dim>>
108 inverse_Hilbert_space_filling_curve_effective(
109 const std::vector<Point<dim, Number>> &points,
110 const Point<dim, Number> &bl,
111 const std::array<LongDouble, dim> &extents,
112 const std::bitset<dim> &valid_extents,
113 const int min_bits,
114 const Integer max_int)
115 {
116 std::vector<std::array<Integer, effective_dim>> int_points(points.size());
117
118 for (unsigned int i = 0; i < points.size(); ++i)
119 {
120 // convert into integers:
121 unsigned int eff_d = 0;
122 for (unsigned int d = 0; d < dim; ++d)
123 if (valid_extents[d])
124 {
125 Assert(extents[d] > 0, ExcInternalError());
126 const LongDouble v = (static_cast<LongDouble>(points[i][d]) -
127 static_cast<LongDouble>(bl[d])) /
128 extents[d];
129 Assert(v >= 0. && v <= 1., ExcInternalError());
130 AssertIndexRange(eff_d, effective_dim);
131 int_points[i][eff_d] =
132 static_cast<Integer>(v * static_cast<LongDouble>(max_int));
133 ++eff_d;
134 }
135 }
136
137 // note that we call this with "min_bits"
138 return inverse_Hilbert_space_filling_curve<effective_dim>(int_points,
139 min_bits);
140 }
141 } // namespace
142
143 template <int dim, typename Number>
144 std::vector<std::array<std::uint64_t, dim>>
146 const std::vector<Point<dim, Number>> &points,
147 const int bits_per_dim)
148 {
149 using Integer = std::uint64_t;
150 // take floating point number hopefully with mantissa >= 64bit
151 using LongDouble = long double;
152
153 // return if there is nothing to do
154 if (points.empty())
155 return std::vector<std::array<std::uint64_t, dim>>();
156
157 // get bounding box:
158 Point<dim, Number> bl = points[0], tr = points[0];
159 for (const auto &p : points)
160 for (unsigned int d = 0; d < dim; ++d)
161 {
162 const double cid = p[d];
163 bl[d] = std::min(cid, bl[d]);
164 tr[d] = std::max(cid, tr[d]);
165 }
166
167 std::array<LongDouble, dim> extents;
168 std::bitset<dim> valid_extents;
169 for (unsigned int i = 0; i < dim; ++i)
170 {
171 extents[i] =
172 static_cast<LongDouble>(tr[i]) - static_cast<LongDouble>(bl[i]);
173 valid_extents[i] = (extents[i] > 0.);
174 }
175
176 // make sure our conversion from fractional coordinates to
177 // Integers work as expected, namely our cast (LongDouble)max_int
178 const int min_bits =
179 std::min(bits_per_dim,
180 std::min(std::numeric_limits<Integer>::digits,
181 std::numeric_limits<LongDouble>::digits));
182
183 // based on that get the maximum integer:
184 const Integer max_int = (min_bits == std::numeric_limits<Integer>::digits ?
185 std::numeric_limits<Integer>::max() :
186 (Integer(1) << min_bits) - 1);
187
188 const unsigned int effective_dim = valid_extents.count();
189 if (effective_dim == dim)
190 {
191 return inverse_Hilbert_space_filling_curve_effective<dim,
192 Number,
193 dim,
194 LongDouble,
195 Integer>(
196 points, bl, extents, valid_extents, min_bits, max_int);
197 }
198
199 // various degenerate cases
200 std::array<std::uint64_t, dim> zero_ind;
201 for (unsigned int d = 0; d < dim; ++d)
202 zero_ind[d] = 0;
203
204 std::vector<std::array<std::uint64_t, dim>> ind(points.size(), zero_ind);
205 // manually check effective_dim == 1 and effective_dim == 2
206 if (dim == 3 && effective_dim == 2)
207 {
208 const auto ind2 =
209 inverse_Hilbert_space_filling_curve_effective<dim,
210 Number,
211 2,
212 LongDouble,
213 Integer>(
214 points, bl, extents, valid_extents, min_bits, max_int);
215
216 for (unsigned int i = 0; i < ind.size(); ++i)
217 for (unsigned int d = 0; d < 2; ++d)
218 ind[i][d + 1] = ind2[i][d];
219
220 return ind;
221 }
222 else if (effective_dim == 1)
223 {
224 const auto ind1 =
225 inverse_Hilbert_space_filling_curve_effective<dim,
226 Number,
227 1,
228 LongDouble,
229 Integer>(
230 points, bl, extents, valid_extents, min_bits, max_int);
231
232 for (unsigned int i = 0; i < ind.size(); ++i)
233 ind[i][dim - 1] = ind1[i][0];
234
235 return ind;
236 }
237
238 // we should get here only if effective_dim == 0
239 Assert(effective_dim == 0, ExcInternalError());
240
241 // if the bounding box is degenerate in all dimensions,
242 // can't do much but exit gracefully by setting index according
243 // to the index of each point so that there is no re-ordering
244 for (unsigned int i = 0; i < points.size(); ++i)
245 ind[i][dim - 1] = i;
246
247 return ind;
248 }
249
250
251
252 template <int dim>
253 std::vector<std::array<std::uint64_t, dim>>
255 const std::vector<std::array<std::uint64_t, dim>> &points,
256 const int bits_per_dim)
257 {
258 using Integer = std::uint64_t;
259
260 std::vector<std::array<Integer, dim>> int_points(points);
261
262 std::vector<std::array<Integer, dim>> res(int_points.size());
263
264 // follow
265 // J. Skilling, Programming the Hilbert curve, AIP Conf. Proc. 707, 381
266 // (2004); http://dx.doi.org/10.1063/1.1751381 also see
267 // https://stackoverflow.com/questions/499166/mapping-n-dimensional-value-to-a-point-on-hilbert-curve
268 // https://gitlab.com/octopus-code/octopus/blob/develop/src/grid/hilbert.c
269 // https://github.com/trilinos/Trilinos/blob/master/packages/zoltan/src/hsfc/hsfc_hilbert.c
270 // (Zoltan_HSFC_InvHilbertXd)
271 // https://github.com/aditi137/Hilbert/blob/master/Hilbert/hilbert.cpp
272
273 // now we can map to 1d coordinate stored in Transpose format
274 // adopt AxestoTranspose function from the paper, that
275 // transforms in-place between geometrical axes and Hilbert transpose.
276 // Example: b=5 bits for each of n=3 coordinates.
277 // 15-bit Hilbert integer = A B C D E F G H I J K L M N O is
278 // stored as its Transpose
279 // X[0] = A D G J M X[2]|
280 // X[1] = B E H K N <-------> | /X[1]
281 // X[2] = C F I L O axes |/
282 // high low 0------ X[0]
283
284 // Depth of the Hilbert curve
285 Assert(bits_per_dim <= std::numeric_limits<Integer>::digits,
286 ExcMessage("This integer type can not hold " +
287 std::to_string(bits_per_dim) + " bits."));
288
289 const Integer M = Integer(1) << (bits_per_dim - 1); // largest bit
290
291 for (unsigned int index = 0; index < int_points.size(); ++index)
292 {
293 auto &X = int_points[index];
294 auto &L = res[index];
295
296 // Inverse undo
297 for (Integer q = M; q > 1; q >>= 1)
298 {
299 const Integer p = q - 1;
300 for (unsigned int i = 0; i < dim; ++i)
301 {
302 // invert
303 if (X[i] & q)
304 {
305 X[0] ^= p;
306 }
307 // exchange
308 else
309 {
310 const Integer t = (X[0] ^ X[i]) & p;
311 X[0] ^= t;
312 X[i] ^= t;
313 }
314 }
315 }
316
317 // Gray encode (inverse of decode)
318 for (unsigned int i = 1; i < dim; ++i)
319 X[i] ^= X[i - 1];
320
321 Integer t = 0;
322 for (Integer q = M; q > 1; q >>= 1)
323 if (X[dim - 1] & q)
324 t ^= q - 1;
325 for (unsigned int i = 0; i < dim; ++i)
326 X[i] ^= t;
327
328 // now we need to go from index stored in transpose format to
329 // consecutive format, which is better suited for comparators.
330 // we could interleave into some big unsigned int...
331 // https://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/
332 // https://stackoverflow.com/questions/4431522/given-2-16-bit-ints-can-i-interleave-those-bits-to-form-a-single-32-bit-int
333 // ...but we would loose spatial resolution!
334
335 // interleave using brute force, follow TransposetoLine from
336 // https://github.com/aditi137/Hilbert/blob/master/Hilbert/hilbert.cpp
337 {
338 Integer p = M;
339 unsigned int j = 0;
340 for (unsigned int i = 0; i < dim; ++i)
341 {
342 L[i] = 0;
343 // go through bits using a mask q
344 for (Integer q = M; q > 0; q >>= 1)
345 {
346 if (X[j] & p)
347 L[i] |= q;
348 if (++j == dim)
349 {
350 j = 0;
351 p >>= 1;
352 }
353 }
354 }
355 }
356
357 } // end of the loop over points
358
359 return res;
360 }
361
362
363
364 template <int dim>
365 std::uint64_t
366 pack_integers(const std::array<std::uint64_t, dim> &index,
367 const int bits_per_dim)
368 {
369 using Integer = std::uint64_t;
370
371 AssertIndexRange(bits_per_dim * dim, 65);
372 Assert(bits_per_dim > 0, ExcMessage("bits_per_dim should be positive"));
373
374 const Integer mask = (Integer(1) << bits_per_dim) - 1;
375
376 Integer res = 0;
377 for (unsigned int i = 0; i < dim; ++i)
378 {
379 // take bits_per_dim from each integer and shift them
380 const Integer v = (mask & index[dim - 1 - i]) << (bits_per_dim * i);
381 res |= v;
382 }
383 return res;
384 }
385
386
387
388 std::string
389 compress(const std::string &input)
390 {
391#ifdef DEAL_II_WITH_ZLIB
392 namespace bio = boost::iostreams;
393
394 std::stringstream compressed;
395 std::stringstream origin(input);
396
397 bio::filtering_streambuf<bio::input> out;
398 out.push(bio::gzip_compressor());
399 out.push(origin);
400 bio::copy(out, compressed);
401
402 return compressed.str();
403#else
404 return input;
405#endif
406 }
407
408
409
410 std::string
411 decompress(const std::string &compressed_input)
412 {
413#ifdef DEAL_II_WITH_ZLIB
414 namespace bio = boost::iostreams;
415
416 std::stringstream compressed(compressed_input);
417 std::stringstream decompressed;
418
419 bio::filtering_streambuf<bio::input> out;
420 out.push(bio::gzip_decompressor());
421 out.push(compressed);
422 bio::copy(out, decompressed);
423
424 return decompressed.str();
425#else
426 return compressed_input;
427#endif
428 }
429
430
431
432 std::string
433 encode_base64(const std::vector<unsigned char> &binary_input)
434 {
435 using namespace boost::archive::iterators;
436 using It = base64_from_binary<
437 transform_width<std::vector<unsigned char>::const_iterator, 6, 8>>;
438 auto base64 = std::string(It(binary_input.begin()), It(binary_input.end()));
439 // Add padding.
440 return base64.append((3 - binary_input.size() % 3) % 3, '=');
441 }
442
443
444
445 std::vector<unsigned char>
446 decode_base64(const std::string &base64_input)
447 {
448 using namespace boost::archive::iterators;
449 using It =
450 transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
451 auto binary = std::vector<unsigned char>(It(base64_input.begin()),
452 It(base64_input.end()));
453 // Remove padding.
454 auto length = base64_input.size();
455 if (binary.size() > 2 && base64_input[length - 1] == '=' &&
456 base64_input[length - 2] == '=')
457 {
458 binary.erase(binary.end() - 2, binary.end());
459 }
460 else if (binary.size() > 1 && base64_input[length - 1] == '=')
461 {
462 binary.erase(binary.end() - 1, binary.end());
463 }
464 return binary;
465 }
466
467
468
469 std::string
470 int_to_string(const unsigned int value, const unsigned int digits)
471 {
472 return to_string(value, digits);
473 }
474
475
476
477 template <typename number>
478 std::string
479 to_string(const number value, const unsigned int digits)
480 {
481 // For integer data types, use the standard std::to_string()
482 // function. On the other hand, that function is defined in terms
483 // of std::sprintf, which does not use the usual std::iostream
484 // interface and tries to render floating point numbers in awkward
485 // ways (see
486 // https://en.cppreference.com/w/cpp/string/basic_string/to_string). So
487 // resort to boost::lexical_cast for all other types (in
488 // particular for floating point types.
489 std::string lc_string =
490 (std::is_integral_v<number> ? std::to_string(value) :
491 boost::lexical_cast<std::string>(value));
492
493 if ((digits != numbers::invalid_unsigned_int) &&
494 (lc_string.size() < digits))
495 {
496 // We have to add the padding zeroes in front of the number
497 const unsigned int padding_position = (lc_string[0] == '-') ? 1 : 0;
498
499 const std::string padding(digits - lc_string.size(), '0');
500 lc_string.insert(padding_position, padding);
501 }
502
503 return lc_string;
504 }
505
506
507
508 std::string
509 replace_in_string(const std::string &input,
510 const std::string &from,
511 const std::string &to)
512 {
513 if (from.empty())
514 return input;
515
516 std::string out = input;
517 std::string::size_type pos = out.find(from);
518
519 while (pos != std::string::npos)
520 {
521 out.replace(pos, from.size(), to);
522 pos = out.find(from, pos + to.size());
523 }
524 return out;
525 }
526
527 std::string
528 trim(const std::string &input)
529 {
530 std::string::size_type left = 0;
531 std::string::size_type right = input.size() > 0 ? input.size() - 1 : 0;
532
533 for (; left < input.size(); ++left)
534 {
535 if (std::isspace(input[left]) == 0)
536 {
537 break;
538 }
539 }
540
541 for (; right >= left; --right)
542 {
543 if (std::isspace(input[right]) == 0)
544 {
545 break;
546 }
547 }
548
549 return std::string(input, left, right - left + 1);
550 }
551
552
553
554 std::string
555 dim_string(const int dim, const int spacedim)
556 {
557 if (dim == spacedim)
558 return int_to_string(dim);
559 else
560 return int_to_string(dim) + "," + int_to_string(spacedim);
561 }
562
563
564 unsigned int
565 needed_digits(const unsigned int max_number)
566 {
567 if (max_number > 0)
568 return static_cast<int>(
569 std::ceil(std::log10(std::fabs(max_number + 0.1))));
570
571 return 1;
572 }
573
574
575
576 template <typename Number>
577 Number
578 truncate_to_n_digits(const Number number, const unsigned int n_digits)
579 {
580 AssertThrow(n_digits >= 1, ExcMessage("invalid parameter."));
581
582 if (!(std::fabs(number) > std::numeric_limits<Number>::min()))
583 return number;
584
585 const int order =
586 static_cast<int>(std::floor(std::log10(std::fabs(number))));
587
588 const int shift = -order + static_cast<int>(n_digits) - 1;
589
590 Assert(shift <= static_cast<int>(std::floor(
591 std::log10(std::numeric_limits<Number>::max()))),
593 "Overflow. Use a smaller value for n_digits and/or make sure "
594 "that the absolute value of 'number' does not become too small."));
595
596 const Number factor = std::pow(10.0, static_cast<Number>(shift));
597
598 const Number number_cutoff = std::trunc(number * factor) / factor;
599
600 return number_cutoff;
601 }
602
603
604 int
605 string_to_int(const std::string &s_)
606 {
607 // trim whitespace on either side of the text if necessary
608 std::string s = s_;
609 while ((s.size() > 0) && (s[0] == ' '))
610 s.erase(s.begin());
611 while ((s.size() > 0) && (s.back() == ' '))
612 s.erase(s.end() - 1);
613
614 // Now convert and see whether we succeed. Note that strtol only
615 // touches errno if an error occurred, so if we want to check
616 // whether an error happened, we need to make sure that errno==0
617 // before calling strtol since otherwise it may be that the
618 // conversion succeeds and that errno remains at the value it
619 // was before, whatever that was.
620 char *p;
621 errno = 0;
622 const int i = std::strtol(s.c_str(), &p, 10);
623
624 // We have an error if one of the following conditions is true:
625 // - strtol sets errno != 0
626 // - The original string was empty (we could have checked that
627 // earlier already)
628 // - The string has non-zero length and strtol converted the
629 // first part to something useful, but stopped converting short
630 // of the terminating '\0' character. This happens, for example,
631 // if the given string is "1234 abc".
632 AssertThrow(!((errno != 0) || (s.empty()) ||
633 ((s.size() > 0) && (*p != '\0'))),
634 ExcMessage("Can't convert <" + s + "> to an integer."));
635
636 return i;
637 }
638
639
640
641 std::vector<int>
642 string_to_int(const std::vector<std::string> &s)
643 {
644 std::vector<int> tmp(s.size());
645 for (unsigned int i = 0; i < s.size(); ++i)
646 tmp[i] = string_to_int(s[i]);
647 return tmp;
648 }
649
650
651
652 double
653 string_to_double(const std::string &s_)
654 {
655 // trim whitespace on either side of the text if necessary
656 std::string s = s_;
657 while ((s.size() > 0) && (s[0] == ' '))
658 s.erase(s.begin());
659 while ((s.size() > 0) && (s.back() == ' '))
660 s.erase(s.end() - 1);
661
662 // Now convert and see whether we succeed. Note that strtol only
663 // touches errno if an error occurred, so if we want to check
664 // whether an error happened, we need to make sure that errno==0
665 // before calling strtol since otherwise it may be that the
666 // conversion succeeds and that errno remains at the value it
667 // was before, whatever that was.
668 char *p;
669 errno = 0;
670 const double d = std::strtod(s.c_str(), &p);
671
672 // We have an error if one of the following conditions is true:
673 // - strtod sets errno != 0
674 // - The original string was empty (we could have checked that
675 // earlier already)
676 // - The string has non-zero length and strtod converted the
677 // first part to something useful, but stopped converting short
678 // of the terminating '\0' character. This happens, for example,
679 // if the given string is "1.234 abc".
680 AssertThrow(!((errno != 0) || (s.empty()) ||
681 ((s.size() > 0) && (*p != '\0'))),
682 ExcMessage("Can't convert <" + s + "> to a double."));
683
684 return d;
685 }
686
687
688
689 std::vector<double>
690 string_to_double(const std::vector<std::string> &s)
691 {
692 std::vector<double> tmp(s.size());
693 for (unsigned int i = 0; i < s.size(); ++i)
694 tmp[i] = string_to_double(s[i]);
695 return tmp;
696 }
697
698
699
700 std::vector<std::string>
701 split_string_list(const std::string &s, const std::string &delimiter)
702 {
703 // keep the currently remaining part of the input string in 'tmp' and
704 // keep chopping elements of the list off the front
705 std::string tmp = s;
706
707 // as discussed in the documentation, eat whitespace from the end
708 // of the string
709 while (tmp.size() != 0 && tmp.back() == ' ')
710 tmp.erase(tmp.size() - 1, 1);
711
712 // split the input list until it is empty. since in every iteration
713 // 'tmp' is what's left of the string after the next delimiter,
714 // and since we've stripped trailing space already, 'tmp' will
715 // be empty at one point if 's' ended in a delimiter, even if
716 // there was space after the last delimiter. this matches what's
717 // discussed in the documentation
718 std::vector<std::string> split_list;
719 while (tmp.size() != 0)
720 {
721 std::string name;
722 name = tmp;
723
724 if (name.find(delimiter) != std::string::npos)
725 {
726 name.erase(name.find(delimiter), std::string::npos);
727 tmp.erase(0, tmp.find(delimiter) + delimiter.size());
728 }
729 else
730 tmp = "";
731
732 // strip spaces from this element's front and end
733 while ((name.size() != 0) && (name[0] == ' '))
734 name.erase(0, 1);
735 while (name.size() != 0 && name.back() == ' ')
736 name.erase(name.size() - 1, 1);
737
738 split_list.push_back(name);
739 }
740
741 return split_list;
742 }
743
744
745 std::vector<std::string>
746 split_string_list(const std::string &s, const char delimiter)
747 {
748 std::string d = ",";
749 d[0] = delimiter;
750 return split_string_list(s, d);
751 }
752
753
754 std::vector<std::string>
755 break_text_into_lines(const std::string &original_text,
756 const unsigned int width,
757 const char delimiter)
758 {
759 std::string text = original_text;
760 std::vector<std::string> lines;
761
762 // remove trailing spaces
763 while ((text.size() != 0) && (text.back() == delimiter))
764 text.erase(text.size() - 1, 1);
765
766 // then split the text into lines
767 while (text.size() != 0)
768 {
769 // in each iteration, first remove
770 // leading spaces
771 while ((text.size() != 0) && (text[0] == delimiter))
772 text.erase(0, 1);
773
774 std::size_t pos_newline = text.find_first_of('\n', 0);
775 if (pos_newline != std::string::npos && pos_newline <= width)
776 {
777 std::string line(text, 0, pos_newline);
778 while ((line.size() != 0) && (line.back() == delimiter))
779 line.erase(line.size() - 1, 1);
780 lines.push_back(line);
781 text.erase(0, pos_newline + 1);
782 continue;
783 }
784
785 // if we can fit everything into one
786 // line, then do so. otherwise, we have
787 // to keep breaking
788 if (text.size() < width)
789 {
790 // remove trailing spaces
791 while ((text.size() != 0) && (text.back() == delimiter))
792 text.erase(text.size() - 1, 1);
793 lines.push_back(text);
794 text = "";
795 }
796 else
797 {
798 // starting at position width, find the
799 // location of the previous space, so
800 // that we can break around there
801 int location = std::min<int>(width, text.size() - 1);
802 for (; location > 0; --location)
803 if (text[location] == delimiter)
804 break;
805
806 // if there are no spaces, then try if
807 // there are spaces coming up
808 if (location == 0)
809 for (location = std::min<int>(width, text.size() - 1);
810 location < static_cast<int>(text.size());
811 ++location)
812 if (text[location] == delimiter)
813 break;
814
815 // now take the text up to the found
816 // location and put it into a single
817 // line, and remove it from 'text'
818 std::string line(text, 0, location);
819 while ((line.size() != 0) && (line.back() == delimiter))
820 line.erase(line.size() - 1, 1);
821 lines.push_back(line);
822 text.erase(0, location);
823 }
824 }
825
826 return lines;
827 }
828
829
830
831 bool
832 match_at_string_start(const std::string &name, const std::string &pattern)
833 {
834 if (pattern.size() > name.size())
835 return false;
836
837 for (unsigned int i = 0; i < pattern.size(); ++i)
838 if (pattern[i] != name[i])
839 return false;
840
841 return true;
842 }
843
844
845
846 std::pair<int, unsigned int>
847 get_integer_at_position(const std::string &name, const unsigned int position)
848 {
849 Assert(position < name.size(), ExcInternalError());
850
851 const std::string test_string(name.begin() + position, name.end());
852
853 std::istringstream str(test_string);
854
855 int i;
856 if (str >> i)
857 {
858 // compute the number of
859 // digits of i. assuming it
860 // is less than 8 is likely
861 // ok
862 if (i < 10)
863 return std::make_pair(i, 1U);
864 else if (i < 100)
865 return std::make_pair(i, 2U);
866 else if (i < 1000)
867 return std::make_pair(i, 3U);
868 else if (i < 10000)
869 return std::make_pair(i, 4U);
870 else if (i < 100000)
871 return std::make_pair(i, 5U);
872 else if (i < 1000000)
873 return std::make_pair(i, 6U);
874 else if (i < 10000000)
875 return std::make_pair(i, 7U);
876 else
877 {
879 return std::make_pair(-1, numbers::invalid_unsigned_int);
880 }
881 }
882 else
883 return std::make_pair(-1, numbers::invalid_unsigned_int);
884 }
885
886
887
888 double
889 generate_normal_random_number(const double a, const double sigma)
890 {
891 // if no noise: return now
892 if (sigma == 0)
893 return a;
894
895 // we would want to use rand(), but that function is not reentrant
896 // in a thread context. one could use rand_r, but this does not
897 // produce reproducible results between threads either (though at
898 // least it is reentrant). these two approaches being
899 // non-workable, use a thread-local random number generator here.
900 // we could use std::mt19937 but doing so results in compiler-dependent
901 // output.
902 static Threads::ThreadLocalStorage<boost::mt19937> random_number_generator;
903 return boost::normal_distribution<>(a,
904 sigma)(random_number_generator.get());
905 }
906
907
908
909 namespace System
910 {
911#ifdef __linux__
912
913 double
915 {
916 std::ifstream cpuinfo;
917 cpuinfo.open("/proc/loadavg");
918
919 AssertThrow(cpuinfo.fail() == false, ExcIO());
920
921 double load;
922 cpuinfo >> load;
923
924 return load;
925 }
926
927#else
928
929 double
931 {
932 return 0.;
933 }
934
935#endif
936
937 std::string
939 {
941 {
942 case 0:
943 return "disabled";
944 case 128:
945#ifdef __ALTIVEC__
946 return "AltiVec";
947#else
948 return "SSE2";
949#endif
950 case 256:
951 return "AVX";
952 case 512:
953 return "AVX512";
954 default:
955 AssertThrow(false,
957 "Invalid DEAL_II_VECTORIZATION_WIDTH_IN_BITS."));
958 return "ERROR";
959 }
960 }
961
962
963 void
965 {
966 stats.VmPeak = stats.VmSize = stats.VmHWM = stats.VmRSS = 0;
967
968 // parsing /proc/self/stat would be a
969 // lot easier, but it does not contain
970 // VmHWM, so we use /status instead.
971#ifdef __linux__
972 std::ifstream file("/proc/self/status");
973 std::string line;
974 std::string name;
975 while (!file.eof())
976 {
977 file >> name;
978 if (name == "VmPeak:")
979 file >> stats.VmPeak;
980 else if (name == "VmSize:")
981 file >> stats.VmSize;
982 else if (name == "VmHWM:")
983 file >> stats.VmHWM;
984 else if (name == "VmRSS:")
985 {
986 file >> stats.VmRSS;
987 break; // this is always the last entry
988 }
989
990 getline(file, line);
991 }
992#endif
993 }
994
995
996
997 std::string
999 {
1000#if defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_GETHOSTNAME)
1001 const unsigned int N = 1024;
1002 char hostname[N];
1003 gethostname(&(hostname[0]), N - 1);
1004#else
1005 std::string hostname("unknown");
1006#endif
1007 return hostname;
1008 }
1009
1010
1011
1012 std::string
1014 {
1015 std::time_t time1 = std::time(nullptr);
1016 const std::tm *time = std::localtime(&time1);
1017
1018 std::ostringstream o;
1019 o << time->tm_hour << ":" << (time->tm_min < 10 ? "0" : "")
1020 << time->tm_min << ":" << (time->tm_sec < 10 ? "0" : "")
1021 << time->tm_sec;
1022
1023 return o.str();
1024 }
1025
1026
1027
1028 std::string
1030 {
1031 std::time_t time1 = std::time(nullptr);
1032 const std::tm *time = std::localtime(&time1);
1033
1034 std::ostringstream o;
1035 o << time->tm_year + 1900 << "/" << time->tm_mon + 1 << "/"
1036 << time->tm_mday;
1037
1038 return o.str();
1039 }
1040
1041
1042
1043 void
1044 posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
1045 {
1046 // Strictly speaking, one can call both posix_memalign() and malloc()
1047 // with size==0. This is documented as returning a pointer that can
1048 // be given to free(), but for which using it is otherwise undefined.
1049 // That just seems like a bad idea -- let's just return a nullptr to
1050 // *ensure* that it can not be used. free() is documented as accepting
1051 // a nullptr, in which it simply does nothing.
1052 if (size > 0)
1053 {
1054#ifndef DEAL_II_MSVC
1055 const int ierr = ::posix_memalign(memptr, alignment, size);
1056
1057 AssertThrow(ierr == 0, ExcOutOfMemory(size));
1058 AssertThrow(*memptr != nullptr, ExcOutOfMemory(size));
1059#else
1060 // Windows does not appear to have posix_memalign. just use the
1061 // regular malloc in that case
1062 *memptr = malloc(size);
1063 (void)alignment;
1064 AssertThrow(*memptr != nullptr, ExcOutOfMemory(size));
1065#endif
1066 }
1067 else
1068 *memptr = nullptr;
1069 }
1070
1071
1072
1073 bool
1078 } // namespace System
1079
1080#ifndef DOXYGEN
1081 template std::string
1082 to_string<int>(int, unsigned int);
1083 template std::string
1084 to_string<long int>(long int, unsigned int);
1085 template std::string
1086 to_string<long long int>(long long int, unsigned int);
1087 template std::string
1088 to_string<unsigned int>(unsigned int, unsigned int);
1089 template std::string
1090 to_string<unsigned long int>(unsigned long int, unsigned int);
1091 template std::string
1092 to_string<unsigned long long int>(unsigned long long int, unsigned int);
1093 template std::string
1094 to_string<float>(float, unsigned int);
1095 template std::string
1096 to_string<double>(double, unsigned int);
1097 template std::string
1098 to_string<long double>(long double, unsigned int);
1099
1100 template double
1101 truncate_to_n_digits(const double, const unsigned int);
1102 template float
1103 truncate_to_n_digits(const float, const unsigned int);
1104
1105 template std::vector<std::array<std::uint64_t, 1>>
1106 inverse_Hilbert_space_filling_curve<1, double>(
1107 const std::vector<Point<1, double>> &,
1108 const int);
1109 template std::vector<std::array<std::uint64_t, 1>>
1110 inverse_Hilbert_space_filling_curve<1>(
1111 const std::vector<std::array<std::uint64_t, 1>> &,
1112 const int);
1113 template std::vector<std::array<std::uint64_t, 2>>
1114 inverse_Hilbert_space_filling_curve<2, double>(
1115 const std::vector<Point<2, double>> &,
1116 const int);
1117 template std::vector<std::array<std::uint64_t, 2>>
1118 inverse_Hilbert_space_filling_curve<2>(
1119 const std::vector<std::array<std::uint64_t, 2>> &,
1120 const int);
1121 template std::vector<std::array<std::uint64_t, 3>>
1122 inverse_Hilbert_space_filling_curve<3, double>(
1123 const std::vector<Point<3, double>> &,
1124 const int);
1125 template std::vector<std::array<std::uint64_t, 3>>
1126 inverse_Hilbert_space_filling_curve<3>(
1127 const std::vector<std::array<std::uint64_t, 3>> &,
1128 const int);
1129
1130 template std::uint64_t
1131 pack_integers<1>(const std::array<std::uint64_t, 1> &, const int);
1132 template std::uint64_t
1133 pack_integers<2>(const std::array<std::uint64_t, 2> &, const int);
1134 template std::uint64_t
1135 pack_integers<3>(const std::array<std::uint64_t, 3> &, const int);
1136
1137#endif
1138
1139} // namespace Utilities
1140
Definition point.h:111
A class that provides a separate storage location on each thread that accesses the object.
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_PACKAGE_VERSION
Definition config.h:25
#define DEAL_II_VECTORIZATION_WIDTH_IN_BITS
Definition config.h:126
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
#define DEAL_II_PACKAGE_NAME
Definition config.h:23
static ::ExceptionBase & ExcInvalidNumber2StringConversersion(unsigned int arg1, unsigned int arg2)
static ::ExceptionBase & ExcOutOfMemory(std::size_t arg1)
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcInvalidNumber(unsigned int arg1)
#define Assert(cond, exc)
#define DeclException2(Exception2, type1, type2, outsequence)
Definition exceptions.h:534
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcCantConvertString(std::string arg1)
#define DeclException1(Exception1, type1, outsequence)
Definition exceptions.h:511
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
#define DEAL_II_NOT_IMPLEMENTED()
std::size_t size
Definition mpi.cc:734
bool job_supports_mpi()
Definition mpi.cc:681
void get_memory_stats(MemoryStats &stats)
Definition utilities.cc:964
std::string get_hostname()
Definition utilities.cc:998
std::string get_time()
void posix_memalign(void **memptr, std::size_t alignment, std::size_t size)
double get_cpu_load()
Definition utilities.cc:930
std::string get_current_vectorization_level()
Definition utilities.cc:938
std::string get_date()
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition utilities.cc:701
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition utilities.cc:578
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:555
std::uint64_t pack_integers(const std::array< std::uint64_t, dim > &index, const int bits_per_dim)
Definition utilities.cc:366
std::pair< int, unsigned int > get_integer_at_position(const std::string &name, const unsigned int position)
Definition utilities.cc:847
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition utilities.cc:433
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition utilities.cc:509
std::vector< unsigned char > decode_base64(const std::string &base64_input)
Definition utilities.cc:446
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition utilities.cc:755
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:479
std::vector< std::array< std::uint64_t, dim > > inverse_Hilbert_space_filling_curve(const std::vector< Point< dim, Number > > &points, const int bits_per_dim=64)
Definition utilities.cc:145
std::string compress(const std::string &input)
Definition utilities.cc:389
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:470
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition utilities.cc:832
std::string decompress(const std::string &compressed_input)
Definition utilities.cc:411
unsigned int needed_digits(const unsigned int max_number)
Definition utilities.cc:565
double string_to_double(const std::string &s)
Definition utilities.cc:653
std::string dealii_version_string()
Definition utilities.cc:94
std::string trim(const std::string &input)
Definition utilities.cc:528
double generate_normal_random_number(const double a, const double sigma)
Definition utilities.cc:889
int string_to_int(const std::string &s)
Definition utilities.cc:605
static const unsigned int invalid_unsigned_int
Definition types.h:220
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)