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 : // MOOSE includes
11 : #include "MooseUtils.h"
12 : #include "MooseError.h"
13 : #include "MaterialProperty.h"
14 : #include "MultiMooseEnum.h"
15 : #include "InputParameters.h"
16 : #include "ExecFlagEnum.h"
17 : #include "InfixIterator.h"
18 : #include "Registry.h"
19 : #include "MortarConstraintBase.h"
20 : #include "MortarNodalAuxKernel.h"
21 : #include "ExecFlagRegistry.h"
22 : #include "RestartableDataReader.h"
23 :
24 : #include "libmesh/utility.h"
25 : #include "libmesh/elem.h"
26 :
27 : // External includes
28 : #include "pcrecpp.h"
29 : #include "tinydir.h"
30 :
31 : // C++ includes
32 : #include <iostream>
33 : #include <fstream>
34 : #include <istream>
35 : #include <iterator>
36 : #include <filesystem>
37 : #include <ctime>
38 : #include <cstdlib>
39 : #include <regex>
40 :
41 : // System includes
42 : #include <sys/stat.h>
43 : #include <numeric>
44 : #include <unistd.h>
45 :
46 : #include "petscsys.h"
47 :
48 : #ifdef __WIN32__
49 : #include <windows.h>
50 : #include <winbase.h>
51 : #include <fileapi.h>
52 : #else
53 : #include <sys/ioctl.h>
54 : #endif
55 :
56 : namespace MooseUtils
57 : {
58 : std::filesystem::path
59 130245 : pathjoin(const std::filesystem::path & p)
60 : {
61 130245 : return p;
62 : }
63 :
64 : std::string
65 7 : runTestsExecutable()
66 : {
67 7 : auto build_loc = pathjoin(Moose::getExecutablePath(), "run_tests");
68 7 : if (pathExists(build_loc) && checkFileReadable(build_loc))
69 7 : return build_loc;
70 : // TODO: maybe no path prefix - just moose_test_runner here?
71 0 : return pathjoin(Moose::getExecutablePath(), "moose_test_runner");
72 7 : }
73 :
74 : std::string
75 7 : findTestRoot()
76 : {
77 7 : std::string path = ".";
78 7 : for (int i = 0; i < 5; i++)
79 : {
80 7 : auto testroot = pathjoin(path, "testroot");
81 7 : if (pathExists(testroot) && checkFileReadable(testroot))
82 7 : return testroot;
83 0 : path += "/..";
84 7 : }
85 0 : return "";
86 7 : }
87 :
88 : bool
89 2473 : parsesToReal(const std::string & input)
90 : {
91 2473 : std::istringstream ss(input);
92 : Real real_value;
93 2473 : if (ss >> real_value && ss.eof())
94 1819 : return true;
95 654 : return false;
96 2473 : }
97 :
98 : std::string
99 14 : installedInputsDir(const std::string & app_name,
100 : const std::string & dir_name,
101 : const std::string & extra_error_msg)
102 : {
103 : // See moose.mk for a detailed explanation of the assumed installed application
104 : // layout. Installed inputs are expected to be installed in "share/<app_name>/<folder>".
105 : // The binary, which has a defined location will be in "bin", a peer directory to "share".
106 : std::string installed_path =
107 14 : pathjoin(Moose::getExecutablePath(), "..", "share", app_name, dir_name);
108 :
109 14 : auto test_root = pathjoin(installed_path, "testroot");
110 14 : if (!pathExists(installed_path))
111 0 : mooseError("Couldn't locate any installed inputs to copy in path: ",
112 : installed_path,
113 0 : '\n',
114 : extra_error_msg);
115 :
116 14 : checkFileReadable(test_root);
117 28 : return installed_path;
118 14 : }
119 :
120 : std::string
121 0 : docsDir(const std::string & app_name)
122 : {
123 : // See moose.mk for a detailed explanation of the assumed installed application
124 : // layout. Installed docs are expected to be installed in "share/<app_name>/doc".
125 : // The binary, which has a defined location will be in "bin", a peer directory to "share".
126 0 : std::string installed_path = pathjoin(Moose::getExecutablePath(), "..", "share", app_name, "doc");
127 :
128 0 : auto docfile = pathjoin(installed_path, "css", "moose.css");
129 0 : if (pathExists(docfile) && checkFileReadable(docfile))
130 0 : return installed_path;
131 0 : return "";
132 0 : }
133 :
134 : std::string
135 19544988 : mooseDocsURL(const std::string & path)
136 : {
137 19544988 : return "https://mooseframework.inl.gov/" + path;
138 : }
139 :
140 : std::string
141 215255 : replaceAll(std::string str, const std::string & from, const std::string & to)
142 : {
143 215255 : size_t start_pos = 0;
144 216006 : while ((start_pos = str.find(from, start_pos)) != std::string::npos)
145 : {
146 751 : str.replace(start_pos, from.length(), to);
147 751 : start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
148 : }
149 215255 : return str;
150 : }
151 :
152 : std::string
153 3370 : convertLatestCheckpoint(std::string orig)
154 : {
155 3370 : auto slash_pos = orig.find_last_of("/");
156 3370 : auto path = orig.substr(0, slash_pos);
157 3370 : auto file = orig.substr(slash_pos + 1);
158 3370 : if (file != "LATEST")
159 3079 : return orig;
160 :
161 291 : auto converted = MooseUtils::getLatestCheckpointFilePrefix(MooseUtils::listDir(path));
162 :
163 291 : if (converted.empty())
164 0 : mooseError("Unable to find suitable recovery file!");
165 :
166 291 : return converted;
167 3370 : }
168 :
169 : // this implementation is copied from
170 : // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.2B.2B
171 : int
172 3623 : levenshteinDist(const std::string & s1, const std::string & s2)
173 : {
174 : // To change the type this function manipulates and returns, change
175 : // the return type and the types of the two variables below.
176 3623 : auto s1len = s1.size();
177 3623 : auto s2len = s2.size();
178 :
179 3623 : auto column_start = (decltype(s1len))1;
180 :
181 3623 : auto column = new decltype(s1len)[s1len + 1];
182 3623 : std::iota(column + column_start, column + s1len + 1, column_start);
183 :
184 35935 : for (auto x = column_start; x <= s2len; x++)
185 : {
186 32312 : column[0] = x;
187 32312 : auto last_diagonal = x - column_start;
188 411673 : for (auto y = column_start; y <= s1len; y++)
189 : {
190 379361 : auto old_diagonal = column[y];
191 379361 : auto possibilities = {
192 379361 : column[y] + 1, column[y - 1] + 1, last_diagonal + (s1[y - 1] == s2[x - 1] ? 0 : 1)};
193 379361 : column[y] = std::min(possibilities);
194 379361 : last_diagonal = old_diagonal;
195 : }
196 : }
197 3623 : auto result = column[s1len];
198 3623 : delete[] column;
199 3623 : return result;
200 : }
201 :
202 : void
203 7104971 : escape(std::string & str)
204 : {
205 7104971 : std::map<char, std::string> escapes;
206 7104971 : escapes['\a'] = "\\a";
207 7104971 : escapes['\b'] = "\\b";
208 7104971 : escapes['\f'] = "\\f";
209 7104971 : escapes['\n'] = "\\n";
210 7104971 : escapes['\t'] = "\\t";
211 7104971 : escapes['\v'] = "\\v";
212 7104971 : escapes['\r'] = "\\r";
213 :
214 56839768 : for (const auto & it : escapes)
215 49734953 : for (size_t pos = 0; (pos = str.find(it.first, pos)) != std::string::npos;
216 156 : pos += it.second.size())
217 156 : str.replace(pos, 1, it.second);
218 7104971 : }
219 :
220 : std::string
221 444935 : removeExtraWhitespace(const std::string & input)
222 : {
223 889870 : return std::regex_replace(input, std::regex("^\\s+|\\s+$|\\s+(?=\\s)"), "");
224 : }
225 :
226 : bool
227 0 : pathContains(const std::string & expression,
228 : const std::string & string_to_find,
229 : const std::string & delims)
230 : {
231 0 : std::vector<std::string> elements;
232 0 : tokenize(expression, elements, 0, delims);
233 :
234 : std::vector<std::string>::iterator found_it =
235 0 : std::find(elements.begin(), elements.end(), string_to_find);
236 0 : if (found_it != elements.end())
237 0 : return true;
238 : else
239 0 : return false;
240 0 : }
241 :
242 : bool
243 22740 : pathExists(const std::string & path)
244 : {
245 : struct stat buffer;
246 22740 : return (stat(path.c_str(), &buffer) == 0);
247 : }
248 :
249 : bool
250 328723 : checkFileReadable(const std::string & filename,
251 : bool check_line_endings,
252 : bool throw_on_unreadable,
253 : bool check_for_git_lfs_pointer)
254 : {
255 328723 : std::ifstream in(filename.c_str(), std::ifstream::in);
256 328723 : if (in.fail())
257 : {
258 67224 : if (throw_on_unreadable)
259 17 : mooseError(
260 23 : (std::string("Unable to open file \"") + filename +
261 20 : std::string("\". Check to make sure that it exists and that you have read permission."))
262 18 : .c_str());
263 : else
264 67207 : return false;
265 : }
266 :
267 261499 : if (check_line_endings)
268 : {
269 62440 : std::istream_iterator<char> iter(in);
270 62440 : std::istream_iterator<char> eos;
271 62440 : in >> std::noskipws;
272 76355988 : while (iter != eos)
273 76293548 : if (*iter++ == '\r')
274 0 : mooseError(filename + " contains Windows(DOS) line endings which are not supported.");
275 : }
276 :
277 261499 : if (check_for_git_lfs_pointer && checkForGitLFSPointer(in))
278 8 : mooseError(filename + " appears to be a Git-LFS pointer. Make sure you have \"git-lfs\" "
279 : "installed so that you may pull this file.");
280 261491 : in.close();
281 :
282 261491 : return true;
283 328699 : }
284 :
285 : bool
286 198462 : checkForGitLFSPointer(std::ifstream & file)
287 : {
288 : mooseAssert(file.is_open(), "Passed in file handle is not open");
289 :
290 198462 : std::string line;
291 :
292 : // git-lfs pointer files contain several name value pairs. The specification states that the
293 : // first name/value pair must be "version {url}". We'll do a simplified check for that.
294 198462 : file.seekg(0);
295 198462 : std::getline(file, line);
296 198462 : if (line.find("version https://") != std::string::npos)
297 8 : return true;
298 : else
299 198454 : return false;
300 198462 : }
301 :
302 : bool
303 240 : checkFileWriteable(const std::string & filename, bool throw_on_unwritable)
304 : {
305 240 : std::ofstream out(filename.c_str(), std::ios_base::app);
306 240 : if (out.fail())
307 : {
308 0 : if (throw_on_unwritable)
309 0 : mooseError(
310 0 : (std::string("Unable to open file \"") + filename +
311 0 : std::string("\". Check to make sure that it exists and that you have write permission."))
312 0 : .c_str());
313 : else
314 0 : return false;
315 : }
316 :
317 240 : out.close();
318 :
319 240 : return true;
320 240 : }
321 :
322 : void
323 240442 : parallelBarrierNotify(const Parallel::Communicator & comm, bool messaging)
324 : {
325 : processor_id_type secondary_processor_id;
326 :
327 240442 : if (messaging)
328 0 : Moose::out << "Waiting For Other Processors To Finish" << std::endl;
329 240442 : if (comm.rank() == 0)
330 : {
331 : // The primary process is already through, so report it
332 173928 : if (messaging)
333 0 : Moose::out << "Jobs complete: 1/" << comm.size() << (1 == comm.size() ? "\n" : "\r")
334 0 : << std::flush;
335 240442 : for (unsigned int i = 2; i <= comm.size(); ++i)
336 : {
337 66514 : comm.receive(MPI_ANY_SOURCE, secondary_processor_id);
338 66514 : if (messaging)
339 0 : Moose::out << "Jobs complete: " << i << "/" << comm.size()
340 0 : << (i == comm.size() ? "\n" : "\r") << std::flush;
341 : }
342 : }
343 : else
344 : {
345 66514 : secondary_processor_id = comm.rank();
346 66514 : comm.send(0, secondary_processor_id);
347 : }
348 :
349 240442 : comm.barrier();
350 240442 : }
351 :
352 : void
353 10 : serialBegin(const libMesh::Parallel::Communicator & comm, bool warn)
354 : {
355 : // unless we are the first processor...
356 10 : if (comm.rank() > 0)
357 : {
358 : // ...wait for the previous processor to finish
359 3 : int dummy = 0;
360 3 : comm.receive(comm.rank() - 1, dummy);
361 : }
362 7 : else if (warn)
363 0 : mooseWarning("Entering serial execution block (use only for debugging)");
364 10 : }
365 :
366 : void
367 10 : serialEnd(const libMesh::Parallel::Communicator & comm, bool warn)
368 : {
369 : // unless we are the last processor...
370 10 : if (comm.rank() + 1 < comm.size())
371 : {
372 : // ...notify the next processor of its turn
373 3 : int dummy = 0;
374 3 : comm.send(comm.rank() + 1, dummy);
375 : }
376 :
377 10 : comm.barrier();
378 10 : if (comm.rank() == 0 && warn)
379 0 : mooseWarning("Leaving serial execution block (use only for debugging)");
380 10 : }
381 :
382 : bool
383 23813 : hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext)
384 : {
385 : // Extract the extension, w/o the '.'
386 23813 : std::string file_ext;
387 23813 : if (strip_exodus_ext)
388 : {
389 : pcrecpp::RE re(
390 570 : ".*\\.([^\\.]*?)(?:-s\\d+)?\\s*$"); // capture the complete extension, ignoring -s*
391 570 : re.FullMatch(filename, &file_ext);
392 570 : }
393 : else
394 : {
395 23243 : pcrecpp::RE re(".*\\.([^\\.]*?)\\s*$"); // capture the complete extension
396 23243 : re.FullMatch(filename, &file_ext);
397 23243 : }
398 :
399 : // Perform the comparision
400 23813 : if (file_ext == ext)
401 12710 : return true;
402 : else
403 11103 : return false;
404 23813 : }
405 :
406 : std::string
407 623 : getExtension(const std::string & filename, const bool rfind)
408 : {
409 623 : std::string file_ext = "";
410 623 : if (filename != "")
411 : {
412 : // The next line splits filename at the last "/" and gives the file name after "/"
413 611 : const std::string stripped_filename = splitFileName<std::string>(filename).second;
414 611 : auto pos = rfind ? stripped_filename.rfind(".") : stripped_filename.find(".");
415 611 : if (pos != std::string::npos)
416 185 : file_ext += stripped_filename.substr(pos + 1, std::string::npos);
417 611 : }
418 :
419 623 : return file_ext;
420 0 : }
421 :
422 : std::string
423 251 : stripExtension(const std::string & s, const bool rfind)
424 : {
425 251 : const std::string ext = getExtension(s, rfind);
426 251 : const bool offset = (ext.size() != 0);
427 : // -1 offset accounts for the extension's leading dot ("."), if there is an extension
428 502 : return s.substr(0, s.size() - ext.size() - offset);
429 251 : }
430 :
431 : std::string
432 7 : getCurrentWorkingDir()
433 : {
434 : // Note: At the time of creating this method, our minimum compiler still
435 : // does not support <filesystem>. Additionally, the inclusion of that header
436 : // requires an additional library to be linked so for now, we'll just
437 : // use the Unix standard library to get us the cwd().
438 7 : constexpr unsigned int BUF_SIZE = 1024;
439 : char buffer[BUF_SIZE];
440 :
441 7 : return getcwd(buffer, BUF_SIZE) != nullptr ? buffer : "";
442 : }
443 :
444 : void
445 8 : makedirs(const std::string & dir_name, bool throw_on_failure)
446 : {
447 : // split path into directories with delimiter '/'
448 8 : std::vector<std::string> split_dir_names;
449 8 : MooseUtils::tokenize(dir_name, split_dir_names);
450 :
451 8 : auto n = split_dir_names.size();
452 :
453 : // remove '.' and '..' when possible
454 8 : auto i = n;
455 8 : i = 0;
456 36 : while (i != n)
457 : {
458 28 : if (split_dir_names[i] == ".")
459 : {
460 3 : for (auto j = i + 1; j < n; ++j)
461 2 : split_dir_names[j - 1] = split_dir_names[j];
462 1 : --n;
463 : }
464 27 : else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
465 : {
466 4 : for (auto j = i + 1; j < n; ++j)
467 3 : split_dir_names[j - 2] = split_dir_names[j];
468 1 : n -= 2;
469 1 : --i;
470 : }
471 : else
472 26 : ++i;
473 : }
474 8 : if (n == 0)
475 0 : return;
476 :
477 8 : split_dir_names.resize(n);
478 :
479 : // start creating directories recursively
480 8 : std::string cur_dir = dir_name[0] == '/' ? "" : ".";
481 32 : for (auto & dir : split_dir_names)
482 : {
483 25 : cur_dir += "/" + dir;
484 :
485 25 : if (!pathExists(cur_dir))
486 : {
487 17 : auto code = Utility::mkdir(cur_dir.c_str());
488 17 : if (code != 0)
489 : {
490 1 : std::string msg = "Failed creating directory " + dir_name;
491 1 : if (throw_on_failure)
492 1 : throw std::invalid_argument(msg);
493 : else
494 0 : mooseError(msg);
495 1 : }
496 : }
497 : }
498 9 : }
499 :
500 : void
501 7 : removedirs(const std::string & dir_name, bool throw_on_failure)
502 : {
503 : // split path into directories with delimiter '/'
504 7 : std::vector<std::string> split_dir_names;
505 7 : MooseUtils::tokenize(dir_name, split_dir_names);
506 :
507 7 : auto n = split_dir_names.size();
508 :
509 : // remove '.' and '..' when possible
510 7 : auto i = n;
511 7 : i = 0;
512 34 : while (i != n)
513 : {
514 27 : if (split_dir_names[i] == ".")
515 : {
516 3 : for (auto j = i + 1; j < n; ++j)
517 2 : split_dir_names[j - 1] = split_dir_names[j];
518 1 : --n;
519 : }
520 26 : else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
521 : {
522 4 : for (auto j = i + 1; j < n; ++j)
523 3 : split_dir_names[j - 2] = split_dir_names[j];
524 1 : n -= 2;
525 1 : --i;
526 : }
527 : else
528 25 : ++i;
529 : }
530 7 : if (n == 0)
531 0 : return;
532 :
533 7 : split_dir_names.resize(n);
534 :
535 : // start removing directories recursively
536 7 : std::string base_dir = dir_name[0] == '/' ? "" : ".";
537 23 : for (i = n; i > 0; --i)
538 : {
539 19 : std::string cur_dir = base_dir;
540 19 : auto j = i;
541 71 : for (j = 0; j < i; ++j)
542 52 : cur_dir += "/" + split_dir_names[j];
543 :
544 : // listDir should return at least '.' and '..'
545 19 : if (pathExists(cur_dir) && listDir(cur_dir).size() == 2)
546 : {
547 16 : auto code = rmdir(cur_dir.c_str());
548 16 : if (code != 0)
549 : {
550 0 : std::string msg = "Failed removing directory " + dir_name;
551 0 : if (throw_on_failure)
552 0 : throw std::invalid_argument(msg);
553 : else
554 0 : mooseError(msg);
555 0 : }
556 : }
557 : else
558 : // stop removing
559 3 : break;
560 19 : }
561 7 : }
562 :
563 : std::string
564 19 : camelCaseToUnderscore(const std::string & camel_case_name)
565 : {
566 19 : std::string replaced = camel_case_name;
567 : // Put underscores in front of each contiguous set of capital letters
568 19 : pcrecpp::RE("(?!^)(?<![A-Z_])([A-Z]+)").GlobalReplace("_\\1", &replaced);
569 :
570 : // Convert all capital letters to lower case
571 19 : std::transform(replaced.begin(), replaced.end(), replaced.begin(), ::tolower);
572 19 : return replaced;
573 0 : }
574 :
575 : std::string
576 510 : underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case)
577 : {
578 510 : pcrecpp::StringPiece input(underscore_name);
579 510 : pcrecpp::RE re("([^_]*)(_|$)");
580 :
581 510 : std::string result;
582 510 : std::string us, not_us;
583 510 : bool make_upper = leading_upper_case;
584 522 : while (re.Consume(&input, ¬_us, &us))
585 : {
586 522 : if (not_us.length() > 0)
587 : {
588 516 : if (make_upper)
589 : {
590 514 : result += std::toupper(not_us[0]);
591 514 : if (not_us.length() > 1)
592 514 : result += not_us.substr(1);
593 : }
594 : else
595 2 : result += not_us;
596 : }
597 522 : if (us == "")
598 510 : break;
599 :
600 : // Toggle flag so next match is upper cased
601 12 : make_upper = true;
602 : }
603 :
604 1020 : return result;
605 510 : }
606 :
607 : std::string
608 4426663 : shortName(const std::string & name)
609 : {
610 4426663 : return name.substr(name.find_last_of('/') != std::string::npos ? name.find_last_of('/') + 1 : 0);
611 : }
612 :
613 : std::string
614 1388297 : baseName(const std::string & name)
615 : {
616 1388297 : return name.substr(0, name.find_last_of('/') != std::string::npos ? name.find_last_of('/') : 0);
617 : }
618 :
619 : std::string
620 11 : hostname()
621 : {
622 : char hostname[1024];
623 11 : hostname[1023] = '\0';
624 : #ifndef __WIN32__
625 11 : if (gethostname(hostname, 1023))
626 0 : mooseError("Failed to retrieve hostname!");
627 : #else
628 : DWORD dwSize = sizeof(hostname);
629 : if (!GetComputerNameEx(ComputerNamePhysicalDnsHostname, hostname, &dwSize))
630 : mooseError("Failed to retrieve hostname!");
631 : #endif
632 11 : return hostname;
633 : }
634 :
635 : unsigned short
636 121815 : getTermWidth(bool use_environment)
637 : {
638 : #ifndef __WIN32__
639 : struct winsize w;
640 : #else
641 : struct
642 : {
643 : unsigned short ws_col;
644 : } w;
645 : #endif
646 : /**
647 : * Initialize the value we intend to populate just in case
648 : * the system call fails
649 : */
650 121815 : w.ws_col = std::numeric_limits<unsigned short>::max();
651 :
652 121815 : if (use_environment)
653 : {
654 121815 : char * pps_width = std::getenv("MOOSE_PPS_WIDTH");
655 121815 : if (pps_width != NULL)
656 : {
657 0 : std::stringstream ss(pps_width);
658 0 : ss >> w.ws_col;
659 0 : }
660 : }
661 : // Default to AUTO if no environment variable was set
662 121815 : if (w.ws_col == std::numeric_limits<unsigned short>::max())
663 : {
664 : #ifndef __WIN32__
665 : try
666 : {
667 121815 : ioctl(0, TIOCGWINSZ, &w);
668 : }
669 : catch (...)
670 : #endif
671 : {
672 : }
673 : }
674 :
675 : // Something bad happened, make sure we have a sane value
676 : // 132 seems good for medium sized screens, and is available as a GNOME preset
677 121815 : if (w.ws_col == std::numeric_limits<unsigned short>::max())
678 121815 : w.ws_col = 132;
679 :
680 121815 : return w.ws_col;
681 : }
682 :
683 : void
684 0 : MaterialPropertyStorageDump(
685 : const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props)
686 : {
687 : // Loop through the elements
688 0 : for (const auto & elem_it : props)
689 : {
690 0 : Moose::out << "Element " << elem_it.first->id() << '\n';
691 :
692 : // Loop through the sides
693 0 : for (const auto & side_it : elem_it.second)
694 : {
695 0 : Moose::out << " Side " << side_it.first << '\n';
696 :
697 : // Loop over properties
698 0 : unsigned int cnt = 0;
699 0 : for (const auto & mat_prop : side_it.second)
700 : {
701 0 : if (auto mp = dynamic_cast<const MaterialProperty<Real> *>(&mat_prop))
702 : {
703 0 : Moose::out << " Property " << cnt << '\n';
704 0 : cnt++;
705 :
706 : // Loop over quadrature points
707 0 : for (unsigned int qp = 0; qp < mp->size(); ++qp)
708 0 : Moose::out << " prop[" << qp << "] = " << (*mp)[qp] << '\n';
709 : }
710 : }
711 : }
712 : }
713 :
714 0 : Moose::out << std::flush;
715 0 : }
716 :
717 : std::string &
718 19527 : removeColor(std::string & msg)
719 : {
720 19527 : pcrecpp::RE re("(\\33\\[3[0-7]m))", pcrecpp::DOTALL());
721 19527 : re.GlobalReplace(std::string(""), &msg);
722 19527 : return msg;
723 19527 : }
724 :
725 : void
726 0 : addLineBreaks(std::string & message,
727 : unsigned int line_width /*= ConsoleUtils::console_line_length*/)
728 : {
729 0 : for (auto i : make_range(int(message.length() / line_width)))
730 0 : message.insert((i + 1) * (line_width + 2) - 2, "\n");
731 0 : }
732 :
733 : void
734 1254755 : indentMessage(const std::string & prefix,
735 : std::string & message,
736 : const char * color /*= COLOR_CYAN*/,
737 : bool indent_first_line,
738 : const std::string & post_prefix)
739 : {
740 : // First we need to see if the message we need to indent (with color) also contains color codes
741 : // that span lines.
742 : // The code matches all of the XTERM constants (see XTermConstants.h). If it does, then we'll work
743 : // on formatting
744 : // each colored multiline chunk one at a time with the right codes.
745 1254755 : std::string colored_message;
746 1254755 : std::string curr_color = COLOR_DEFAULT; // tracks last color code before newline
747 1254755 : std::string line, color_code;
748 :
749 1254755 : bool ends_in_newline = message.empty() ? true : message.back() == '\n';
750 :
751 1254755 : bool first = true;
752 :
753 1254755 : std::istringstream iss(message);
754 3175135 : for (std::string line; std::getline(iss, line);) // loop over each line
755 : {
756 1920380 : const static pcrecpp::RE match_color(".*(\\33\\[3\\dm)((?!\\33\\[3\\d)[^\n])*");
757 1920380 : pcrecpp::StringPiece line_piece(line);
758 1920380 : match_color.FindAndConsume(&line_piece, &color_code);
759 :
760 1920380 : if (!first || indent_first_line)
761 1920380 : colored_message += color + prefix + post_prefix + curr_color;
762 :
763 1920380 : colored_message += line;
764 :
765 : // Only add a newline to the last line if it had one to begin with!
766 1920380 : if (!iss.eof() || ends_in_newline)
767 1856970 : colored_message += "\n";
768 :
769 1920380 : if (!color_code.empty())
770 897709 : curr_color = color_code; // remember last color of this line
771 :
772 1920380 : first = false;
773 1254755 : }
774 1254755 : message = colored_message;
775 1254755 : }
776 :
777 : std::list<std::string>
778 3235 : listDir(const std::string path, bool files_only)
779 : {
780 3235 : std::list<std::string> files;
781 :
782 3235 : tinydir_dir dir;
783 3235 : dir.has_next = 0; // Avoid a garbage value in has_next (clang StaticAnalysis)
784 3235 : tinydir_open(&dir, path.c_str());
785 :
786 20380 : while (dir.has_next)
787 : {
788 : tinydir_file file;
789 17145 : file.is_dir = 0; // Avoid a garbage value in is_dir (clang StaticAnalysis)
790 17145 : tinydir_readfile(&dir, &file);
791 :
792 17145 : if (!files_only || !file.is_dir)
793 17145 : files.push_back(path + "/" + file.name);
794 :
795 17145 : tinydir_next(&dir);
796 : }
797 :
798 3235 : tinydir_close(&dir);
799 :
800 6470 : return files;
801 0 : }
802 :
803 : std::list<std::string>
804 2892 : getFilesInDirs(const std::list<std::string> & directory_list, const bool files_only /* = true */)
805 : {
806 2892 : std::list<std::string> files;
807 :
808 5818 : for (const auto & dir_name : directory_list)
809 2926 : files.splice(files.end(), listDir(dir_name, files_only));
810 :
811 2892 : return files;
812 0 : }
813 :
814 : std::string
815 3183 : getLatestCheckpointFilePrefix(const std::list<std::string> & checkpoint_files)
816 : {
817 : // Create storage for newest restart files
818 : // Note that these might have the same modification time if the simulation was fast.
819 : // In that case we're going to save all of the "newest" files and sort it out momentarily
820 3183 : std::time_t newest_time = 0;
821 3183 : std::list<std::string> newest_restart_files;
822 :
823 : // Loop through all possible files and store the newest
824 20234 : for (const auto & cp_file : checkpoint_files)
825 : {
826 17051 : if (MooseUtils::hasExtension(cp_file, "rd"))
827 : {
828 : struct stat stats;
829 6292 : stat(cp_file.c_str(), &stats);
830 :
831 6292 : std::time_t mod_time = stats.st_mtime;
832 6292 : if (mod_time > newest_time)
833 : {
834 3295 : newest_restart_files.clear(); // If the modification time is greater, clear the list
835 3295 : newest_time = mod_time;
836 : }
837 :
838 6292 : if (mod_time == newest_time)
839 5883 : newest_restart_files.push_back(cp_file);
840 : }
841 : }
842 :
843 : // Loop through all of the newest files according the number in the file name
844 3183 : int max_file_num = -1;
845 3183 : std::string max_file;
846 3183 : std::string max_prefix;
847 :
848 : // Pull out the path including the number and the number itself
849 : // This takes something_blah_out_cp/0024-restart-1.rd
850 : // and returns "something_blah_out_cp/0024" as the "prefix"
851 : // and then "24" as the number itself
852 3183 : pcrecpp::RE re_file_num("(.*?(\\d+))-restart-\\d+.rd$");
853 :
854 : // Now, out of the newest files find the one with the largest number in it
855 8871 : for (const auto & res_file : newest_restart_files)
856 : {
857 5688 : int file_num = 0;
858 :
859 : // All of the file up to and including the digits
860 5688 : std::string file_prefix;
861 :
862 5688 : re_file_num.FullMatch(res_file, &file_prefix, &file_num);
863 :
864 5688 : if (file_num > max_file_num)
865 : {
866 : // Need both the header and the data
867 3332 : if (!RestartableDataReader::isAvailable(res_file))
868 0 : continue;
869 :
870 3332 : max_file_num = file_num;
871 3332 : max_file = res_file;
872 3332 : max_prefix = file_prefix;
873 : }
874 5688 : }
875 :
876 : // Error if nothing was located
877 3183 : if (max_file_num == -1)
878 8 : mooseError("No checkpoint file found!");
879 :
880 6350 : return max_prefix;
881 3175 : }
882 :
883 : bool
884 23342958 : wildCardMatch(std::string name, std::string search_string)
885 : {
886 : // Assume that an empty string matches anything
887 23342958 : if (search_string == "")
888 21801980 : return true;
889 :
890 : // transform to lower for case insenstive matching
891 1540978 : std::transform(name.begin(), name.end(), name.begin(), (int (*)(int))std::toupper);
892 1540978 : std::transform(search_string.begin(),
893 : search_string.end(),
894 : search_string.begin(),
895 : (int (*)(int))std::toupper);
896 :
897 : // exact match!
898 1540978 : if (search_string.find("*") == std::string::npos)
899 1540978 : return search_string == name;
900 :
901 : // wildcard
902 0 : std::vector<std::string> tokens;
903 0 : MooseUtils::tokenize(search_string, tokens, 1, "*");
904 :
905 0 : size_t pos = 0;
906 0 : for (unsigned int i = 0; i < tokens.size() && pos != std::string::npos; ++i)
907 : {
908 0 : pos = name.find(tokens[i], pos);
909 : // See if we have a leading wildcard
910 0 : if (search_string[0] != '*' && i == 0 && pos != 0)
911 0 : return false;
912 : }
913 :
914 0 : if (pos != std::string::npos && tokens.size() > 0)
915 : {
916 : // Now see if we have a trailing wildcard
917 0 : size_t last_token_length = tokens.back().length();
918 0 : if (*search_string.rbegin() == '*' || pos == name.size() - last_token_length)
919 0 : return true;
920 : else
921 0 : return false;
922 : }
923 : else
924 0 : return false;
925 0 : }
926 :
927 : bool
928 35871 : globCompare(const std::string & candidate,
929 : const std::string & pattern,
930 : std::size_t c,
931 : std::size_t p)
932 : {
933 35871 : if (p == pattern.size())
934 1670 : return c == candidate.size();
935 :
936 34201 : if (pattern[p] == '*')
937 : {
938 16220 : for (; c < candidate.size(); ++c)
939 15510 : if (globCompare(candidate, pattern, c, p + 1))
940 156 : return true;
941 710 : return globCompare(candidate, pattern, c, p + 1);
942 : }
943 :
944 33335 : if (pattern[p] != '?' && pattern[p] != candidate[c])
945 21670 : return false;
946 :
947 11665 : return globCompare(candidate, pattern, c + 1, p + 1);
948 : }
949 :
950 : template <typename T>
951 : T
952 4690 : convertStringToInt(const std::string & str, bool throw_on_failure)
953 : {
954 : T val;
955 :
956 : // Let's try to read a double and see if we can cast it to an int
957 : // This would be the case for scientific notation
958 : long double double_val;
959 4690 : std::stringstream double_ss(str);
960 4690 : double_ss >> double_val;
961 :
962 : // on arm64 the long double does not have sufficient precission
963 4690 : bool use_int = false;
964 4690 : std::stringstream int_ss(str);
965 4690 : if (!(int_ss >> val).fail() && int_ss.eof())
966 4226 : use_int = true;
967 :
968 4690 : if (double_ss.fail() || !double_ss.eof())
969 : {
970 894 : std::string msg =
971 894 : std::string("Unable to convert '") + str + "' to type " + demangle(typeid(T).name());
972 :
973 447 : if (throw_on_failure)
974 441 : throw std::invalid_argument(msg);
975 : else
976 6 : mooseError(msg);
977 443 : }
978 :
979 : // Check to see if it's an integer (and within range of an integer)
980 4243 : if (double_val == static_cast<long double>(static_cast<T>(double_val)))
981 8458 : return use_int ? val : static_cast<T>(double_val);
982 :
983 : // Still failure
984 28 : std::string msg =
985 28 : std::string("Unable to convert '") + str + "' to type " + demangle(typeid(T).name());
986 :
987 14 : if (throw_on_failure)
988 14 : throw std::invalid_argument(msg);
989 : else
990 0 : mooseError(msg);
991 5157 : }
992 :
993 : template <>
994 : short int
995 708 : convert<short int>(const std::string & str, bool throw_on_failure)
996 : {
997 708 : return convertStringToInt<short int>(str, throw_on_failure);
998 : }
999 :
1000 : template <>
1001 : unsigned short int
1002 1856 : convert<unsigned short int>(const std::string & str, bool throw_on_failure)
1003 : {
1004 1856 : return convertStringToInt<unsigned short int>(str, throw_on_failure);
1005 : }
1006 :
1007 : template <>
1008 : int
1009 498 : convert<int>(const std::string & str, bool throw_on_failure)
1010 : {
1011 498 : return convertStringToInt<int>(str, throw_on_failure);
1012 : }
1013 :
1014 : template <>
1015 : unsigned int
1016 1425 : convert<unsigned int>(const std::string & str, bool throw_on_failure)
1017 : {
1018 1425 : return convertStringToInt<unsigned int>(str, throw_on_failure);
1019 : }
1020 :
1021 : template <>
1022 : long int
1023 7 : convert<long int>(const std::string & str, bool throw_on_failure)
1024 : {
1025 7 : return convertStringToInt<long int>(str, throw_on_failure);
1026 : }
1027 :
1028 : template <>
1029 : unsigned long int
1030 138 : convert<unsigned long int>(const std::string & str, bool throw_on_failure)
1031 : {
1032 138 : return convertStringToInt<unsigned long int>(str, throw_on_failure);
1033 : }
1034 :
1035 : template <>
1036 : long long int
1037 7 : convert<long long int>(const std::string & str, bool throw_on_failure)
1038 : {
1039 7 : return convertStringToInt<long long int>(str, throw_on_failure);
1040 : }
1041 :
1042 : template <>
1043 : unsigned long long int
1044 51 : convert<unsigned long long int>(const std::string & str, bool throw_on_failure)
1045 : {
1046 51 : return convertStringToInt<unsigned long long int>(str, throw_on_failure);
1047 : }
1048 :
1049 : std::string
1050 4681952 : stringJoin(const std::vector<std::string> & values, const std::string & separator)
1051 : {
1052 4681952 : std::string combined;
1053 11444929 : for (const auto & value : values)
1054 6762977 : combined += value + separator;
1055 4681952 : if (values.size())
1056 4673833 : combined = combined.substr(0, combined.size() - separator.size());
1057 4681952 : return combined;
1058 0 : }
1059 :
1060 : bool
1061 1119810 : beginsWith(const std::string & value, const std::string & begin_value)
1062 : {
1063 1119810 : return value.rfind(begin_value, 0) == 0;
1064 : }
1065 :
1066 : ExecFlagEnum
1067 16955876 : getDefaultExecFlagEnum()
1068 : {
1069 16955876 : return moose::internal::ExecFlagRegistry::getExecFlagRegistry().getDefaultFlags();
1070 : }
1071 :
1072 : int
1073 394 : stringToInteger(const std::string & input, bool throw_on_failure)
1074 : {
1075 394 : return convert<int>(input, throw_on_failure);
1076 : }
1077 :
1078 : void
1079 802 : linearPartitionItems(dof_id_type num_items,
1080 : dof_id_type num_chunks,
1081 : dof_id_type chunk_id,
1082 : dof_id_type & num_local_items,
1083 : dof_id_type & local_items_begin,
1084 : dof_id_type & local_items_end)
1085 : {
1086 802 : auto global_num_local_items = num_items / num_chunks;
1087 :
1088 802 : num_local_items = global_num_local_items;
1089 :
1090 802 : auto leftovers = num_items % num_chunks;
1091 :
1092 802 : if (chunk_id < leftovers)
1093 : {
1094 33 : num_local_items++;
1095 33 : local_items_begin = num_local_items * chunk_id;
1096 : }
1097 : else
1098 769 : local_items_begin =
1099 769 : (global_num_local_items + 1) * leftovers + global_num_local_items * (chunk_id - leftovers);
1100 :
1101 802 : local_items_end = local_items_begin + num_local_items;
1102 802 : }
1103 :
1104 : processor_id_type
1105 356534 : linearPartitionChunk(dof_id_type num_items, dof_id_type num_chunks, dof_id_type item_id)
1106 : {
1107 356534 : auto global_num_local_items = num_items / num_chunks;
1108 :
1109 356534 : auto leftovers = num_items % num_chunks;
1110 :
1111 356534 : auto first_item_past_first_part = leftovers * (global_num_local_items + 1);
1112 :
1113 : // Is it in the first section (that gets an extra item)
1114 356534 : if (item_id < first_item_past_first_part)
1115 429 : return item_id / (global_num_local_items + 1);
1116 : else
1117 : {
1118 356105 : auto new_item_id = item_id - first_item_past_first_part;
1119 :
1120 : // First chunk after the first section + the number of chunks after that
1121 356105 : return leftovers + (new_item_id / global_num_local_items);
1122 : }
1123 : }
1124 :
1125 : std::vector<std::string>
1126 262897 : split(const std::string & str, const std::string & delimiter, std::size_t max_count)
1127 : {
1128 262897 : std::vector<std::string> output;
1129 262897 : std::size_t count = 0;
1130 262897 : size_t prev = 0, pos = 0;
1131 : do
1132 : {
1133 275459 : pos = str.find(delimiter, prev);
1134 275459 : output.push_back(str.substr(prev, pos - prev));
1135 275459 : prev = pos + delimiter.length();
1136 275459 : count += 1;
1137 275459 : } while (pos != std::string::npos && count < max_count);
1138 :
1139 262897 : if (pos != std::string::npos)
1140 1 : output.push_back(str.substr(prev));
1141 :
1142 262897 : return output;
1143 0 : }
1144 :
1145 : std::vector<std::string>
1146 9082 : rsplit(const std::string & str, const std::string & delimiter, std::size_t max_count)
1147 : {
1148 9082 : std::vector<std::string> output;
1149 9082 : std::size_t count = 0;
1150 9082 : size_t prev = str.length(), pos = str.length();
1151 : do
1152 : {
1153 15509 : pos = str.rfind(delimiter, prev);
1154 15509 : output.insert(output.begin(), str.substr(pos + delimiter.length(), prev - pos));
1155 15509 : prev = pos - delimiter.length();
1156 15509 : count += 1;
1157 15509 : } while (pos != std::string::npos && pos > 0 && count < max_count);
1158 :
1159 9082 : if (pos != std::string::npos)
1160 2 : output.insert(output.begin(), str.substr(0, pos));
1161 :
1162 9082 : return output;
1163 0 : }
1164 :
1165 : void
1166 145 : createSymlink(const std::string & target, const std::string & link)
1167 : {
1168 145 : clearSymlink(link);
1169 : #ifndef __WIN32__
1170 145 : auto err = symlink(target.c_str(), link.c_str());
1171 : #else
1172 : auto err = CreateSymbolicLink(target.c_str(), link.c_str(), 0);
1173 : #endif
1174 145 : if (err)
1175 0 : mooseError("Failed to create symbolic link (via 'symlink') from ", target, " to ", link);
1176 145 : }
1177 :
1178 : void
1179 4734 : clearSymlink(const std::string & link)
1180 : {
1181 : #ifndef __WIN32__
1182 : struct stat sbuf;
1183 4734 : if (lstat(link.c_str(), &sbuf) == 0)
1184 : {
1185 113 : auto err = unlink(link.c_str());
1186 113 : if (err != 0)
1187 0 : mooseError("Failed to remove symbolic link (via 'unlink') to ", link);
1188 : }
1189 : #else
1190 : auto attr = GetFileAttributesA(link.c_str());
1191 : if (attr != INVALID_FILE_ATTRIBUTES)
1192 : {
1193 : auto err = _unlink(link.c_str());
1194 : if (err != 0)
1195 : mooseError("Failed to remove link/file (via '_unlink') to ", link);
1196 : }
1197 : #endif
1198 4734 : }
1199 :
1200 : std::size_t
1201 116387 : fileSize(const std::string & filename)
1202 : {
1203 : #ifndef __WIN32__
1204 : struct stat buffer;
1205 116387 : if (!stat(filename.c_str(), &buffer))
1206 116387 : return buffer.st_size;
1207 : #else
1208 : HANDLE hFile = CreateFile(filename.c_str(),
1209 : GENERIC_READ,
1210 : FILE_SHARE_READ | FILE_SHARE_WRITE,
1211 : NULL,
1212 : OPEN_EXISTING,
1213 : FILE_ATTRIBUTE_NORMAL,
1214 : NULL);
1215 : if (hFile == INVALID_HANDLE_VALUE)
1216 : return 0;
1217 :
1218 : LARGE_INTEGER size;
1219 : if (GetFileSizeEx(hFile, &size))
1220 : {
1221 : CloseHandle(hFile);
1222 : return size.QuadPart;
1223 : }
1224 :
1225 : CloseHandle(hFile);
1226 : #endif
1227 0 : return 0;
1228 : }
1229 :
1230 : std::string
1231 62465 : realpath(const std::string & path)
1232 : {
1233 124930 : return std::filesystem::absolute(path);
1234 : }
1235 :
1236 : BoundingBox
1237 7036 : buildBoundingBox(const Point & p1, const Point & p2)
1238 : {
1239 7036 : BoundingBox bb;
1240 7036 : bb.union_with(p1);
1241 7036 : bb.union_with(p2);
1242 7036 : return bb;
1243 : }
1244 :
1245 : std::string
1246 6786982 : prettyCppType(const std::string & cpp_type)
1247 : {
1248 : // On mac many of the std:: classes are inline namespaced with __1
1249 : // On linux std::string can be inline namespaced with __cxx11
1250 6786982 : std::string s = cpp_type;
1251 : // Remove all spaces surrounding a >
1252 6786982 : pcrecpp::RE("\\s(?=>)").GlobalReplace("", &s);
1253 6786982 : pcrecpp::RE("std::__\\w+::").GlobalReplace("std::", &s);
1254 : // It would be nice if std::string actually looked normal
1255 6786982 : pcrecpp::RE("\\s*std::basic_string<char, std::char_traits<char>, std::allocator<char>>\\s*")
1256 6786982 : .GlobalReplace("std::string", &s);
1257 : // It would be nice if std::vector looked normal
1258 6786982 : pcrecpp::RE r("std::vector<([[:print:]]+),\\s?std::allocator<\\s?\\1\\s?>\\s?>");
1259 6786982 : r.GlobalReplace("std::vector<\\1>", &s);
1260 : // Do it again for nested vectors
1261 6786982 : r.GlobalReplace("std::vector<\\1>", &s);
1262 13573964 : return s;
1263 6786982 : }
1264 :
1265 : std::string
1266 63182 : canonicalPath(const std::string & path)
1267 : {
1268 126364 : return std::filesystem::weakly_canonical(path).c_str();
1269 : }
1270 :
1271 : bool
1272 0 : startsWith(const std::string & string1, const std::string & string2)
1273 : {
1274 0 : if (string2.size() > string1.size())
1275 0 : return false;
1276 0 : return string1.compare(0, string2.size(), string2) == 0;
1277 : }
1278 :
1279 : void
1280 0 : replaceStart(std::string & string1, const std::string & string2, const std::string & string3)
1281 : {
1282 : mooseAssert(startsWith(string1, string2),
1283 : "Cannot replace the start because it doesn't match the start string");
1284 0 : string1.replace(0, string2.size(), string3);
1285 0 : }
1286 :
1287 : bool
1288 0 : isAllLowercase(const std::string & str)
1289 : {
1290 0 : return std::all_of(
1291 0 : str.begin(), str.end(), [](unsigned char c) { return !std::isalpha(c) || std::islower(c); });
1292 : }
1293 : } // MooseUtils namespace
1294 :
1295 : void
1296 76552 : removeSubstring(std::string & main, const std::string & sub)
1297 : {
1298 76552 : std::string::size_type n = sub.length();
1299 76552 : for (std::string::size_type i = main.find(sub); i != std::string::npos; i = main.find(sub))
1300 0 : main.erase(i, n);
1301 76552 : }
1302 :
1303 : std::string
1304 285627 : removeSubstring(const std::string & main, const std::string & sub)
1305 : {
1306 285627 : std::string copy_main = main;
1307 285627 : std::string::size_type n = sub.length();
1308 571254 : for (std::string::size_type i = copy_main.find(sub); i != std::string::npos;
1309 285627 : i = copy_main.find(sub))
1310 285627 : copy_main.erase(i, n);
1311 285627 : return copy_main;
1312 0 : }
|