https://mooseframework.inl.gov
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"
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 pathjoin(const std::filesystem::path & p)
60 {
61  return p;
62 }
63 
64 std::string
66 {
67  auto build_loc = pathjoin(Moose::getExecutablePath(), "run_tests");
68  if (pathExists(build_loc) && checkFileReadable(build_loc))
69  return build_loc;
70  // TODO: maybe no path prefix - just moose_test_runner here?
71  return pathjoin(Moose::getExecutablePath(), "moose_test_runner");
72 }
73 
74 std::string
76 {
77  std::string path = ".";
78  for (int i = 0; i < 5; i++)
79  {
80  auto testroot = pathjoin(path, "testroot");
81  if (pathExists(testroot) && checkFileReadable(testroot))
82  return testroot;
83  path += "/..";
84  }
85  return "";
86 }
87 
88 bool
89 parsesToReal(const std::string & input, Real * parsed_real)
90 {
91  std::istringstream ss(input);
92  Real real_value;
93  if (ss >> real_value && ss.eof())
94  {
95  if (parsed_real)
96  (*parsed_real) = real_value;
97  return true;
98  }
99  return false;
100 }
101 
102 std::string
103 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  pathjoin(Moose::getExecutablePath(), "..", "share", app_name, dir_name);
112 
113  auto test_root = pathjoin(installed_path, "testroot");
114  if (!pathExists(installed_path))
115  mooseError("Couldn't locate any installed inputs to copy in path: ",
116  installed_path,
117  '\n',
118  extra_error_msg);
119 
120  checkFileReadable(test_root);
121  return installed_path;
122 }
123 
124 std::string
125 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  std::string installed_path = pathjoin(Moose::getExecutablePath(), "..", "share", app_name, "doc");
131 
132  auto docfile = pathjoin(installed_path, "css", "moose.css");
133  if (pathExists(docfile) && checkFileReadable(docfile))
134  return installed_path;
135  return "";
136 }
137 
138 std::string
139 mooseDocsURL(const std::string & path)
140 {
141  return "https://mooseframework.inl.gov/" + path;
142 }
143 
144 std::string
145 replaceAll(std::string str, const std::string & from, const std::string & to)
146 {
147  size_t start_pos = 0;
148  while ((start_pos = str.find(from, start_pos)) != std::string::npos)
149  {
150  str.replace(start_pos, from.length(), to);
151  start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
152  }
153  return str;
154 }
155 
156 std::string
157 convertLatestCheckpoint(std::string orig)
158 {
159  auto slash_pos = orig.find_last_of("/");
160  auto path = orig.substr(0, slash_pos);
161  auto file = orig.substr(slash_pos + 1);
162  if (file != "LATEST")
163  return orig;
164 
166 
167  if (converted.empty())
168  mooseError("Unable to find suitable recovery file!");
169 
170  return converted;
171 }
172 
173 // this implementation is copied from
174 // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.2B.2B
175 int
176 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  auto s1len = s1.size();
181  auto s2len = s2.size();
182 
183  auto column_start = (decltype(s1len))1;
184 
185  auto column = new decltype(s1len)[s1len + 1];
186  std::iota(column + column_start, column + s1len + 1, column_start);
187 
188  for (auto x = column_start; x <= s2len; x++)
189  {
190  column[0] = x;
191  auto last_diagonal = x - column_start;
192  for (auto y = column_start; y <= s1len; y++)
193  {
194  auto old_diagonal = column[y];
195  auto possibilities = {
196  column[y] + 1, column[y - 1] + 1, last_diagonal + (s1[y - 1] == s2[x - 1] ? 0 : 1)};
197  column[y] = std::min(possibilities);
198  last_diagonal = old_diagonal;
199  }
200  }
201  auto result = column[s1len];
202  delete[] column;
203  return result;
204 }
205 
206 void
207 escape(std::string & str)
208 {
209  std::map<char, std::string> escapes;
210  escapes['\a'] = "\\a";
211  escapes['\b'] = "\\b";
212  escapes['\f'] = "\\f";
213  escapes['\n'] = "\\n";
214  escapes['\t'] = "\\t";
215  escapes['\v'] = "\\v";
216  escapes['\r'] = "\\r";
217 
218  for (const auto & it : escapes)
219  for (size_t pos = 0; (pos = str.find(it.first, pos)) != std::string::npos;
220  pos += it.second.size())
221  str.replace(pos, 1, it.second);
222 }
223 
224 std::string
225 removeExtraWhitespace(const std::string & input)
226 {
227  return std::regex_replace(input, std::regex("^\\s+|\\s+$|\\s+(?=\\s)"), "");
228 }
229 
230 bool
231 pathContains(const std::string & expression,
232  const std::string & string_to_find,
233  const std::string & delims)
234 {
235  std::vector<std::string> elements;
236  tokenize(expression, elements, 0, delims);
237 
238  std::vector<std::string>::iterator found_it =
239  std::find(elements.begin(), elements.end(), string_to_find);
240  if (found_it != elements.end())
241  return true;
242  else
243  return false;
244 }
245 
246 bool
247 pathExists(const std::string & path)
248 {
249  struct stat buffer;
250  return (stat(path.c_str(), &buffer) == 0);
251 }
252 
253 bool
254 checkFileReadable(const std::string & filename,
255  bool check_line_endings,
256  bool throw_on_unreadable,
257  bool check_for_git_lfs_pointer)
258 {
259  std::ifstream in(filename.c_str(), std::ifstream::in);
260  if (in.fail())
261  {
262  if (throw_on_unreadable)
263  mooseError(
264  (std::string("Unable to open file \"") + filename +
265  std::string("\". Check to make sure that it exists and that you have read permission."))
266  .c_str());
267  else
268  return false;
269  }
270 
271  if (check_line_endings)
272  {
273  std::istream_iterator<char> iter(in);
274  std::istream_iterator<char> eos;
275  in >> std::noskipws;
276  while (iter != eos)
277  if (*iter++ == '\r')
278  mooseError(filename + " contains Windows(DOS) line endings which are not supported.");
279  }
280 
281  if (check_for_git_lfs_pointer && checkForGitLFSPointer(in))
282  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  in.close();
285 
286  return true;
287 }
288 
289 bool
290 checkForGitLFSPointer(std::ifstream & file)
291 {
292  mooseAssert(file.is_open(), "Passed in file handle is not open");
293 
294  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  file.seekg(0);
299  std::getline(file, line);
300  if (line.find("version https://") != std::string::npos)
301  return true;
302  else
303  return false;
304 }
305 
306 bool
307 checkFileWriteable(const std::string & filename, bool throw_on_unwritable)
308 {
309  std::ofstream out(filename.c_str(), std::ios_base::app);
310  if (out.fail())
311  {
312  if (throw_on_unwritable)
313  mooseError(
314  (std::string("Unable to open file \"") + filename +
315  std::string("\". Check to make sure that it exists and that you have write permission."))
316  .c_str());
317  else
318  return false;
319  }
320 
321  out.close();
322 
323  return true;
324 }
325 
326 void
327 parallelBarrierNotify(const Parallel::Communicator & comm, bool messaging)
328 {
329  processor_id_type secondary_processor_id;
330 
331  if (messaging)
332  Moose::out << "Waiting For Other Processors To Finish" << std::endl;
333  if (comm.rank() == 0)
334  {
335  // The primary process is already through, so report it
336  if (messaging)
337  Moose::out << "Jobs complete: 1/" << comm.size() << (1 == comm.size() ? "\n" : "\r")
338  << std::flush;
339  for (unsigned int i = 2; i <= comm.size(); ++i)
340  {
341  comm.receive(MPI_ANY_SOURCE, secondary_processor_id);
342  if (messaging)
343  Moose::out << "Jobs complete: " << i << "/" << comm.size()
344  << (i == comm.size() ? "\n" : "\r") << std::flush;
345  }
346  }
347  else
348  {
349  secondary_processor_id = comm.rank();
350  comm.send(0, secondary_processor_id);
351  }
352 
353  comm.barrier();
354 }
355 
356 void
358 {
359  // unless we are the first processor...
360  if (comm.rank() > 0)
361  {
362  // ...wait for the previous processor to finish
363  int dummy = 0;
364  comm.receive(comm.rank() - 1, dummy);
365  }
366  else if (warn)
367  mooseWarning("Entering serial execution block (use only for debugging)");
368 }
369 
370 void
372 {
373  // unless we are the last processor...
374  if (comm.rank() + 1 < comm.size())
375  {
376  // ...notify the next processor of its turn
377  int dummy = 0;
378  comm.send(comm.rank() + 1, dummy);
379  }
380 
381  comm.barrier();
382  if (comm.rank() == 0 && warn)
383  mooseWarning("Leaving serial execution block (use only for debugging)");
384 }
385 
386 bool
387 hasExtension(const std::string & filename, std::string ext, bool strip_exodus_ext)
388 {
389  // Extract the extension, w/o the '.'
390  std::string file_ext;
391  if (strip_exodus_ext)
392  {
393  pcrecpp::RE re(
394  ".*\\.([^\\.]*?)(?:-s\\d+)?\\s*$"); // capture the complete extension, ignoring -s*
395  re.FullMatch(filename, &file_ext);
396  }
397  else
398  {
399  pcrecpp::RE re(".*\\.([^\\.]*?)\\s*$"); // capture the complete extension
400  re.FullMatch(filename, &file_ext);
401  }
402 
403  // Perform the comparision
404  if (file_ext == ext)
405  return true;
406  else
407  return false;
408 }
409 
410 std::string
411 getExtension(const std::string & filename, const bool rfind)
412 {
413  std::string file_ext = "";
414  if (filename != "")
415  {
416  // The next line splits filename at the last "/" and gives the file name after "/"
417  const std::string stripped_filename = splitFileName<std::string>(filename).second;
418  auto pos = rfind ? stripped_filename.rfind(".") : stripped_filename.find(".");
419  if (pos != std::string::npos)
420  file_ext += stripped_filename.substr(pos + 1, std::string::npos);
421  }
422 
423  return file_ext;
424 }
425 
426 std::string
427 stripExtension(const std::string & s, const bool rfind)
428 {
429  const std::string ext = getExtension(s, rfind);
430  const bool offset = (ext.size() != 0);
431  // -1 offset accounts for the extension's leading dot ("."), if there is an extension
432  return s.substr(0, s.size() - ext.size() - offset);
433 }
434 
435 std::string
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  constexpr unsigned int BUF_SIZE = 1024;
443  char buffer[BUF_SIZE];
444 
445  return getcwd(buffer, BUF_SIZE) != nullptr ? buffer : "";
446 }
447 
448 void
449 makedirs(const std::string & dir_name, bool throw_on_failure)
450 {
451  // split path into directories with delimiter '/'
452  std::vector<std::string> split_dir_names;
453  MooseUtils::tokenize(dir_name, split_dir_names);
454 
455  auto n = split_dir_names.size();
456 
457  // remove '.' and '..' when possible
458  auto i = n;
459  i = 0;
460  while (i != n)
461  {
462  if (split_dir_names[i] == ".")
463  {
464  for (auto j = i + 1; j < n; ++j)
465  split_dir_names[j - 1] = split_dir_names[j];
466  --n;
467  }
468  else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
469  {
470  for (auto j = i + 1; j < n; ++j)
471  split_dir_names[j - 2] = split_dir_names[j];
472  n -= 2;
473  --i;
474  }
475  else
476  ++i;
477  }
478  if (n == 0)
479  return;
480 
481  split_dir_names.resize(n);
482 
483  // start creating directories recursively
484  std::string cur_dir = dir_name[0] == '/' ? "" : ".";
485  for (auto & dir : split_dir_names)
486  {
487  cur_dir += "/" + dir;
488 
489  if (!pathExists(cur_dir))
490  {
491  auto code = Utility::mkdir(cur_dir.c_str());
492  if (code != 0)
493  {
494  std::string msg = "Failed creating directory " + dir_name;
495  if (throw_on_failure)
496  throw std::invalid_argument(msg);
497  else
498  mooseError(msg);
499  }
500  }
501  }
502 }
503 
504 void
505 removedirs(const std::string & dir_name, bool throw_on_failure)
506 {
507  // split path into directories with delimiter '/'
508  std::vector<std::string> split_dir_names;
509  MooseUtils::tokenize(dir_name, split_dir_names);
510 
511  auto n = split_dir_names.size();
512 
513  // remove '.' and '..' when possible
514  auto i = n;
515  i = 0;
516  while (i != n)
517  {
518  if (split_dir_names[i] == ".")
519  {
520  for (auto j = i + 1; j < n; ++j)
521  split_dir_names[j - 1] = split_dir_names[j];
522  --n;
523  }
524  else if (i > 0 && split_dir_names[i] == ".." && split_dir_names[i - 1] != "..")
525  {
526  for (auto j = i + 1; j < n; ++j)
527  split_dir_names[j - 2] = split_dir_names[j];
528  n -= 2;
529  --i;
530  }
531  else
532  ++i;
533  }
534  if (n == 0)
535  return;
536 
537  split_dir_names.resize(n);
538 
539  // start removing directories recursively
540  std::string base_dir = dir_name[0] == '/' ? "" : ".";
541  for (i = n; i > 0; --i)
542  {
543  std::string cur_dir = base_dir;
544  auto j = i;
545  for (j = 0; j < i; ++j)
546  cur_dir += "/" + split_dir_names[j];
547 
548  // listDir should return at least '.' and '..'
549  if (pathExists(cur_dir) && listDir(cur_dir).size() == 2)
550  {
551  auto code = rmdir(cur_dir.c_str());
552  if (code != 0)
553  {
554  std::string msg = "Failed removing directory " + dir_name;
555  if (throw_on_failure)
556  throw std::invalid_argument(msg);
557  else
558  mooseError(msg);
559  }
560  }
561  else
562  // stop removing
563  break;
564  }
565 }
566 
567 std::string
568 camelCaseToUnderscore(const std::string & camel_case_name)
569 {
570  std::string replaced = camel_case_name;
571  // Put underscores in front of each contiguous set of capital letters
572  pcrecpp::RE("(?!^)(?<![A-Z_])([A-Z]+)").GlobalReplace("_\\1", &replaced);
573 
574  // Convert all capital letters to lower case
575  std::transform(replaced.begin(), replaced.end(), replaced.begin(), ::tolower);
576  return replaced;
577 }
578 
579 std::string
580 underscoreToCamelCase(const std::string & underscore_name, bool leading_upper_case)
581 {
582  pcrecpp::StringPiece input(underscore_name);
583  pcrecpp::RE re("([^_]*)(_|$)");
584 
585  std::string result;
586  std::string us, not_us;
587  bool make_upper = leading_upper_case;
588  while (re.Consume(&input, &not_us, &us))
589  {
590  if (not_us.length() > 0)
591  {
592  if (make_upper)
593  {
594  result += std::toupper(not_us[0]);
595  if (not_us.length() > 1)
596  result += not_us.substr(1);
597  }
598  else
599  result += not_us;
600  }
601  if (us == "")
602  break;
603 
604  // Toggle flag so next match is upper cased
605  make_upper = true;
606  }
607 
608  return result;
609 }
610 
611 std::string
612 shortName(const std::string & name)
613 {
614  return name.substr(name.find_last_of('/') != std::string::npos ? name.find_last_of('/') + 1 : 0);
615 }
616 
617 std::string
618 baseName(const std::string & name)
619 {
620  return name.substr(0, name.find_last_of('/') != std::string::npos ? name.find_last_of('/') : 0);
621 }
622 
623 std::string
625 {
626  char hostname[1024];
627  hostname[1023] = '\0';
628 #ifndef __WIN32__
629  if (gethostname(hostname, 1023))
630  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  return hostname;
637 }
638 
639 unsigned short
640 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 
655 
656  if (use_environment)
657  {
658  char * pps_width = std::getenv("MOOSE_PPS_WIDTH");
659  if (pps_width != NULL)
660  {
661  std::stringstream ss(pps_width);
662  ss >> w.ws_col;
663  }
664  }
665  // Default to AUTO if no environment variable was set
667  {
668 #ifndef __WIN32__
669  try
670  {
671  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
682  w.ws_col = 132;
683 
684  return w.ws_col;
685 }
686 
687 void
690 {
691  // Loop through the elements
692  for (const auto & elem_it : props)
693  {
694  Moose::out << "Element " << elem_it.first->id() << '\n';
695 
696  // Loop through the sides
697  for (const auto & side_it : elem_it.second)
698  {
699  Moose::out << " Side " << side_it.first << '\n';
700 
701  // Loop over properties
702  unsigned int cnt = 0;
703  for (const auto & mat_prop : side_it.second)
704  {
705  if (auto mp = dynamic_cast<const MaterialProperty<Real> *>(&mat_prop))
706  {
707  Moose::out << " Property " << cnt << '\n';
708  cnt++;
709 
710  // Loop over quadrature points
711  for (unsigned int qp = 0; qp < mp->size(); ++qp)
712  Moose::out << " prop[" << qp << "] = " << (*mp)[qp] << '\n';
713  }
714  }
715  }
716  }
717 
718  Moose::out << std::flush;
719 }
720 
721 std::string &
722 removeColor(std::string & msg)
723 {
724  pcrecpp::RE re("(\\33\\[3[0-7]m))", pcrecpp::DOTALL());
725  re.GlobalReplace(std::string(""), &msg);
726  return msg;
727 }
728 
729 void
730 addLineBreaks(std::string & message,
731  unsigned int line_width /*= ConsoleUtils::console_line_length*/)
732 {
733  for (auto i : make_range(int(message.length() / line_width)))
734  message.insert((i + 1) * (line_width + 2) - 2, "\n");
735 }
736 
737 void
738 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  std::string colored_message;
750  std::string curr_color = COLOR_DEFAULT; // tracks last color code before newline
751  std::string line, color_code;
752 
753  bool ends_in_newline = message.empty() ? true : message.back() == '\n';
754 
755  bool first = true;
756 
757  std::istringstream iss(message);
758  for (std::string line; std::getline(iss, line);) // loop over each line
759  {
760  const static pcrecpp::RE match_color(".*(\\33\\[3\\dm)((?!\\33\\[3\\d)[^\n])*");
761  pcrecpp::StringPiece line_piece(line);
762  match_color.FindAndConsume(&line_piece, &color_code);
763 
764  if (!first || indent_first_line)
765  colored_message += color + prefix + post_prefix + curr_color;
766 
767  colored_message += line;
768 
769  // Only add a newline to the last line if it had one to begin with!
770  if (!iss.eof() || ends_in_newline)
771  colored_message += "\n";
772 
773  if (!color_code.empty())
774  curr_color = color_code; // remember last color of this line
775 
776  first = false;
777  }
778  message = colored_message;
779 }
780 
781 std::list<std::string>
782 listDir(const std::string path, bool files_only)
783 {
784  std::list<std::string> files;
785 
786  tinydir_dir dir;
787  dir.has_next = 0; // Avoid a garbage value in has_next (clang StaticAnalysis)
788  tinydir_open(&dir, path.c_str());
789 
790  while (dir.has_next)
791  {
792  tinydir_file file;
793  file.is_dir = 0; // Avoid a garbage value in is_dir (clang StaticAnalysis)
794  tinydir_readfile(&dir, &file);
795 
796  if (!files_only || !file.is_dir)
797  files.push_back(path + "/" + file.name);
798 
799  tinydir_next(&dir);
800  }
801 
802  tinydir_close(&dir);
803 
804  return files;
805 }
806 
807 std::list<std::string>
808 getFilesInDirs(const std::list<std::string> & directory_list, const bool files_only /* = true */)
809 {
810  std::list<std::string> files;
811 
812  for (const auto & dir_name : directory_list)
813  files.splice(files.end(), listDir(dir_name, files_only));
814 
815  return files;
816 }
817 
818 std::string
819 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  std::time_t newest_time = 0;
825  std::list<std::string> newest_restart_files;
826 
827  // Loop through all possible files and store the newest
828  for (const auto & cp_file : checkpoint_files)
829  {
830  if (MooseUtils::hasExtension(cp_file, "rd"))
831  {
832  struct stat stats;
833  stat(cp_file.c_str(), &stats);
834 
835  std::time_t mod_time = stats.st_mtime;
836  if (mod_time > newest_time)
837  {
838  newest_restart_files.clear(); // If the modification time is greater, clear the list
839  newest_time = mod_time;
840  }
841 
842  if (mod_time == newest_time)
843  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  int max_file_num = -1;
849  std::string max_file;
850  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  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  for (const auto & res_file : newest_restart_files)
860  {
861  int file_num = 0;
862 
863  // All of the file up to and including the digits
864  std::string file_prefix;
865 
866  re_file_num.FullMatch(res_file, &file_prefix, &file_num);
867 
868  if (file_num > max_file_num)
869  {
870  // Need both the header and the data
871  if (!RestartableDataReader::isAvailable(res_file))
872  continue;
873 
874  max_file_num = file_num;
875  max_file = res_file;
876  max_prefix = file_prefix;
877  }
878  }
879 
880  // Error if nothing was located
881  if (max_file_num == -1)
882  mooseError("No checkpoint file found!");
883 
884  return max_prefix;
885 }
886 
887 bool
888 wildCardMatch(std::string name, std::string search_string)
889 {
890  // Assume that an empty string matches anything
891  if (search_string == "")
892  return true;
893 
894  // transform to lower for case insenstive matching
895  std::transform(name.begin(), name.end(), name.begin(), (int (*)(int))std::toupper);
896  std::transform(search_string.begin(),
897  search_string.end(),
898  search_string.begin(),
899  (int (*)(int))std::toupper);
900 
901  // exact match!
902  if (search_string.find("*") == std::string::npos)
903  return search_string == name;
904 
905  // wildcard
906  std::vector<std::string> tokens;
907  MooseUtils::tokenize(search_string, tokens, 1, "*");
908 
909  size_t pos = 0;
910  for (unsigned int i = 0; i < tokens.size() && pos != std::string::npos; ++i)
911  {
912  pos = name.find(tokens[i], pos);
913  // See if we have a leading wildcard
914  if (search_string[0] != '*' && i == 0 && pos != 0)
915  return false;
916  }
917 
918  if (pos != std::string::npos && tokens.size() > 0)
919  {
920  // Now see if we have a trailing wildcard
921  size_t last_token_length = tokens.back().length();
922  if (*search_string.rbegin() == '*' || pos == name.size() - last_token_length)
923  return true;
924  else
925  return false;
926  }
927  else
928  return false;
929 }
930 
931 bool
932 globCompare(const std::string & candidate,
933  const std::string & pattern,
934  std::size_t c,
935  std::size_t p)
936 {
937  if (p == pattern.size())
938  return c == candidate.size();
939 
940  if (pattern[p] == '*')
941  {
942  for (; c < candidate.size(); ++c)
943  if (globCompare(candidate, pattern, c, p + 1))
944  return true;
945  return globCompare(candidate, pattern, c, p + 1);
946  }
947 
948  if (pattern[p] != '?' && pattern[p] != candidate[c])
949  return false;
950 
951  return globCompare(candidate, pattern, c + 1, p + 1);
952 }
953 
954 std::string
955 stringJoin(const std::vector<std::string> & values, const std::string & separator)
956 {
957  std::string combined;
958  for (const auto & value : values)
959  combined += value + separator;
960  if (values.size())
961  combined = combined.substr(0, combined.size() - separator.size());
962  return combined;
963 }
964 
965 bool
966 beginsWith(const std::string & value, const std::string & begin_value)
967 {
968  return value.rfind(begin_value, 0) == 0;
969 }
970 
973 {
975 }
976 
977 int
978 stringToInteger(const std::string & input, bool throw_on_failure)
979 {
980  return convert<int>(input, throw_on_failure);
981 }
982 
983 void
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 
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 
1030 std::vector<std::string>
1031 split(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 
1050 std::vector<std::string>
1051 rsplit(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 
1070 void
1071 createSymlink(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 
1083 void
1084 clearSymlink(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 
1105 std::size_t
1106 fileSize(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 
1135 std::string
1136 realpath(const std::string & path)
1137 {
1138  return std::filesystem::absolute(path);
1139 }
1140 
1141 BoundingBox
1142 buildBoundingBox(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 
1150 std::string
1151 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  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  return s;
1168 }
1169 
1170 std::string
1171 canonicalPath(const std::string & path)
1172 {
1173  return std::filesystem::weakly_canonical(path).c_str();
1174 }
1175 
1176 bool
1177 startsWith(const std::string & string1, const std::string & string2)
1178 {
1179  if (string2.size() > string1.size())
1180  return false;
1181  return string1.compare(0, string2.size(), string2) == 0;
1182 }
1183 
1184 void
1185 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  string1.replace(0, string2.size(), string3);
1190 }
1191 
1192 bool
1193 isAllLowercase(const std::string & str)
1194 {
1195  return std::all_of(
1196  str.begin(), str.end(), [](unsigned char c) { return !std::isalpha(c) || std::islower(c); });
1197 }
1198 } // MooseUtils namespace
1199 
1200 void
1201 removeSubstring(std::string & main, const std::string & sub)
1202 {
1203  std::string::size_type n = sub.length();
1204  for (std::string::size_type i = main.find(sub); i != std::string::npos; i = main.find(sub))
1205  main.erase(i, n);
1206 }
1207 
1208 std::string
1209 removeSubstring(const std::string & main, const std::string & sub)
1210 {
1211  std::string copy_main = main;
1212  std::string::size_type n = sub.length();
1213  for (std::string::size_type i = copy_main.find(sub); i != std::string::npos;
1214  i = copy_main.find(sub))
1215  copy_main.erase(i, n);
1216  return copy_main;
1217 }
std::string name(const ElemQuality q)
OStreamProxy err
std::string docsDir(const std::string &app_name)
Returns the directory of any installed docs/site.
Definition: MooseUtils.C:125
bool globCompare(const std::string &candidate, const std::string &pattern, std::size_t c=0, std::size_t p=0)
Definition: MooseUtils.C:932
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:30
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:371
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 ...
bool beginsWith(const std::string &value, const std::string &begin_value)
Definition: MooseUtils.C:966
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:978
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
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:688
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:103
std::string getExecutablePath()
Gets the directory the running executable is on Mac OS X and linux.
bool parsesToReal(const std::string &input, Real *parsed_real=nullptr)
Check if the input string can be parsed into a Real.
Definition: MooseUtils.C:89
bool isAllLowercase(const std::string &str)
Definition: MooseUtils.C:1193
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:357
bool startsWith(const std::string &string1, const std::string &string2)
Definition: MooseUtils.C:1177
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:808
processor_id_type rank() const
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:505
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:984
bool checkForGitLFSPointer(std::ifstream &file)
Check if the file is a Git-LFS pointer.
Definition: MooseUtils.C:290
std::string realpath(const std::string &path)
Wrapper around PetscGetRealPath, which is a cross-platform replacement for realpath.
Definition: MooseUtils.C:1136
static ExecFlagRegistry & getExecFlagRegistry()
Return Singleton instance.
std::string convertLatestCheckpoint(std::string orig)
Replaces "LATEST" placeholders with the latest checkpoint file name.
Definition: MooseUtils.C:157
std::string mooseDocsURL(const std::string &path)
Returns the URL of a page located on the MOOSE documentation site.
Definition: MooseUtils.C:139
std::string hostname()
Get the hostname the current process is running on.
Definition: MooseUtils.C:624
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:568
std::string shortName(const std::string &name)
Function for stripping name after the file / in parser block.
Definition: MooseUtils.C:612
void removeSubstring(std::string &main, const std::string &sub)
find, erase, length algorithm for removing a substring from a string
Definition: MooseUtils.C:1201
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:1031
ExecFlagEnum getDefaultExecFlagEnum()
Return the default ExecFlagEnum for MOOSE.
Definition: MooseUtils.C:972
std::string getExtension(const std::string &filename, const bool rfind=false)
Gets the extension of the passed file name.
Definition: MooseUtils.C:411
void replaceStart(std::string &string1, const std::string &string2, const std::string &string3)
Replace the starting string string2 of string1 with string3.
Definition: MooseUtils.C:1185
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:1051
uint8_t processor_id_type
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
std::string stripExtension(const std::string &s, const bool rfind=false)
Removes any file extension from the given string s (i.e.
Definition: MooseUtils.C:427
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
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:738
void parallelBarrierNotify(const libMesh::Parallel::Communicator &comm, bool messaging=true)
This function implements a parallel barrier function but writes progress to stdout.
Definition: MooseUtils.C:327
std::string getLatestCheckpointFilePrefix(const std::list< std::string > &checkpoint_files)
Returns the most recent checkpoint prefix (the four numbers at the beginning) If a suitable file isn&#39;...
Definition: MooseUtils.C:819
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:357
std::string canonicalPath(const std::string &path)
Gets the canonical path of the given path.
Definition: MooseUtils.C:1171
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:254
std::string runTestsExecutable()
Returns the location of either a local repo run_tests script - or an installed test executor script i...
Definition: MooseUtils.C:65
std::size_t fileSize(const std::string &filename)
Check the file size.
Definition: MooseUtils.C:1106
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:580
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:387
std::string & removeColor(std::string &msg)
remove ANSI escape sequences for terminal color from msg
Definition: MooseUtils.C:722
bool checkFileWriteable(const std::string &filename, bool throw_on_unwritable=true)
Check if the file is writable (path exists and permissions)
Definition: MooseUtils.C:307
void addLineBreaks(std::string &message, unsigned int line_width)
Definition: MooseUtils.C:730
int main(int argc, char *argv[])
Initialize, create and run a MooseApp.
Definition: MooseMain.h:31
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:1084
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:1010
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:1071
std::filesystem::path pathjoin(const std::filesystem::path &p)
Definition: MooseUtils.C:59
std::string baseName(const std::string &name)
Function for string the information before the final / in a parser block.
Definition: MooseUtils.C:618
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool wildCardMatch(std::string name, std::string search_string)
Definition: MooseUtils.C:888
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:782
libMesh::BoundingBox buildBoundingBox(const Point &p1, const Point &p2)
Construct a valid bounding box from 2 arbitrary points.
Definition: MooseUtils.C:1142
int levenshteinDist(const std::string &s1, const std::string &s2)
Computes and returns the Levenshtein distance between strings s1 and s2.
Definition: MooseUtils.C:176
std::string getCurrentWorkingDir()
Returns the current working directory as a string.
Definition: MooseUtils.C:436
void makedirs(const std::string &dir_name, bool throw_on_failure=false)
Recursively make directories.
Definition: MooseUtils.C:449
std::string removeExtraWhitespace(const std::string &str)
Removes additional whitespace from a string.
Definition: MooseUtils.C:225
void union_with(const Point &p)
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:231
bool pathExists(const std::string &path)
Definition: MooseUtils.C:247
std::string replaceAll(std::string str, const std::string &from, const std::string &to)
Replaces all occurrences of from in str with to and returns the result.
Definition: MooseUtils.C:145
auto min(const L &left, const R &right)
std::string stringJoin(const std::vector< std::string > &values, const std::string &separator=" ")
Concatenates value into a single string separated by separator.
Definition: MooseUtils.C:955
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:207
std::string prettyCppType(const std::string &cpp_type)
Definition: MooseUtils.C:1151
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:75
unsigned short getTermWidth(bool use_environment)
Returns the width of the terminal using sys/ioctl.
Definition: MooseUtils.C:640
static bool isAvailable(const std::filesystem::path &folder_base)