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