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