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