Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : // MOOSE includes
13 : #include "MooseTypes.h"
14 : #include "HashMap.h"
15 : #include "InfixIterator.h"
16 : #include "MooseEnumItem.h"
17 : #include "MooseError.h"
18 : #include "Moose.h"
19 : #include "ExecutablePath.h"
20 : #include "ConsoleUtils.h"
21 : #include "MooseStringUtils.h"
22 :
23 : #include "libmesh/compare_types.h"
24 : #include "libmesh/bounding_box.h"
25 : #include "libmesh/int_range.h"
26 : #include "libmesh/tensor_tools.h"
27 : #include "metaphysicl/raw_type.h"
28 : #include "metaphysicl/metaphysicl_version.h"
29 : #include "metaphysicl/dualnumber_decl.h"
30 : #include "metaphysicl/dynamic_std_array_wrapper.h"
31 : #include "timpi/standard_type.h"
32 :
33 : // C++ includes
34 : #include <string>
35 : #include <vector>
36 : #include <map>
37 : #include <list>
38 : #include <filesystem>
39 : #include <deque>
40 : #include <regex>
41 :
42 : // Forward Declarations
43 : class InputParameters;
44 : class ExecFlagEnum;
45 : class MaterialProperties;
46 : class MaterialBase;
47 :
48 : namespace libMesh
49 : {
50 : class Elem;
51 : namespace Parallel
52 : {
53 : class Communicator;
54 : }
55 : }
56 : class MultiMooseEnum;
57 :
58 : namespace MooseUtils
59 : {
60 :
61 : std::filesystem::path pathjoin(const std::filesystem::path & p);
62 :
63 : template <typename... Args>
64 : std::filesystem::path
65 693412 : pathjoin(const std::filesystem::path & p, Args... args)
66 : {
67 693412 : return p / pathjoin(args...);
68 : }
69 :
70 : /// Check if the input string can be parsed into a Real
71 : /// @param input input to check / parse
72 : /// @param parsed_real pointer to a Real that gets set to the parsed real if it does parse to Real
73 : bool parsesToReal(const std::string & input, Real * parsed_real = nullptr);
74 :
75 : /// Returns the location of either a local repo run_tests script - or an
76 : /// installed test executor script if run_tests isn't found.
77 : std::string runTestsExecutable();
78 :
79 : /// Searches in the current working directory and then recursively up in each
80 : /// parent directory looking for a "testroot" file. Returns the full path to
81 : /// the first testroot file found.
82 : std::string findTestRoot();
83 :
84 : /// Returns the directory of any installed inputs or the empty string if none are found.
85 : std::string installedInputsDir(const std::string & app_name,
86 : const std::string & dir_name,
87 : const std::string & extra_error_msg = "");
88 :
89 : /// Returns the directory of any installed docs/site.
90 : std::string docsDir(const std::string & app_name);
91 :
92 : /**
93 : * Returns the URL of a page located on the MOOSE documentation site.
94 : *
95 : * @param[in] path URL path following the domain name. For example, in the
96 : * URL "www.example.com/folder1/folder2/file.html", this
97 : * would be "folder1/folder2/file.html".
98 : */
99 : std::string mooseDocsURL(const std::string & path);
100 :
101 : /// Replaces all occurrences of from in str with to and returns the result.
102 : std::string replaceAll(std::string str, const std::string & from, const std::string & to);
103 :
104 : /**
105 : * Replaces "LATEST" placeholders with the latest checkpoint file name.
106 : */
107 : std::string convertLatestCheckpoint(std::string orig);
108 :
109 : /// Computes and returns the Levenshtein distance between strings s1 and s2.
110 : int levenshteinDist(const std::string & s1, const std::string & s2);
111 :
112 : /**
113 : * This function will escape all of the standard C++ escape characters so that they can be printed.
114 : * The
115 : * passed in parameter is modified in place
116 : */
117 : void escape(std::string & str);
118 :
119 : /**
120 : * Removes additional whitespace from a string
121 : *
122 : * Removes beginning whitespace, end whitespace, and repeated whitespace into a single space
123 : */
124 : std::string removeExtraWhitespace(const std::string & str);
125 :
126 : /**
127 : * Python like split functions for strings.
128 : *
129 : * NOTE: This is similar to the tokenize function, but it maintains empty items, which tokenize does
130 : * not. For example, "foo;bar;;" becomes {"foo", "bar", "", ""}.
131 : */
132 : std::vector<std::string> split(const std::string & str,
133 : const std::string & delimiter,
134 : std::size_t max_count = std::numeric_limits<std::size_t>::max());
135 : std::vector<std::string> rsplit(const std::string & str,
136 : const std::string & delimiter,
137 : std::size_t max_count = std::numeric_limits<std::size_t>::max());
138 :
139 : /**
140 : * Python-like join function for strings over an iterator range.
141 : */
142 : template <typename Iterator>
143 : std::string
144 665761 : join(Iterator begin, Iterator end, const std::string & delimiter)
145 : {
146 665761 : std::ostringstream oss;
147 665761 : std::copy(begin, end, infix_ostream_iterator<std::string>(oss, delimiter.c_str()));
148 1331522 : return oss.str();
149 665761 : }
150 :
151 : /**
152 : * Python-like join function for strings over a container.
153 : */
154 : template <typename T>
155 : std::string
156 665654 : join(const T & strings, const std::string & delimiter)
157 : {
158 665654 : return join(strings.begin(), strings.end(), delimiter);
159 : }
160 :
161 : /**
162 : * Check the file size.
163 : */
164 : std::size_t fileSize(const std::string & filename);
165 :
166 : /**
167 : * This function tokenizes a path and checks to see if it contains the string to look for
168 : */
169 : bool pathContains(const std::string & expression,
170 : const std::string & string_to_find,
171 : const std::string & delims = "/");
172 :
173 : /**
174 : * Checks to see if a file is readable (exists and permissions)
175 : * @param filename The filename to check
176 : * @param check_line_endings Whether or not to see if the file contains DOS line endings.
177 : * @param throw_on_unreadable Whether or not to throw a MOOSE error if the file doesn't exist
178 : * @param check_for_git_lfs_pointer Whether or not to call a subroutine utility to make sure that
179 : * the file in question is not actually a git-lfs pointer.
180 : * @return a Boolean indicating whether the file exists and is readable
181 : */
182 : bool checkFileReadable(const std::string & filename,
183 : bool check_line_endings = false,
184 : bool throw_on_unreadable = true,
185 : bool check_for_git_lfs_pointer = true);
186 :
187 : /**
188 : * Check if the file is writable (path exists and permissions)
189 : * @param filename The filename you want to see if you can write to.
190 : * @param throw_on_unwritable Whether or not to throw a MOOSE error if the file is not writable
191 : * return a Boolean indicating whether the file exists and is writable
192 : */
193 : bool checkFileWriteable(const std::string & filename, bool throw_on_unwritable = true);
194 :
195 : /**
196 : * Check if the file is a Git-LFS pointer. When using a repository that utilizes Git-LFS,
197 : * it's possible that the client may not have the right packages installed in which case
198 : * the clone will contain plain-text files with key information for retrieving the actual
199 : * (large) files. This can cause odd errors since the file technically exists, is readable,
200 : * and even has the right name/extension. However, the content of the file will not match
201 : * the expected content.
202 : * @param file A pointer to the open filestream.
203 : */
204 : bool checkForGitLFSPointer(std::ifstream & file);
205 :
206 : /**
207 : * This function implements a parallel barrier function but writes progress
208 : * to stdout.
209 : */
210 : void parallelBarrierNotify(const libMesh::Parallel::Communicator & comm, bool messaging = true);
211 :
212 : /**
213 : * This function marks the begin of a section of code that is executed in serial
214 : * rank by rank. The section must be closed with a call to serialEnd.
215 : * These functions are intended for debugging use to obtain clean terminal output
216 : * from multiple ranks (use --keep-cout).
217 : * @param comm The communicator to use
218 : * @param warn Whether or not to warn that something is being serialized
219 : */
220 : void serialBegin(const libMesh::Parallel::Communicator & comm, bool warn = true);
221 :
222 : /**
223 : * Closes a section of code that is executed in serial rank by rank, and that was
224 : * opened with a call to serialBegin. No MPI communication can happen in this block.
225 : * @param comm The communicator to use
226 : * @param warn Whether or not to warn that something is being serialized
227 : */
228 : void serialEnd(const libMesh::Parallel::Communicator & comm, bool warn = true);
229 :
230 : /**
231 : * Function tests if the supplied filename as the desired extension
232 : * @param filename The filename to test the extension
233 : * @param ext The extension to test for (do not include the .)
234 : * @param strip_exodus_ext When true, this function ignores -s* from the end of the extension
235 : * @return True if the filename has the supplied extension
236 : */
237 : bool hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext = false);
238 :
239 : /**
240 : * Gets the extension of the passed file name.
241 : * @param filename The filename of which to get the extension
242 : * @param rfind When true, searches for last "." in filename. Otherwise, searches for first "."
243 : * @return file_ext The extension of filename (does not include the leading "."). If filename has no
244 : * extension, returns "".
245 : */
246 : std::string getExtension(const std::string & filename, const bool rfind = false);
247 :
248 : /**
249 : * Removes any file extension from the given string s (i.e. any ".[extension]" suffix of s) and
250 : * returns the result.
251 : */
252 : std::string stripExtension(const std::string & s, const bool rfind = false);
253 :
254 : /**
255 : * Function for splitting path and filename
256 : * @param full_file A complete filename and path
257 : * @return A std::pair<std::string, std::string> containing the path and filename
258 : *
259 : * If the supplied filename does not contain a path, it returns "." as the path
260 : */
261 : template <typename T>
262 : std::pair<std::filesystem::path, std::filesystem::path>
263 134323 : splitFileName(const T & full_file)
264 : {
265 134323 : const auto p = std::filesystem::path(std::string(full_file));
266 : // Error if path ends with /
267 134323 : if (!p.has_filename())
268 2 : mooseError("Invalid full file name: ", p);
269 :
270 134321 : const auto d = p.parent_path();
271 268642 : return {d.empty() ? "." : d, p.filename()};
272 134323 : }
273 :
274 : /**
275 : * Returns the current working directory as a string. If there's a problem
276 : * obtaining the current working directory, this function just returns an
277 : * empty string. It doesn't not throw.
278 : */
279 : std::string getCurrentWorkingDir();
280 :
281 : /**
282 : * Recursively make directories
283 : * @param dir_name A complete path
284 : * @param throw_on_failure True to throw instead of error out when creating a directory is failed.
285 : *
286 : * The path can be relative like 'a/b/c' or absolute like '/a/b/c'.
287 : * The path is allowed to contain '.' or '..'.
288 : */
289 : void makedirs(const std::string & dir_name, bool throw_on_failure = false);
290 :
291 : /**
292 : * Recursively remove directories from inner-most when the directories are empty
293 : * @param dir_name A complete path
294 : * @param throw_on_failure True to throw instead of error out when deleting a directory is failed.
295 : *
296 : * The path can be relative like 'a/b/c' or absolute like '/a/b/c'.
297 : * The path is allowed to contain '.' or '..'.
298 : */
299 : void removedirs(const std::string & dir_name, bool throw_on_failure = false);
300 :
301 : /**
302 : * Function for converting a camel case name to a name containing underscores.
303 : * @param camel_case_name A string containing camel casing
304 : * @return a string containing no capital letters with underscores as appropriate
305 : */
306 : std::string camelCaseToUnderscore(const std::string & camel_case_name);
307 :
308 : /**
309 : * Function for converting an underscore name to a camel case name.
310 : * @param underscore_name A string containing underscores
311 : * @return a string containing camel casing
312 : */
313 : std::string underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case);
314 :
315 : /**
316 : * Function for stripping name after the file / in parser block
317 : */
318 : std::string shortName(const std::string & name);
319 :
320 : /**
321 : * Function for string the information before the final / in a parser block
322 : */
323 : std::string baseName(const std::string & name);
324 :
325 : /**
326 : * Get the hostname the current process is running on
327 : */
328 : std::string hostname();
329 :
330 : /**
331 : * Returns the width of the terminal using sys/ioctl
332 : */
333 : unsigned short getTermWidth(bool use_environment);
334 :
335 : /**
336 : * @returns A cleaner representation of the c++ type \p cpp_type.
337 : */
338 : std::string prettyCppType(const std::string & cpp_type);
339 :
340 : /**
341 : * @returns A cleaner representation of the type for the given object
342 : */
343 : template <typename T>
344 : std::string
345 141443 : prettyCppType(const T * obj = nullptr)
346 : {
347 141443 : if (obj)
348 10684 : return prettyCppType(libMesh::demangle(typeid(*obj).name()));
349 : else
350 130759 : return prettyCppType(libMesh::demangle(typeid(T).name()));
351 : }
352 :
353 : /**
354 : * This routine is a simple helper function for searching a map by values instead of keys
355 : */
356 : template <typename T1, typename T2>
357 : bool
358 108129 : doesMapContainValue(const std::map<T1, T2> & the_map, const T2 & value)
359 : {
360 365359 : for (typename std::map<T1, T2>::const_iterator iter = the_map.begin(); iter != the_map.end();
361 257230 : ++iter)
362 348909 : if (iter->second == value)
363 91679 : return true;
364 16450 : return false;
365 : }
366 :
367 : /**
368 : * Function to check whether two points are the same for each component
369 : * @param var1 The first variable to be checked
370 : * @param var2 The second variable to be checked
371 : * @param tol The tolerance to be used
372 : * @return true if var1 and var2 are equal within tol for each component
373 : * TODO: make this a template to make it work for all vector types
374 : * Notably figure out the component access differences
375 : */
376 : inline bool
377 608 : absoluteFuzzyEqual(const Point & v1,
378 : const Point & v2,
379 : const Real tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
380 : {
381 1005 : for (const auto i : make_range(LIBMESH_DIM))
382 917 : if (std::abs(v1(i) - v2(i)) > tol)
383 520 : return false;
384 88 : return true;
385 : }
386 :
387 : /**
388 : * Function to check whether two variables are equal within an absolute tolerance
389 : * @param var1 The first variable to be checked
390 : * @param var2 The second variable to be checked
391 : * @param tol The tolerance to be used
392 : * @return true if var1 and var2 are equal within tol
393 : */
394 : template <
395 : typename T,
396 : typename T2,
397 : typename T3 = T,
398 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
399 : libMesh::ScalarTraits<T3>::value,
400 : int>::type = 0>
401 : bool
402 44869982 : absoluteFuzzyEqual(const T & var1,
403 : const T2 & var2,
404 78750658 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
405 : {
406 44869982 : return (std::abs(MetaPhysicL::raw_value(var1) - MetaPhysicL::raw_value(var2)) <=
407 44869982 : MetaPhysicL::raw_value(tol));
408 : }
409 :
410 : /**
411 : * Function to check whether a variable is greater than or equal to another variable within an
412 : * absolute tolerance
413 : * @param var1 The first variable to be checked
414 : * @param var2 The second variable to be checked
415 : * @param tol The tolerance to be used
416 : * @return true if var1 > var2 or var1 == var2 within tol
417 : */
418 : template <
419 : typename T,
420 : typename T2,
421 : typename T3 = T,
422 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
423 : libMesh::ScalarTraits<T3>::value,
424 : int>::type = 0>
425 : bool
426 260431 : absoluteFuzzyGreaterEqual(const T & var1,
427 : const T2 & var2,
428 351013 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
429 : {
430 260431 : return (MetaPhysicL::raw_value(var1) >=
431 260431 : (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
432 : }
433 :
434 : /**
435 : * Function to check whether a variable is greater than another variable within an absolute
436 : * tolerance
437 : * @param var1 The first variable to be checked
438 : * @param var2 The second variable to be checked
439 : * @param tol The tolerance to be used
440 : * @return true if var1 > var2 and var1 != var2 within tol
441 : */
442 : template <
443 : typename T,
444 : typename T2,
445 : typename T3 = T,
446 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
447 : libMesh::ScalarTraits<T3>::value,
448 : int>::type = 0>
449 : bool
450 5786709 : absoluteFuzzyGreaterThan(const T & var1,
451 : const T2 & var2,
452 8219286 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
453 : {
454 5786709 : return (MetaPhysicL::raw_value(var1) >
455 5786709 : (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
456 : }
457 :
458 : /**
459 : * Function to check whether a variable is less than or equal to another variable within an absolute
460 : * tolerance
461 : * @param var1 The first variable to be checked
462 : * @param var2 The second variable to be checked
463 : * @param tol The tolerance to be used
464 : * @return true if var1 < var2 or var1 == var2 within tol
465 : */
466 : template <
467 : typename T,
468 : typename T2,
469 : typename T3 = T,
470 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
471 : libMesh::ScalarTraits<T3>::value,
472 : int>::type = 0>
473 : bool
474 283 : absoluteFuzzyLessEqual(const T & var1,
475 : const T2 & var2,
476 250 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
477 : {
478 283 : return (MetaPhysicL::raw_value(var1) <=
479 283 : (MetaPhysicL::raw_value(var2) + MetaPhysicL::raw_value(tol)));
480 : }
481 :
482 : /**
483 : * Function to check whether a variable is less than another variable within an absolute tolerance
484 : * @param var1 The first variable to be checked
485 : * @param var2 The second variable to be checked
486 : * @param tol The tolerance to be used
487 : * @return true if var1 < var2 and var1 != var2 within tol
488 : */
489 : template <
490 : typename T,
491 : typename T2,
492 : typename T3 = T,
493 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
494 : libMesh::ScalarTraits<T3>::value,
495 : int>::type = 0>
496 : bool
497 688218 : absoluteFuzzyLessThan(const T & var1,
498 : const T2 & var2,
499 893443 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
500 : {
501 688218 : return (MetaPhysicL::raw_value(var1) <
502 688218 : (MetaPhysicL::raw_value(var2) - MetaPhysicL::raw_value(tol)));
503 : }
504 :
505 : /**
506 : * Function to check whether two variables are equal within a relative tolerance
507 : * @param var1 The first variable to be checked
508 : * @param var2 The second variable to be checked
509 : * @param tol The relative tolerance to be used
510 : * @return true if var1 and var2 are equal within relative tol
511 : */
512 : template <typename T, typename T2, typename T3 = Real>
513 : bool
514 5103865 : relativeFuzzyEqual(const T & var1,
515 : const T2 & var2,
516 665 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
517 : {
518 : if constexpr (libMesh::ScalarTraits<T>::value ||
519 : libMesh::TensorTools::MathWrapperTraits<T>::value)
520 : {
521 : static_assert(libMesh::TensorTools::TensorTraits<T>::rank ==
522 : libMesh::TensorTools::TensorTraits<T2>::rank,
523 : "Mathematical types must be same for arguments to relativelyFuzzEqual");
524 : if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
525 10207730 : return absoluteFuzzyEqual(
526 : var1,
527 : var2,
528 5103865 : tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2))));
529 : else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
530 : {
531 : for (const auto i : make_range(Moose::dim))
532 : if (!relativeFuzzyEqual(var1(i), var2(i), tol))
533 : return false;
534 :
535 : return true;
536 : }
537 : else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
538 : {
539 : for (const auto i : make_range(Moose::dim))
540 : for (const auto j : make_range(Moose::dim))
541 : if (!relativeFuzzyEqual(var1(i, j), var2(i, j), tol))
542 : return false;
543 :
544 : return true;
545 : }
546 : }
547 : else
548 : {
549 : // We dare to dream
550 : mooseAssert(var1.size() == var2.size(), "These must be the same size");
551 : for (const auto i : index_range(var1))
552 : if (!relativeFuzzyEqual(var1(i), var2(i), tol))
553 : return false;
554 :
555 : return true;
556 : }
557 : }
558 :
559 : /**
560 : * Function to check whether a variable is greater than or equal to another variable within a
561 : * relative tolerance
562 : * @param var1 The first variable to be checked
563 : * @param var2 The second variable to be checked
564 : * @param tol The tolerance to be used
565 : * @return true if var1 > var2 or var1 == var2 within relative tol
566 : */
567 : template <
568 : typename T,
569 : typename T2,
570 : typename T3 = T,
571 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
572 : libMesh::ScalarTraits<T3>::value,
573 : int>::type = 0>
574 : bool
575 8 : relativeFuzzyGreaterEqual(const T & var1,
576 : const T2 & var2,
577 16 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
578 : {
579 16 : return (absoluteFuzzyGreaterEqual(
580 : var1,
581 : var2,
582 8 : tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
583 : }
584 :
585 : /**
586 : * Function to check whether a variable is greater than another variable within a relative tolerance
587 : * @param var1 The first variable to be checked
588 : * @param var2 The second variable to be checked
589 : * @param tol The tolerance to be used
590 : * @return true if var1 > var2 and var1 != var2 within relative tol
591 : */
592 : template <
593 : typename T,
594 : typename T2,
595 : typename T3 = T,
596 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
597 : libMesh::ScalarTraits<T3>::value,
598 : int>::type = 0>
599 : bool
600 4 : relativeFuzzyGreaterThan(const T & var1,
601 : const T2 & var2,
602 8 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
603 : {
604 8 : return (absoluteFuzzyGreaterThan(
605 : var1,
606 : var2,
607 4 : tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
608 : }
609 :
610 : /**
611 : * Function to check whether a variable is less than or equal to another variable within a relative
612 : * tolerance
613 : * @param var1 The first variable to be checked
614 : * @param var2 The second variable to be checked
615 : * @param tol The tolerance to be used
616 : * @return true if var1 < var2 or var1 == var2 within relative tol
617 : */
618 : template <
619 : typename T,
620 : typename T2,
621 : typename T3 = T,
622 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
623 : libMesh::ScalarTraits<T3>::value,
624 : int>::type = 0>
625 : bool
626 8 : relativeFuzzyLessEqual(const T & var1,
627 : const T2 & var2,
628 16 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
629 : {
630 16 : return (absoluteFuzzyLessEqual(
631 : var1,
632 : var2,
633 8 : tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
634 : }
635 :
636 : /**
637 : * Function to check whether a variable is less than another variable within a relative tolerance
638 : * @param var1 The first variable to be checked
639 : * @param var2 The second variable to be checked
640 : * @param tol The tolerance to be used
641 : * @return true if var1 < var2 and var1 != var2 within relative tol
642 : */
643 : template <
644 : typename T,
645 : typename T2,
646 : typename T3 = T,
647 : typename std::enable_if<libMesh::ScalarTraits<T>::value && libMesh::ScalarTraits<T2>::value &&
648 : libMesh::ScalarTraits<T3>::value,
649 : int>::type = 0>
650 : bool
651 4806 : relativeFuzzyLessThan(const T & var1,
652 : const T2 & var2,
653 7211 : const T3 & tol = libMesh::TOLERANCE * libMesh::TOLERANCE)
654 : {
655 9612 : return (absoluteFuzzyLessThan(
656 : var1,
657 : var2,
658 4806 : tol * (std::abs(MetaPhysicL::raw_value(var1)) + std::abs(MetaPhysicL::raw_value(var2)))));
659 : }
660 :
661 : /**
662 : * Function which takes the union of \p vector1 and \p vector2 and copies them
663 : * to \p common . Depending on the vector size and data type this can be very expensive!
664 : */
665 : template <typename T>
666 : void
667 137043 : getUnion(const std::vector<T> & vector1, const std::vector<T> & vector2, std::vector<T> & common)
668 : {
669 137043 : std::unordered_set<T> unique_elements;
670 137043 : unique_elements.reserve(vector1.size() + vector2.size());
671 137043 : unique_elements.insert(vector1.begin(), vector1.end());
672 137043 : unique_elements.insert(vector2.begin(), vector2.end());
673 :
674 : // Now populate the common vector with the union
675 137043 : common.assign(unique_elements.begin(), unique_elements.end());
676 137043 : }
677 :
678 : /**
679 : * Taken from https://stackoverflow.com/a/257382
680 : * Evaluating constexpr (Has_size<T>::value) in a templated method over class T will
681 : * return whether T is a standard container or a singleton
682 : */
683 : template <typename T>
684 : class Has_size
685 : {
686 : using Yes = char;
687 : struct No
688 : {
689 : char x[2];
690 : };
691 :
692 : template <typename C>
693 : static Yes test(decltype(&C::size));
694 : template <typename C>
695 : static No test(...);
696 :
697 : public:
698 : static constexpr bool value = sizeof(test<T>(0)) == sizeof(Yes);
699 : };
700 :
701 : /**
702 : * @param value The quantity to test for zero-ness
703 : * @param tolerance The tolerance for testing zero-ness. The default is 1e-18 for double precision
704 : * configurations of libMesh/MOOSE
705 : * @return whether the L_infty norm of the value is (close enough to) zero
706 : */
707 : template <typename T>
708 : bool
709 112 : isZero(const T & value, const Real tolerance = TOLERANCE * TOLERANCE * TOLERANCE)
710 : {
711 : if constexpr (Has_size<T>::value)
712 : {
713 12 : for (const auto & element : value)
714 8 : if (!isZero(element, tolerance))
715 4 : return false;
716 :
717 4 : return true;
718 : }
719 : else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 0)
720 88 : return MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value), 0, tolerance);
721 : else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 1)
722 : {
723 20 : for (const auto i : make_range(Moose::dim))
724 16 : if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i)), 0, tolerance))
725 4 : return false;
726 :
727 4 : return true;
728 : }
729 : else if constexpr (libMesh::TensorTools::TensorTraits<T>::rank == 2)
730 : {
731 20 : for (const auto i : make_range(Moose::dim))
732 52 : for (const auto j : make_range(Moose::dim))
733 40 : if (!MooseUtils::absoluteFuzzyEqual(MetaPhysicL::raw_value(value(i, j)), 0, tolerance))
734 4 : return false;
735 :
736 4 : return true;
737 : }
738 : }
739 :
740 : /**
741 : * Function to dump the contents of MaterialPropertyStorage for debugging purposes
742 : * @param props The storage item to dump, this should be
743 : * MaterialPropertyStorage.props(state)
744 : *
745 : * Currently this only words for scalar material properties. Something to do as needed would be to
746 : * create a method in MaterialProperty
747 : * that may be overloaded to dump the type using template specialization.
748 : */
749 : void MaterialPropertyStorageDump(
750 : const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props);
751 :
752 : /**
753 : * Indents the supplied message given the prefix and color
754 : * @param prefix The prefix to use for indenting
755 : * @param message The message that will be indented
756 : * @param color The color to apply to the prefix (default CYAN)
757 : * @param indent_first_line If true this will indent the first line too (default)
758 : * @param post_prefix A string to append right after the prefix, defaults to a column and a space
759 : *
760 : * Takes a message like the following and indents it with another color code (see below)
761 : *
762 : * Input message:
763 : * COLOR_YELLOW
764 : * *** Warning ***
765 : * Something bad has happened and we want to draw attention to it with color
766 : * COLOR_DEFAULT
767 : *
768 : * Output message:
769 : * COLOR_CYAN sub_app: COLOR_YELLOW
770 : * COLOR_CYAN sub_app: COLOR_YELLOW *** Warning ***
771 : * COLOR_CYAN sub_app: COLOR_YELLOW Something bad has happened and we want to draw attention to it
772 : * with color
773 : * COLOR_DEFAULT
774 : *
775 : * Also handles single line color codes
776 : * COLOR_CYAN sub_app: 0 Nonlinear |R| = COLOR_GREEN 1.0e-10 COLOR_DEFAULT
777 : *
778 : * Not indenting the first line is useful in the case where the first line is actually finishing
779 : * the line before it.
780 : */
781 : void indentMessage(const std::string & prefix,
782 : std::string & message,
783 : const char * color = COLOR_CYAN,
784 : bool dont_indent_first_line = true,
785 : const std::string & post_prefix = ": ");
786 :
787 : /**
788 : * remove ANSI escape sequences for terminal color from msg
789 : */
790 : std::string & removeColor(std::string & msg);
791 :
792 : std::list<std::string> listDir(const std::string path, bool files_only = false);
793 :
794 : bool pathExists(const std::string & path);
795 :
796 : /**
797 : * Retrieves the names of all of the files contained within the list of directories passed into
798 : * the routine. The names returned will be the paths to the files relative to the current
799 : * directory.
800 : * @param directory_list The list of directories to retrieve files from.
801 : * @param file_only Whether or not to list only files
802 : */
803 : std::list<std::string> getFilesInDirs(const std::list<std::string> & directory_list,
804 : const bool files_only = true);
805 :
806 : /**
807 : * Returns the most recent checkpoint prefix (the four numbers at the beginning)
808 : * If a suitable file isn't found the empty string is returned
809 : * @param checkpoint_files the list of files to analyze
810 : */
811 : std::string getLatestCheckpointFilePrefix(const std::list<std::string> & checkpoint_files);
812 :
813 : /*
814 : * Checks to see if a string matches a search string
815 : * @param name The name to check
816 : * @param search_string The search string to check name against
817 : */
818 : bool wildCardMatch(std::string name, std::string search_string);
819 :
820 : /*
821 : * Checks to see if a candidate string matches a pattern string, permitting glob
822 : * wildcards (* and ?) anywhere in the pattern.
823 : * @param candidate The name to check
824 : * @param pattern The search string to check name candidate
825 : */
826 : bool globCompare(const std::string & candidate,
827 : const std::string & pattern,
828 : std::size_t c = 0,
829 : std::size_t p = 0);
830 :
831 : template <typename T>
832 : void
833 24 : expandAllMatches(const std::vector<T> & candidates, std::vector<T> & patterns)
834 : {
835 24 : std::set<T> expanded;
836 72 : for (const auto & p : patterns)
837 : {
838 48 : unsigned int found = 0;
839 240 : for (const auto & c : candidates)
840 192 : if (globCompare(c, p))
841 : {
842 48 : expanded.insert(c);
843 48 : found++;
844 : }
845 48 : if (!found)
846 0 : throw std::invalid_argument(p);
847 : }
848 24 : patterns.assign(expanded.begin(), expanded.end());
849 24 : }
850 :
851 : /**
852 : * Takes the string representation of a value and converts it to the value.
853 : *
854 : * See the convert method in MooseStringUtils.h for more information on
855 : * handling of each case.
856 : *
857 : * @param str The string to convert from
858 : * @param throw_on_failure If true, throw on a failure to convert, otherwise use mooseError
859 : * @return The converted value on success
860 : */
861 : template <typename T>
862 : T
863 5990 : convert(const std::string & str, bool throw_on_failure = false)
864 : {
865 : T val;
866 : try
867 : {
868 5990 : convert(str, val, true);
869 : }
870 1801 : catch (std::exception const & e)
871 : {
872 902 : if (throw_on_failure)
873 895 : throw;
874 7 : mooseError(e.what());
875 : }
876 5088 : return val;
877 : }
878 :
879 : /**
880 : * Create a symbolic link, if the link already exists it is replaced.
881 : */
882 : void createSymlink(const std::string & target, const std::string & link);
883 :
884 : /**
885 : * Remove a symbolic link, if the given filename is a link.
886 : */
887 : void clearSymlink(const std::string & link);
888 :
889 : /**
890 : * Returns a container that contains the content of second passed in container
891 : * inserted into the first passed in container (set or map union).
892 : */
893 : template <typename T>
894 : T
895 : concatenate(T c1, const T & c2)
896 : {
897 : c1.insert(c2.begin(), c2.end());
898 : return c1;
899 : }
900 :
901 : /**
902 : * Returns a vector that contains is the concatenation of the two passed in vectors.
903 : */
904 : template <typename T>
905 : std::vector<T>
906 : concatenate(std::vector<T> c1, const std::vector<T> & c2)
907 : {
908 : c1.insert(c1.end(), c2.begin(), c2.end());
909 : return c1;
910 : }
911 :
912 : /**
913 : * Returns the passed in vector with the item appended to it.
914 : */
915 : template <typename T>
916 : std::vector<T>
917 30 : concatenate(std::vector<T> c1, const T & item)
918 : {
919 30 : c1.push_back(item);
920 30 : return c1;
921 : }
922 :
923 : /**
924 : * @return Whether or not \p value begins with \p begin_value
925 : */
926 : bool beginsWith(const std::string & value, const std::string & begin_value);
927 :
928 : /**
929 : * Return the number of digits for a number.
930 : *
931 : * This can foster quite a large discussion:
932 : * https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer
933 : *
934 : * For our purposes I like the following algorithm.
935 : */
936 : template <typename T>
937 : int
938 1826 : numDigits(const T & num)
939 : {
940 1826 : return num > 9 ? static_cast<int>(std::log10(static_cast<double>(num))) + 1 : 1;
941 : }
942 :
943 : /**
944 : * Return the default ExecFlagEnum for MOOSE.
945 : */
946 : ExecFlagEnum getDefaultExecFlagEnum();
947 :
948 : /**
949 : * Robust string to integer conversion that fails for cases such at "1foo".
950 : * @param input The string to convert.
951 : * @param throw_on_failure Throw an invalid_argument exception instead of mooseError.
952 : */
953 : int stringToInteger(const std::string & input, bool throw_on_failure = false);
954 :
955 : /**
956 : * Linearly partition a number of items
957 : *
958 : * @param num_items The number of items to partition
959 : * @param num_chunks The number of chunks to partition into
960 : * @param chunk_id The ID of the chunk you are trying to get information about (typically the
961 : * current MPI rank)
962 : * @param num_local_items Output: The number of items for this chunk_id
963 : * @param local_items_begin Output: The first item for this chunk_id
964 : * @param local_items_end Output: One past the final item for this chunk_id
965 : */
966 : void linearPartitionItems(dof_id_type num_items,
967 : dof_id_type num_chunks,
968 : dof_id_type chunk_id,
969 : dof_id_type & num_local_items,
970 : dof_id_type & local_items_begin,
971 : dof_id_type & local_items_end);
972 :
973 : /**
974 : * Return the chunk_id that is assigned to handle item_id
975 : *
976 : * @param num_items Global number of items to partition
977 : * @param num_chunks Total number of chunks to split into
978 : * @param item_id The item to find the chunk_id for
979 : * @return The chunk_id of the chunk that contains item_id
980 : */
981 : processor_id_type
982 : linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id);
983 :
984 : /**
985 : * Wrapper around PetscGetRealPath, which is a cross-platform replacement for realpath
986 : */
987 : std::string realpath(const std::string & path);
988 :
989 : /**
990 : * Custom type trait that has a ::value of true for types that cam be use interchangeably
991 : * with Real. Most notably it is false for complex numbers, which do not have a
992 : * strict ordering (and therefore no <,>,<=,>= operators).
993 : */
994 : template <typename T>
995 : struct IsLikeReal
996 : {
997 : static constexpr bool value = false;
998 : };
999 : template <>
1000 : struct IsLikeReal<Real>
1001 : {
1002 : static constexpr bool value = true;
1003 : };
1004 : template <>
1005 : struct IsLikeReal<ADReal>
1006 : {
1007 : static constexpr bool value = true;
1008 : };
1009 :
1010 : /**
1011 : * Custom type trait that has a ::value of true for types that can be broadcasted
1012 : */
1013 : template <typename T>
1014 : struct canBroadcast
1015 : {
1016 : static constexpr bool value = std::is_base_of<TIMPI::DataType, TIMPI::StandardType<T>>::value ||
1017 : TIMPI::Has_buffer_type<TIMPI::Packing<T>>::value;
1018 : };
1019 :
1020 : ///@{ Comparison helpers that support the MooseUtils::Any wildcard which will match any value
1021 : const static struct AnyType
1022 : {
1023 : } Any;
1024 :
1025 : template <typename T1, typename T2>
1026 : bool
1027 47767 : wildcardEqual(const T1 & a, const T2 & b)
1028 : {
1029 47767 : return a == b;
1030 : }
1031 :
1032 : template <typename T>
1033 : bool
1034 : wildcardEqual(const T &, AnyType)
1035 : {
1036 : return true;
1037 : }
1038 : template <typename T>
1039 : bool
1040 5052 : wildcardEqual(AnyType, const T &)
1041 : {
1042 5052 : return true;
1043 : }
1044 : ///@}
1045 :
1046 : /**
1047 : * Find a specific pair in a container matching on first, second or both pair components
1048 : */
1049 : template <typename C, typename It, typename M1, typename M2>
1050 : auto
1051 53566 : findPair(C & container, It start_iterator, const M1 & first, const M2 & second)
1052 : {
1053 53566 : return std::find_if(start_iterator,
1054 : container.end(),
1055 47767 : [&](auto & item) {
1056 52819 : return wildcardEqual(first, item.first) &&
1057 52819 : wildcardEqual(second, item.second);
1058 53566 : });
1059 : }
1060 :
1061 : /**
1062 : * Construct a valid bounding box from 2 arbitrary points
1063 : *
1064 : * If you have 2 points in space and you wish to construct a bounding box, you should use
1065 : * this method to avoid unexpected behavior of the underlying BoundingBox class in libMesh.
1066 : * BoundingBox class expect 2 points whose coordinates are "sorted" (i.e., x-, y- and -z
1067 : * coordinates of the first point are smaller then the corresponding coordinates of the second
1068 : * point). If this "sorting" is not present, the BoundingBox class will build an empty box and
1069 : * any further testing of points inside the box will fail. This method will allow you to obtain
1070 : * the correct bounding box for any valid combination of 2 corner points of a box.
1071 : *
1072 : * @param p1 First corner of the constructed bounding box
1073 : * @param p2 Second corner of the constructed bounding box
1074 : * @return Valid bounding box
1075 : */
1076 : libMesh::BoundingBox buildBoundingBox(const Point & p1, const Point & p2);
1077 :
1078 : /**
1079 : * Utility class template for a semidynamic vector with a maximum size N
1080 : * and a chosen dynamic size. This container avoids heap allocation and
1081 : * is meant as a replacement for small local std::vector variables.
1082 : * By default this class uses `value initialization`. This can be disabled
1083 : * using the third template parameter if uninitialized storage is acceptable,
1084 : */
1085 : template <typename T, std::size_t N, bool value_init = true>
1086 : #if METAPHYSICL_MAJOR_VERSION < 2
1087 : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>>
1088 : {
1089 : typedef MetaPhysicL::DynamicStdArrayWrapper<T, MetaPhysicL::NWrapper<N>> Parent;
1090 : #else
1091 : class SemidynamicVector : public MetaPhysicL::DynamicStdArrayWrapper<T, N>
1092 : {
1093 : typedef MetaPhysicL::DynamicStdArrayWrapper<T, N> Parent;
1094 : #endif
1095 :
1096 : public:
1097 19360038 : SemidynamicVector(std::size_t size) : Parent()
1098 : {
1099 4840014 : Parent::resize(size);
1100 : if constexpr (value_init)
1101 19328140 : for (const auto i : make_range(size))
1102 14488128 : _data[i] = T{};
1103 4840014 : }
1104 :
1105 2 : void resize(std::size_t new_size)
1106 : {
1107 2 : [[maybe_unused]] const auto old_dynamic_n = Parent::size();
1108 :
1109 2 : Parent::resize(new_size);
1110 :
1111 : if constexpr (value_init)
1112 : for (const auto i : make_range(old_dynamic_n, _dynamic_n))
1113 : _data[i] = T{};
1114 2 : }
1115 :
1116 2 : void push_back(const T & v)
1117 : {
1118 2 : const auto old_dynamic_n = Parent::size();
1119 2 : Parent::resize(old_dynamic_n + 1);
1120 2 : _data[old_dynamic_n] = v;
1121 2 : }
1122 :
1123 : template <typename... Args>
1124 2 : void emplace_back(Args &&... args)
1125 : {
1126 2 : const auto old_dynamic_n = Parent::size();
1127 2 : Parent::resize(old_dynamic_n + 1);
1128 2 : (::new (&_data[old_dynamic_n]) T(std::forward<Args>(args)...));
1129 2 : }
1130 :
1131 2 : std::size_t max_size() const { return N; }
1132 :
1133 : using Parent::_data;
1134 : using Parent::_dynamic_n;
1135 : };
1136 :
1137 : /**
1138 : * The MooseUtils::get() specializations are used to support making
1139 : * forwards-compatible code changes from dumb pointers to smart pointers.
1140 : * The same line of code, e.g.
1141 : *
1142 : * libMesh::Parameters::Value * value = MooseUtils::get(map_iter->second);
1143 : *
1144 : * will then work regardless of whether map_iter->second is a dumb pointer
1145 : * or a smart pointer. Note that the smart pointer get() functions are const
1146 : * so they can be (ab)used to get a non-const pointer to the underlying
1147 : * resource. We are simply following this convention here.
1148 : */
1149 : template <typename T>
1150 : T *
1151 128351611 : get(const std::unique_ptr<T> & u)
1152 : {
1153 128351611 : return u.get();
1154 : }
1155 :
1156 : template <typename T>
1157 : T *
1158 : get(T * p)
1159 : {
1160 : return p;
1161 : }
1162 :
1163 : template <typename T>
1164 : T *
1165 : get(const std::shared_ptr<T> & s)
1166 : {
1167 : return s.get();
1168 : }
1169 :
1170 : /**
1171 : * This method detects whether two sets intersect without building a result set.
1172 : * It exits as soon as any intersection is detected.
1173 : */
1174 : template <class InputIterator>
1175 : bool
1176 33 : setsIntersect(InputIterator first1, InputIterator last1, InputIterator first2, InputIterator last2)
1177 : {
1178 46 : while (first1 != last1 && first2 != last2)
1179 : {
1180 16 : if (*first1 == *first2)
1181 3 : return true;
1182 :
1183 13 : if (*first1 < *first2)
1184 0 : ++first1;
1185 13 : else if (*first1 > *first2)
1186 13 : ++first2;
1187 : }
1188 30 : return false;
1189 : }
1190 :
1191 : template <class T>
1192 : bool
1193 33 : setsIntersect(const T & s1, const T & s2)
1194 : {
1195 33 : return setsIntersect(s1.begin(), s1.end(), s2.begin(), s2.end());
1196 : }
1197 :
1198 : /**
1199 : * Courtesy https://stackoverflow.com/a/8889045 and
1200 : * https://en.cppreference.com/w/cpp/string/byte/isdigit
1201 : * @return Whether every character in the string is a digit
1202 : */
1203 : inline bool
1204 1526063 : isDigits(const std::string & str)
1205 : {
1206 3585883 : return std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isdigit(c); });
1207 : }
1208 :
1209 : /**
1210 : * Courtesy https://stackoverflow.com/a/57163016 and
1211 : * https://stackoverflow.com/questions/447206/c-isfloat-function
1212 : * @return Whether the string is convertible to a float
1213 : */
1214 : inline bool
1215 15 : isFloat(const std::string & str)
1216 : {
1217 15 : if (str.empty())
1218 0 : return false;
1219 : char * ptr;
1220 15 : strtof(str.c_str(), &ptr);
1221 15 : return (*ptr) == '\0';
1222 : }
1223 :
1224 : /**
1225 : * Gets the canonical path of the given path
1226 : */
1227 : std::string canonicalPath(const std::string & path);
1228 :
1229 : /**
1230 : * @returns Whether the \p string1 starts with \p string2
1231 : */
1232 : bool startsWith(const std::string & string1, const std::string & string2);
1233 :
1234 : /**
1235 : * Replace the starting string \p string2 of \p string1 with \p string3. A user should have checked
1236 : * that \p string1 \p startsWith \p string2
1237 : */
1238 : void replaceStart(std::string & string1, const std::string & string2, const std::string & string3);
1239 :
1240 : /**
1241 : * @returns whether every alphabetic character in a string is lower-case
1242 : */
1243 : bool isAllLowercase(const std::string & str);
1244 : } // MooseUtils namespace
1245 :
1246 : namespace Moose
1247 : {
1248 : template <typename T>
1249 : struct ADType;
1250 :
1251 : template <typename T, std::size_t N, bool value_init>
1252 : struct ADType<MooseUtils::SemidynamicVector<T, N, value_init>>
1253 : {
1254 : typedef MooseUtils::SemidynamicVector<typename ADType<T>::type, N, value_init> type;
1255 : };
1256 : }
1257 :
1258 : /**
1259 : * find, erase, length algorithm for removing a substring from a string
1260 : */
1261 : void removeSubstring(std::string & main, const std::string & sub);
1262 :
1263 : /**
1264 : * find, erase, length algorithm for removing a substring from a copy of a string
1265 : */
1266 : std::string removeSubstring(const std::string & main, const std::string & sub);
|