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