Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #ifdef HAVE_GPERFTOOLS
11 : #include "gperftools/profiler.h"
12 : #include "gperftools/heap-profiler.h"
13 : #endif
14 :
15 : // MOOSE includes
16 : #include "MooseRevision.h"
17 : #include "AppFactory.h"
18 : #include "DisplacedProblem.h"
19 : #include "NonlinearSystemBase.h"
20 : #include "AuxiliarySystem.h"
21 : #include "MooseSyntax.h"
22 : #include "MooseInit.h"
23 : #include "Executioner.h"
24 : #include "Executor.h"
25 : #include "PetscSupport.h"
26 : #include "Conversion.h"
27 : #include "CommandLine.h"
28 : #include "InfixIterator.h"
29 : #include "MultiApp.h"
30 : #include "MooseUtils.h"
31 : #include "MooseObjectAction.h"
32 : #include "InputParameterWarehouse.h"
33 : #include "SystemInfo.h"
34 : #include "MooseMesh.h"
35 : #include "FileOutput.h"
36 : #include "ConsoleUtils.h"
37 : #include "JsonSyntaxTree.h"
38 : #include "JsonInputFileFormatter.h"
39 : #include "SONDefinitionFormatter.h"
40 : #include "RelationshipManager.h"
41 : #include "ProxyRelationshipManager.h"
42 : #include "Registry.h"
43 : #include "SerializerGuard.h"
44 : #include "PerfGraphInterface.h" // For TIME_SECTION
45 : #include "SolutionInvalidInterface.h"
46 : #include "Attributes.h"
47 : #include "MooseApp.h"
48 : #include "CommonOutputAction.h"
49 : #include "CastUniquePointer.h"
50 : #include "NullExecutor.h"
51 : #include "ExecFlagRegistry.h"
52 : #include "SolutionInvalidity.h"
53 : #include "MooseServer.h"
54 : #include "RestartableDataWriter.h"
55 : #include "StringInputStream.h"
56 : #include "MooseMain.h"
57 : #include "FEProblemBase.h"
58 :
59 : // Regular expression includes
60 : #include "pcrecpp.h"
61 :
62 : #include "libmesh/exodusII_io.h"
63 : #include "libmesh/mesh_refinement.h"
64 : #include "libmesh/string_to_enum.h"
65 : #include "libmesh/checkpoint_io.h"
66 : #include "libmesh/mesh_base.h"
67 : #include "libmesh/petsc_solver_exception.h"
68 :
69 : // System include for dynamic library methods
70 : #ifdef LIBMESH_HAVE_DLOPEN
71 : #include <dlfcn.h>
72 : #include <sys/utsname.h> // utsname
73 : #endif
74 :
75 : #ifdef LIBTORCH_ENABLED
76 : #include <torch/version.h>
77 : #endif
78 :
79 : // C++ includes
80 : #include <numeric> // std::accumulate
81 : #include <fstream>
82 : #include <sys/types.h>
83 : #include <unistd.h>
84 : #include <cstdlib> // for system()
85 : #include <chrono>
86 : #include <thread>
87 : #include <filesystem>
88 :
89 : using namespace libMesh;
90 :
91 : #define QUOTE(macro) stringifyName(macro)
92 :
93 : void
94 176895 : MooseApp::addAppParam(InputParameters & params)
95 : {
96 176895 : params.addCommandLineParam<std::string>(
97 : "app_to_run", "--app <type>", "Specify the application type to run (case-sensitive)");
98 176895 : }
99 :
100 : void
101 114143 : MooseApp::addInputParam(InputParameters & params)
102 : {
103 114143 : params.addCommandLineParam<std::vector<std::string>>(
104 : "input_file", "-i <input file(s)>", "Specify input file(s); multiple files are merged");
105 114143 : }
106 :
107 : InputParameters
108 62752 : MooseApp::validParams()
109 : {
110 62752 : InputParameters params = emptyInputParameters();
111 :
112 62752 : MooseApp::addAppParam(params);
113 62752 : MooseApp::addInputParam(params);
114 :
115 62752 : params.addCommandLineParam<bool>("display_version", "-v --version", "Print application version");
116 :
117 62752 : params.addOptionalValuedCommandLineParam<std::string>(
118 : "mesh_only",
119 : "--mesh-only <optional path>",
120 : "",
121 : "Build and output the mesh only (Default: \"<input_file_name>_in.e\")");
122 :
123 62752 : params.addCommandLineParam<bool>(
124 : "show_input", "--show-input", "Shows the parsed input file before running the simulation");
125 62752 : params.setGlobalCommandLineParam("show_input");
126 62752 : params.addCommandLineParam<bool>(
127 : "show_outputs", "--show-outputs", "Shows the output execution time information");
128 62752 : params.setGlobalCommandLineParam("show_outputs");
129 62752 : params.addCommandLineParam<bool>(
130 : "show_controls", "--show-controls", "Shows the Control logic available and executed");
131 62752 : params.setGlobalCommandLineParam("show_controls");
132 :
133 62752 : params.addCommandLineParam<bool>(
134 : "no_color", "--no-color", "Disable coloring of all Console outputs");
135 62752 : params.setGlobalCommandLineParam("no_color");
136 :
137 62752 : MooseEnum colors("auto on off", "on");
138 62752 : params.addCommandLineParam<MooseEnum>(
139 : "color", "--color <auto,on,off=on>", colors, "Whether to use color in console output");
140 62752 : params.setGlobalCommandLineParam("color");
141 :
142 62752 : params.addCommandLineParam<bool>("help", "-h --help", "Displays CLI usage statement");
143 62752 : params.addCommandLineParam<bool>(
144 : "minimal",
145 : "--minimal",
146 : "Ignore input file and build a minimal application with Transient executioner");
147 :
148 62752 : params.addCommandLineParam<bool>(
149 : "language_server",
150 : "--language-server",
151 : "Starts a process to communicate with development tools using the language server protocol");
152 :
153 62752 : params.addCommandLineParam<bool>(
154 : "definition", "--definition", "Shows a SON style input definition dump for input validation");
155 62752 : params.addCommandLineParam<bool>("dump", "--dump", "Shows a dump of available input file syntax");
156 62752 : params.addCommandLineParam<std::string>(
157 : "dump_search",
158 : "--dump-search <search>",
159 : "Shows a dump of available input syntax matching a search");
160 62752 : params.addCommandLineParam<bool>("registry", "--registry", "Lists all known objects and actions");
161 62752 : params.addCommandLineParam<bool>(
162 : "registry_hit", "--registry-hit", "Lists all known objects and actions in hit format");
163 62752 : params.addCommandLineParam<bool>(
164 : "use_executor", "--executor", "Use the new Executor system instead of Executioners");
165 :
166 62752 : params.addCommandLineParam<bool>(
167 : "show_type", "--show-type", "Return the name of the application object");
168 62752 : params.addCommandLineParam<bool>("yaml", "--yaml", "Dumps all input file syntax in YAML format");
169 62752 : params.addCommandLineParam<std::string>(
170 : "yaml_search", "--yaml-search", "Dumps input file syntax matching a search in YAML format");
171 62752 : params.addCommandLineParam<bool>("json", "--json", "Dumps all input file syntax in JSON format");
172 62752 : params.addCommandLineParam<std::string>(
173 : "json_search", "--json-search", "Dumps input file syntax matching a search in JSON format");
174 62752 : params.addCommandLineParam<bool>(
175 : "syntax", "--syntax", "Dumps the associated Action syntax paths ONLY");
176 62752 : params.addCommandLineParam<bool>(
177 : "show_docs", "--docs", "Print url/path to the documentation website");
178 62752 : params.addCommandLineParam<bool>(
179 : "show_capabilities", "--show-capabilities", "Dumps the capability registry in JSON format.");
180 62752 : params.addCommandLineParam<std::string>(
181 : "required_capabilities",
182 : "--required-capabilities",
183 : "A list of conditions that is checked against the registered capabilities (see "
184 : "--show-capabilities). The executable will terminate early if the conditions are not met.");
185 62752 : params.addCommandLineParam<std::string>(
186 : "check_capabilities",
187 : "--check-capabilities",
188 : "A list of conditions that is checked against the registered capabilities. Will exit based "
189 : "on whether or not the capaiblities are fulfilled. Does not check dynamically loaded apps.");
190 62752 : params.addCommandLineParam<bool>("check_input",
191 : "--check-input",
192 : "Check the input file (i.e. requires -i <filename>) and quit");
193 62752 : params.setGlobalCommandLineParam("check_input");
194 62752 : params.addCommandLineParam<bool>(
195 : "show_inputs",
196 : "--show-copyable-inputs",
197 : "Shows the directories able to be copied into a user-writable location");
198 :
199 62752 : params.addCommandLineParam<std::string>(
200 : "copy_inputs",
201 : "--copy-inputs <dir>",
202 : "Copies installed inputs (e.g. tests, examples, etc.) to a directory <appname>_<dir>");
203 : // TODO: Should this remain a bool? It can't be a regular argument because it contains
204 : // values that have dashes in it, so it'll get treated as another arg
205 62752 : params.addOptionalValuedCommandLineParam<std::string>(
206 : "run",
207 : "--run <test harness args>",
208 : "",
209 : "Runs the inputs in the current directory copied to a "
210 : "user-writable location by \"--copy-inputs\"");
211 :
212 62752 : params.addCommandLineParam<bool>(
213 : "list_constructed_objects",
214 : "--list-constructed-objects",
215 : "List all moose object type names constructed by the master app factory");
216 :
217 62752 : params.addCommandLineParam<unsigned int>(
218 : "n_threads", "--n-threads=<n>", "Runs the specified number of threads per process");
219 : // This probably shouldn't be global, but the implications of removing this are currently
220 : // unknown and we need to manage it with libmesh better
221 62752 : params.setGlobalCommandLineParam("n_threads");
222 :
223 62752 : params.addCommandLineParam<bool>("allow_unused",
224 : "-w --allow-unused",
225 : "Warn about unused input file options instead of erroring");
226 62752 : params.setGlobalCommandLineParam("allow_unused");
227 62752 : params.addCommandLineParam<bool>(
228 : "error_unused", "-e --error-unused", "Error when encountering unused input file options");
229 62752 : params.setGlobalCommandLineParam("error_unused");
230 62752 : params.addCommandLineParam<bool>(
231 : "error_override",
232 : "-o --error-override",
233 : "Error when encountering overridden or parameters supplied multiple times");
234 62752 : params.setGlobalCommandLineParam("error_override");
235 62752 : params.addCommandLineParam<bool>(
236 : "error_deprecated", "--error-deprecated", "Turn deprecated code messages into Errors");
237 62752 : params.setGlobalCommandLineParam("error_deprecated");
238 :
239 62752 : params.addCommandLineParam<bool>("distributed_mesh",
240 : "--distributed-mesh",
241 : "Forces the use of a distributed finite element mesh");
242 : // Would prefer that this parameter isn't global, but we rely on it too much
243 : // in tests to be able to go back on that decision now
244 62752 : params.setGlobalCommandLineParam("distributed_mesh");
245 :
246 62752 : params.addCommandLineParam<std::string>(
247 : "split_mesh",
248 : "--split-mesh <splits>",
249 : "Comma-separated list of numbers of chunks to split the mesh into");
250 :
251 : // TODO: remove the logic now that this is global
252 62752 : params.addCommandLineParam<std::string>(
253 : "split_file", "--split-file <filename>", "Name of split mesh file(s) to write/read");
254 :
255 62752 : params.addCommandLineParam<bool>("use_split", "--use-split", "Use split distributed mesh files");
256 :
257 62752 : params.addCommandLineParam<unsigned int>(
258 : "refinements", "-r <num refinements>", "Specify additional initial uniform mesh refinements");
259 :
260 62752 : params.addOptionalValuedCommandLineParam<std::string>(
261 : "recover",
262 : "--recover <optional file base>",
263 : "",
264 : "Continue the calculation. Without <file base>, the most recent recovery file will be used");
265 62752 : params.setGlobalCommandLineParam("recover");
266 62752 : params.addCommandLineParam<bool>(
267 : "force_restart",
268 : "--force-restart",
269 : "Forcefully load checkpoints despite possible incompatibilities");
270 62752 : params.setGlobalCommandLineParam("force_restart");
271 :
272 188256 : params.addCommandLineParam<bool>("suppress_header",
273 : "--suppress-header",
274 125504 : false,
275 : "Disables the output of the application header.");
276 62752 : params.setGlobalCommandLineParam("suppress_header");
277 :
278 62752 : params.addCommandLineParam<bool>(
279 : "test_checkpoint_half_transient",
280 : "--test-checkpoint-half-transient",
281 : "Run half of a transient with checkpoints enabled; used by the TestHarness");
282 62752 : params.setGlobalCommandLineParam("test_checkpoint_half_transient");
283 :
284 62752 : params.addCommandLineParam<bool>(
285 : "trap_fpe",
286 : "--trap-fpe",
287 : "Enable floating point exception handling in critical sections of code"
288 : #ifdef DEBUG
289 : " (automatic due to debug build)"
290 : #endif
291 : );
292 62752 : params.setGlobalCommandLineParam("trap_fpe");
293 :
294 62752 : params.addCommandLineParam<bool>(
295 : "no_trap_fpe",
296 : "--no-trap-fpe",
297 : "Disable floating point exception handling in critical sections of code"
298 : #ifndef DEBUG
299 : " (unused due to non-debug build)"
300 : #endif
301 : );
302 :
303 62752 : params.setGlobalCommandLineParam("no_trap_fpe");
304 :
305 62752 : params.addCommandLineParam<bool>(
306 : "no_gdb_backtrace", "--no-gdb-backtrace", "Disables gdb backtraces.");
307 62752 : params.setGlobalCommandLineParam("no_gdb_backtrace");
308 :
309 62752 : params.addCommandLineParam<bool>("error", "--error", "Turn all warnings into errors");
310 62752 : params.setGlobalCommandLineParam("error");
311 :
312 62752 : params.addCommandLineParam<bool>("timing",
313 : "-t --timing",
314 : "Enable all performance logging for timing; disables screen "
315 : "output of performance logs for all Console objects");
316 62752 : params.setGlobalCommandLineParam("timing");
317 62752 : params.addCommandLineParam<bool>(
318 : "no_timing", "--no-timing", "Disabled performance logging; overrides -t or --timing");
319 62752 : params.setGlobalCommandLineParam("no_timing");
320 :
321 62752 : params.addCommandLineParam<bool>(
322 : "allow_test_objects", "--allow-test-objects", "Register test objects and syntax");
323 62752 : params.setGlobalCommandLineParam("allow_test_objects");
324 :
325 : // Options ignored by MOOSE but picked up by libMesh, these are here so that they are displayed in
326 : // the application help
327 62752 : params.addCommandLineParam<bool>(
328 : "keep_cout",
329 : "--keep-cout",
330 : "Keep standard output from all processors when running in parallel");
331 62752 : params.setGlobalCommandLineParam("keep_cout");
332 62752 : params.addCommandLineParam<bool>(
333 : "redirect_stdout",
334 : "--redirect-stdout",
335 : "Keep standard output from all processors when running in parallel");
336 62752 : params.setGlobalCommandLineParam("redirect_stdout");
337 :
338 62752 : params.addCommandLineParam<std::string>(
339 : "timpi_sync",
340 : "--timpi-sync <type=nbx>",
341 : "nbx",
342 : "Changes the sync type used in spare parallel communitations within TIMPI");
343 62752 : params.setGlobalCommandLineParam("timpi_sync");
344 :
345 : // Options for debugging
346 62752 : params.addCommandLineParam<std::string>("start_in_debugger",
347 : "--start-in-debugger <debugger>",
348 : "Start the application and attach a debugger; this will "
349 : "launch xterm windows using <debugger>");
350 :
351 62752 : params.addCommandLineParam<unsigned int>(
352 : "stop_for_debugger",
353 : "--stop-for-debugger <seconds>",
354 : "Pauses the application during startup for <seconds> to allow for connection of debuggers");
355 :
356 62752 : params.addCommandLineParam<bool>(
357 : "perf_graph_live_all", "--perf-graph-live-all", "Forces printing of ALL progress messages");
358 62752 : params.setGlobalCommandLineParam("perf_graph_live_all");
359 :
360 62752 : params.addCommandLineParam<bool>(
361 : "disable_perf_graph_live", "--disable-perf-graph-live", "Disables PerfGraph live printing");
362 62752 : params.setGlobalCommandLineParam("disable_perf_graph_live");
363 :
364 188256 : params.addParam<bool>(
365 125504 : "automatic_automatic_scaling", false, "Whether to turn on automatic scaling by default");
366 :
367 62752 : MooseEnum libtorch_device_type("cpu cuda mps", "cpu");
368 62752 : params.addCommandLineParam<MooseEnum>("libtorch_device",
369 : "--libtorch-device",
370 : libtorch_device_type,
371 : "The device type we want to run libtorch on.");
372 :
373 : #ifdef HAVE_GPERFTOOLS
374 : params.addCommandLineParam<std::string>(
375 : "gperf_profiler_on",
376 : "--gperf-profiler-on <ranks>",
377 : "To generate profiling report only on comma-separated list of MPI ranks");
378 : #endif
379 :
380 188256 : params.addCommandLineParam<bool>(
381 : "show_data_params",
382 : "--show-data-params",
383 125504 : false,
384 : "Show found paths for all DataFileName parameters in the header");
385 188256 : params.addCommandLineParam<bool>("show_data_paths",
386 : "--show-data-paths",
387 125504 : false,
388 : "Show registered data paths for searching in the header");
389 :
390 62752 : params.addPrivateParam<std::string>("_app_name"); // the name passed to AppFactory::create
391 62752 : params.addPrivateParam<std::string>("_type");
392 62752 : params.addPrivateParam<int>("_argc");
393 62752 : params.addPrivateParam<char **>("_argv");
394 62752 : params.addPrivateParam<std::shared_ptr<CommandLine>>("_command_line");
395 62752 : params.addPrivateParam<std::shared_ptr<Parallel::Communicator>>("_comm");
396 62752 : params.addPrivateParam<unsigned int>("_multiapp_level");
397 62752 : params.addPrivateParam<unsigned int>("_multiapp_number");
398 62752 : params.addPrivateParam<bool>("_use_master_mesh", false);
399 62752 : params.addPrivateParam<const MooseMesh *>("_master_mesh");
400 62752 : params.addPrivateParam<const MooseMesh *>("_master_displaced_mesh");
401 62752 : params.addPrivateParam<std::unique_ptr<Backup> *>("_initial_backup", nullptr);
402 62752 : params.addPrivateParam<std::shared_ptr<Parser>>("_parser");
403 :
404 188256 : params.addParam<bool>(
405 : "use_legacy_material_output",
406 125504 : true,
407 : "Set false to allow material properties to be output on INITIAL, not just TIMESTEP_END.");
408 188256 : params.addParam<bool>(
409 : "use_legacy_initial_residual_evaluation_behavior",
410 125504 : true,
411 : "The legacy behavior performs an often times redundant residual evaluation before the "
412 : "solution modifying objects are executed prior to the initial (0th nonlinear iteration) "
413 : "residual evaluation. The new behavior skips that redundant residual evaluation unless the "
414 : "parameter Executioner/use_pre_SMO_residual is set to true.");
415 :
416 125504 : params.addParam<bool>(
417 : MeshGeneratorSystem::allow_data_driven_param,
418 62752 : false,
419 : "Set true to enable data-driven mesh generation, which is an experimental feature");
420 :
421 62752 : params.addCommandLineParam<bool>(
422 : "parse_neml2_only",
423 : "--parse-neml2-only",
424 : "Executes the [NEML2] block to parse the input file and terminate.");
425 :
426 62752 : MooseApp::addAppParam(params);
427 :
428 125504 : return params;
429 62752 : }
430 :
431 62755 : MooseApp::MooseApp(const InputParameters & parameters)
432 : : ConsoleStreamInterface(*this),
433 : PerfGraphInterface(*this, "MooseApp"),
434 62755 : ParallelObject(*parameters.get<std::shared_ptr<Parallel::Communicator>>(
435 62755 : "_comm")), // Can't call getParam() before pars is set
436 : // The use of AppFactory::getAppParams() is atrocious. However, a long time ago
437 : // we decided to copy construct parameters in each derived application...
438 : // which means that the "parameters" we get if someone derives from MooseApp are
439 : // actually a copy of the ones built by the factory. Because we have unique
440 : // application names, this allows us to reference (using _pars and MooseBase)
441 : // the actual const parameters that the AppFactory made for this application
442 62755 : MooseBase(AppFactory::instance().getAppParams(parameters).get<std::string>("_type"),
443 62755 : AppFactory::instance().getAppParams(parameters).get<std::string>("_app_name"),
444 : *this,
445 125510 : AppFactory::instance().getAppParams(parameters)),
446 62755 : _pars(AppFactory::instance().getAppParams(parameters)),
447 62755 : _comm(getParam<std::shared_ptr<Parallel::Communicator>>("_comm")),
448 62755 : _file_base_set_by_user(false),
449 62755 : _output_position_set(false),
450 62755 : _start_time_set(false),
451 62755 : _start_time(0.0),
452 62755 : _global_time_offset(0.0),
453 62755 : _input_parameter_warehouse(std::make_unique<InputParameterWarehouse>()),
454 62755 : _action_factory(*this),
455 62755 : _action_warehouse(*this, _syntax, _action_factory),
456 62755 : _output_warehouse(*this),
457 62755 : _parser(_pars.get<std::shared_ptr<Parser>>("_parser")),
458 62755 : _builder(*this, _action_warehouse, _parser),
459 62755 : _restartable_data(libMesh::n_threads()),
460 62755 : _perf_graph(createRecoverablePerfGraph()),
461 62755 : _solution_invalidity(createRecoverableSolutionInvalidity()),
462 62755 : _rank_map(*_comm, _perf_graph),
463 62755 : _use_executor(_pars.get<bool>("use_executor")),
464 62755 : _null_executor(NULL),
465 62755 : _use_nonlinear(true),
466 62755 : _use_eigen_value(false),
467 62755 : _enable_unused_check(ERROR_UNUSED),
468 62755 : _factory(*this),
469 62755 : _error_overridden(false),
470 62755 : _early_exit_param(""),
471 62755 : _ready_to_exit(false),
472 62755 : _exit_code(0),
473 62755 : _initial_from_file(false),
474 62755 : _distributed_mesh_on_command_line(false),
475 62755 : _recover(false),
476 62755 : _restart(false),
477 62755 : _split_mesh(false),
478 62755 : _use_split(_pars.get<bool>("use_split")),
479 62755 : _force_restart(_pars.get<bool>("force_restart")),
480 : #ifdef DEBUG
481 : _trap_fpe(true),
482 : #else
483 62755 : _trap_fpe(false),
484 : #endif
485 62755 : _test_checkpoint_half_transient(false),
486 62755 : _check_input(getParam<bool>("check_input")),
487 62755 : _multiapp_level(isParamValid("_multiapp_level") ? _pars.get<unsigned int>("_multiapp_level")
488 : : 0),
489 62755 : _multiapp_number(isParamValid("_multiapp_number") ? _pars.get<unsigned int>("_multiapp_number")
490 : : 0),
491 62755 : _use_master_mesh(_pars.get<bool>("_use_master_mesh")),
492 62755 : _master_mesh(isParamValid("_master_mesh") ? _pars.get<const MooseMesh *>("_master_mesh")
493 : : nullptr),
494 125510 : _master_displaced_mesh(isParamValid("_master_displaced_mesh")
495 62755 : ? _pars.get<const MooseMesh *>("_master_displaced_mesh")
496 : : nullptr),
497 62755 : _mesh_generator_system(*this),
498 62755 : _chain_control_system(*this),
499 62755 : _rd_reader(*this, _restartable_data, forceRestart()),
500 62755 : _execute_flags(moose::internal::ExecFlagRegistry::getExecFlagRegistry().getFlags()),
501 62755 : _output_buffer_cache(nullptr),
502 62755 : _automatic_automatic_scaling(getParam<bool>("automatic_automatic_scaling")),
503 676192 : _initial_backup(getParam<std::unique_ptr<Backup> *>("_initial_backup"))
504 : #ifdef LIBTORCH_ENABLED
505 : ,
506 90844 : _libtorch_device(determineLibtorchDeviceType(getParam<MooseEnum>("libtorch_device")))
507 : #endif
508 : {
509 62755 : if (¶meters != &_pars)
510 : {
511 1 : const auto show_trace = Moose::show_trace;
512 1 : Moose::show_trace = false;
513 1 : const std::string bad_params = "(InputParameters parameters)";
514 1 : const std::string good_params = "(const InputParameters & parameters)";
515 1 : const std::string source_constructor = type() + "::" + type();
516 1 : mooseDoOnce(mooseDeprecated(type(),
517 : " copy-constructs its input parameters.\n\n",
518 : "This is deprecated and will not be allowed in the future.\n\n",
519 : "In ",
520 : type(),
521 : ".C, change:\n ",
522 : source_constructor,
523 : bad_params,
524 : " -> ",
525 : source_constructor,
526 : good_params,
527 : "\n\n",
528 : "In ",
529 : type(),
530 : ".h, change:\n ",
531 : type(),
532 : bad_params,
533 : "; -> ",
534 : type(),
535 : good_params,
536 : ";"));
537 0 : Moose::show_trace = show_trace;
538 3 : }
539 :
540 : // Set the TIMPI sync type via --timpi-sync
541 62754 : const auto & timpi_sync = _pars.get<std::string>("timpi_sync");
542 62754 : const_cast<Parallel::Communicator &>(comm()).sync_type(timpi_sync);
543 :
544 : #ifdef HAVE_GPERFTOOLS
545 : if (isUltimateMaster())
546 : {
547 : bool has_cpu_profiling = false;
548 : bool has_heap_profiling = false;
549 : static std::string cpu_profile_file;
550 : static std::string heap_profile_file;
551 :
552 : // For CPU profiling, users need to have environment 'MOOSE_PROFILE_BASE'
553 : if (std::getenv("MOOSE_PROFILE_BASE"))
554 : {
555 : has_cpu_profiling = true;
556 : cpu_profile_file =
557 : std::getenv("MOOSE_PROFILE_BASE") + std::to_string(_comm->rank()) + ".prof";
558 : // create directory if needed
559 : auto name = MooseUtils::splitFileName(cpu_profile_file);
560 : if (!name.first.empty())
561 : {
562 : if (processor_id() == 0)
563 : MooseUtils::makedirs(name.first.c_str());
564 : _comm->barrier();
565 : }
566 : }
567 :
568 : // For Heap profiling, users need to have 'MOOSE_HEAP_BASE'
569 : if (std::getenv("MOOSE_HEAP_BASE"))
570 : {
571 : has_heap_profiling = true;
572 : heap_profile_file = std::getenv("MOOSE_HEAP_BASE") + std::to_string(_comm->rank());
573 : // create directory if needed
574 : auto name = MooseUtils::splitFileName(heap_profile_file);
575 : if (!name.first.empty())
576 : {
577 : if (processor_id() == 0)
578 : MooseUtils::makedirs(name.first.c_str());
579 : _comm->barrier();
580 : }
581 : }
582 :
583 : // turn on profiling only on selected ranks
584 : if (isParamSetByUser("gperf_profiler_on"))
585 : {
586 : auto rankstr = getParam<std::string>("gperf_profiler_on");
587 : std::vector<processor_id_type> ranks;
588 : bool success = MooseUtils::tokenizeAndConvert(rankstr, ranks, ", ");
589 : if (!success)
590 : mooseError("Invalid argument for --gperf-profiler-on: '", rankstr, "'");
591 : for (auto & rank : ranks)
592 : {
593 : if (rank >= _comm->size())
594 : mooseError("Invalid argument for --gperf-profiler-on: ",
595 : rank,
596 : " is greater than or equal to ",
597 : _comm->size());
598 : if (rank == _comm->rank())
599 : {
600 : _cpu_profiling = has_cpu_profiling;
601 : _heap_profiling = has_heap_profiling;
602 : }
603 : }
604 : }
605 : else
606 : {
607 : _cpu_profiling = has_cpu_profiling;
608 : _heap_profiling = has_heap_profiling;
609 : }
610 :
611 : if (_cpu_profiling)
612 : if (!ProfilerStart(cpu_profile_file.c_str()))
613 : mooseError("CPU profiler is not started properly");
614 :
615 : if (_heap_profiling)
616 : {
617 : HeapProfilerStart(heap_profile_file.c_str());
618 : if (!IsHeapProfilerRunning())
619 : mooseError("Heap profiler is not started properly");
620 : }
621 : }
622 : #else
623 62754 : if (std::getenv("MOOSE_PROFILE_BASE") || std::getenv("MOOSE_HEAP_BASE"))
624 0 : mooseError("gperftool is not available for CPU or heap profiling");
625 : #endif
626 :
627 : // If this will be a language server then turn off output until that starts
628 62754 : if (isParamValid("language_server") && getParam<bool>("language_server"))
629 0 : _output_buffer_cache = Moose::out.rdbuf(nullptr);
630 :
631 62754 : Registry::addKnownLabel(_type);
632 62754 : Moose::registerAll(_factory, _action_factory, _syntax);
633 :
634 62754 : _the_warehouse = std::make_unique<TheWarehouse>();
635 62754 : _the_warehouse->registerAttribute<AttribMatrixTags>("matrix_tags", 0);
636 62754 : _the_warehouse->registerAttribute<AttribVectorTags>("vector_tags", 0);
637 62754 : _the_warehouse->registerAttribute<AttribExecOns>("exec_ons", 0);
638 62754 : _the_warehouse->registerAttribute<AttribSubdomains>("subdomains", 0);
639 62754 : _the_warehouse->registerAttribute<AttribBoundaries>("boundaries", 0);
640 62754 : _the_warehouse->registerAttribute<AttribThread>("thread", 0);
641 62754 : _the_warehouse->registerAttribute<AttribExecutionOrderGroup>("execution_order_group", 0);
642 62754 : _the_warehouse->registerAttribute<AttribPreIC>("pre_ic", 0);
643 62754 : _the_warehouse->registerAttribute<AttribPreAux>("pre_aux");
644 62754 : _the_warehouse->registerAttribute<AttribPostAux>("post_aux");
645 62754 : _the_warehouse->registerAttribute<AttribName>("name", "dummy");
646 62754 : _the_warehouse->registerAttribute<AttribSystem>("system", "dummy");
647 62754 : _the_warehouse->registerAttribute<AttribVar>("variable", -1);
648 62754 : _the_warehouse->registerAttribute<AttribInterfaces>("interfaces", 0);
649 62754 : _the_warehouse->registerAttribute<AttribSysNum>("sys_num", libMesh::invalid_uint);
650 62754 : _the_warehouse->registerAttribute<AttribResidualObject>("residual_object");
651 62754 : _the_warehouse->registerAttribute<AttribSorted>("sorted");
652 62754 : _the_warehouse->registerAttribute<AttribDisplaced>("displaced", -1);
653 :
654 62754 : _perf_graph.enableLivePrint();
655 :
656 62754 : if (isParamValid("_argc") && isParamValid("_argv"))
657 : {
658 51361 : int argc = getParam<int>("_argc");
659 51361 : char ** argv = getParam<char **>("_argv");
660 :
661 51361 : _sys_info = std::make_unique<SystemInfo>(argc, argv);
662 : }
663 62754 : if (isParamValid("_command_line"))
664 62754 : _command_line = getParam<std::shared_ptr<CommandLine>>("_command_line");
665 : else
666 0 : mooseError("Valid CommandLine object required");
667 :
668 62754 : if (_check_input && isParamSetByUser("recover"))
669 0 : mooseError("Cannot run --check-input with --recover. Recover files might not exist");
670 :
671 62754 : if (isParamSetByUser("start_in_debugger") && isUltimateMaster())
672 : {
673 0 : auto command = getParam<std::string>("start_in_debugger");
674 :
675 0 : Moose::out << "Starting in debugger using: " << command << std::endl;
676 :
677 0 : auto hostname = MooseUtils::hostname();
678 :
679 0 : std::stringstream command_stream;
680 :
681 : // This will start XTerm and print out some info first... then run the debugger
682 0 : command_stream << "xterm -e \"echo 'Rank: " << processor_id() << " Hostname: " << hostname
683 0 : << " PID: " << getpid() << "'; echo ''; ";
684 :
685 : // Figure out how to run the debugger
686 0 : if (command.find("lldb") != std::string::npos || command.find("gdb") != std::string::npos)
687 0 : command_stream << command << " -p " << getpid();
688 : else
689 0 : mooseError("Unknown debugger: ",
690 : command,
691 : "\nIf this is truly what you meant then contact moose-users to have a discussion "
692 : "about adding your debugger.");
693 :
694 : // Finish up the command
695 : command_stream << "\""
696 0 : << " & ";
697 0 : std::string command_string = command_stream.str();
698 0 : Moose::out << "Running: " << command_string << std::endl;
699 :
700 0 : int ret = std::system(command_string.c_str());
701 0 : libmesh_ignore(ret);
702 :
703 : // Sleep to allow time for the debugger to attach
704 0 : std::this_thread::sleep_for(std::chrono::seconds(10));
705 0 : }
706 :
707 62754 : if (isParamSetByUser("stop_for_debugger") && isUltimateMaster())
708 : {
709 20 : Moose::out << "\nStopping for " << getParam<unsigned int>("stop_for_debugger")
710 10 : << " seconds to allow attachment from a debugger.\n";
711 :
712 10 : Moose::out << "\nAll of the processes you can connect to:\n";
713 10 : Moose::out << "rank - hostname - pid\n";
714 :
715 10 : auto hostname = MooseUtils::hostname();
716 :
717 : {
718 : // The 'false' turns off the serialization warning
719 10 : SerializerGuard sg(_communicator, false); // Guarantees that the processors print in order
720 10 : Moose::err << processor_id() << " - " << hostname << " - " << getpid() << "\n";
721 10 : }
722 :
723 10 : Moose::out << "\nWaiting...\n" << std::endl;
724 :
725 : // Sleep to allow time for the debugger to attach
726 10 : std::this_thread::sleep_for(std::chrono::seconds(getParam<unsigned int>("stop_for_debugger")));
727 10 : }
728 :
729 62754 : if (_master_mesh && _multiapp_level == 0)
730 0 : mooseError("Mesh can be passed in only for sub-apps");
731 :
732 62754 : if (_master_displaced_mesh && !_master_mesh)
733 0 : mooseError("_master_mesh should have been set when _master_displaced_mesh is set");
734 :
735 : // Data specifically associated with the mesh (meta-data) that will read from the restart
736 : // file early during the simulation setup so that they are available to Actions and other objects
737 : // that need them during the setup process. Most of the restartable data isn't made available
738 : // until all objects have been created and all Actions have been executed (i.e. initialSetup).
739 62754 : registerRestartableDataMapName(MooseApp::MESH_META_DATA, MooseApp::MESH_META_DATA_SUFFIX);
740 :
741 62754 : if (_pars.have_parameter<bool>("use_legacy_dirichlet_bc"))
742 0 : mooseDeprecated("The parameter 'use_legacy_dirichlet_bc' is no longer valid.\n\n",
743 : "All Dirichlet boundary conditions are preset by default.\n\n",
744 : "Remove said parameter in ",
745 0 : name(),
746 : " to remove this deprecation warning.");
747 :
748 62754 : registerCapabilities();
749 62754 : Moose::out << std::flush;
750 62796 : }
751 :
752 : void
753 62754 : MooseApp::registerCapabilities()
754 : {
755 : // helper lambdas
756 799694 : auto haveCapability = [](const std::string & capability, const std::string & doc)
757 799694 : { addCapability(capability, true, doc + " is available."); };
758 :
759 : auto missingCapability =
760 260136 : [](const std::string & capability, const std::string & doc, const std::string & help = "")
761 260136 : { addCapability(capability, false, doc + " is not available. " + help); };
762 :
763 : auto haveCapabilityVersion =
764 188262 : [](const std::string & capability, const std::string & doc, const std::string & version)
765 188262 : { addCapability(capability, version, doc + " version " + version + " is available."); };
766 :
767 125508 : auto petscMissingCapability = [](const std::string & capability, const std::string & doc)
768 : {
769 125508 : addCapability(
770 251016 : capability, false, doc + " is not available. Check your PETSc configure options.");
771 125508 : };
772 :
773 : auto libmeshMissingCapability =
774 251016 : [](const std::string & capability, const std::string & doc, const std::string & config_option)
775 : {
776 251016 : addCapability(capability,
777 251016 : false,
778 502032 : doc + " is not available. It is controlled by the `" + config_option +
779 : "` libMesh configure option.");
780 251016 : };
781 :
782 : // register capabilities
783 62754 : if (_trap_fpe)
784 0 : addCapability("trap_fpe",
785 0 : true,
786 : "Trapping floating point exceptions is enabled (in debug mode this "
787 : "can be disabled using the --no-trap-fpe option).");
788 : else
789 188262 : addCapability("trap_fpe",
790 125508 : false,
791 : "Trapping floating point exceptions is not enabled (enable them using "
792 : "the --trap-fpe option or by running a debug mode executable).");
793 :
794 : {
795 62754 : const auto doc = "LibTorch machine learning and parallel tensor algebra library";
796 : #ifdef LIBTORCH_ENABLED
797 6988 : addCapability("libtorch", TORCH_VERSION, doc);
798 : #else
799 55766 : missingCapability("libtorch",
800 : doc,
801 : "Check "
802 : "https://mooseframework.inl.gov/moose/getting_started/installation/"
803 : "install_libtorch.html for "
804 : "instructions on how to configure and build moose with libTorch.");
805 : #endif
806 : }
807 :
808 : {
809 62754 : const auto doc = "MFEM finite element library";
810 : #ifdef MFEM_ENABLED
811 39589 : haveCapability("mfem", doc);
812 : #else
813 23165 : missingCapability("mfem",
814 : doc,
815 : "Install mfem using the scripts/update_and_rebuild_mfem.sh script after "
816 : "first running scripts/update_and_rebuild_conduit.sh. Finally, configure "
817 : "moose with ./configure --with-mfem");
818 : #endif
819 : }
820 :
821 : {
822 62754 : const auto doc = "New Engineering Material model Library, version 2";
823 : #ifdef NEML2_ENABLED
824 6988 : haveCapability("neml2", doc);
825 : #else
826 55766 : missingCapability("neml2",
827 : doc,
828 : "Install neml2 using the scripts/update_and_rebuild_neml2.sh script, then "
829 : "configure moose with ./configure --with-neml2 --with-libtorch");
830 : #endif
831 : }
832 :
833 : {
834 62754 : const auto doc = "gperftools code performance analysis and profiling library";
835 : #ifdef HAVE_GPERFTOOLS
836 : haveCapability("gperftools", doc);
837 : #else
838 62754 : missingCapability("gperftools",
839 : doc,
840 : "Check https://mooseframework.inl.gov/application_development/profiling.html "
841 : "for instructions on profiling MOOSE based applications.");
842 : #endif
843 : }
844 :
845 : {
846 62754 : const auto doc = "libPNG portable network graphics format library";
847 : #ifdef MOOSE_HAVE_LIBPNG
848 62754 : haveCapability("libpng", doc);
849 : #else
850 : missingCapability("libpng",
851 : doc,
852 : "Install libpng through conda or your distribution and check that it gets "
853 : "detected through pkg-config, then reconfigure and rebuild MOOSE.");
854 : #endif
855 : }
856 :
857 : {
858 62754 : const auto doc = "NVIDIA GPU parallel computing platform";
859 : #ifdef PETSC_HAVE_CUDA
860 69 : haveCapability("cuda", doc);
861 : #else
862 62685 : missingCapability("cuda", doc, "Add the CUDA bin directory to your path and rebuild PETSc.");
863 : #endif
864 : }
865 :
866 62754 : addCapability(
867 : "ad_size",
868 62754 : MOOSE_AD_MAX_DOFS_PER_ELEM,
869 125508 : "MOOSE was configured and built with a dual number backing store size of " +
870 251016 : Moose::stringify(MOOSE_AD_MAX_DOFS_PER_ELEM) +
871 : ". Complex simulations with many variables or contact problems may require larger "
872 : "values. Reconfigure MOOSE with the --with-derivative-size=<n> option in the root of the "
873 : "repository.");
874 : {
875 62754 : const std::string method = QUOTE(METHOD);
876 62754 : addCapability("method", method, "The executable was built with METHOD=\"" + method + "\"");
877 62754 : }
878 :
879 : {
880 : const std::string version = QUOTE(LIBMESH_DETECTED_PETSC_VERSION_MAJOR) "." QUOTE(
881 62754 : LIBMESH_DETECTED_PETSC_VERSION_MINOR) "." QUOTE(LIBMESH_DETECTED_PETSC_VERSION_SUBMINOR);
882 62754 : addCapability("petsc", version, "Using PETSc version " + version + ".");
883 62754 : }
884 :
885 : #ifdef LIBMESH_PETSC_USE_DEBUG
886 62754 : addCapability("petsc_debug", true, "PETSc was built with debugging options.");
887 : #else
888 : addCapability("petsc_debug", false, "PETSc was built without debugging options.");
889 : #endif
890 :
891 : {
892 62754 : const auto doc = "SuperLU direct solver";
893 : #ifdef LIBMESH_PETSC_HAVE_SUPERLU_DIST
894 62754 : haveCapability("superlu", doc);
895 : #else
896 : petscMissingCapability("superlu", doc);
897 : #endif
898 : }
899 :
900 : {
901 62754 : const auto doc = "MUltifrontal Massively Parallel sparse direct Solver (MUMPS)";
902 : #ifdef LIBMESH_PETSC_HAVE_MUMPS
903 62754 : haveCapability("mumps", doc);
904 : #else
905 : petscMissingCapability("mumps", doc);
906 : #endif
907 : }
908 :
909 : {
910 62754 : const auto doc = "STRUMPACK - STRUctured Matrix PACKage solver library";
911 : #ifdef LIBMESH_PETSC_HAVE_STRUMPACK
912 62754 : haveCapability("strumpack", doc);
913 : #else
914 : petscMissingCapability("strumpack", doc);
915 : #endif
916 : }
917 :
918 : {
919 62754 : const auto doc = "Parmetis partitioning library";
920 : #if defined(LIBMESH_PETSC_HAVE_PARMETIS) || defined(LIBMESH_HAVE_PARMETIS)
921 62754 : haveCapability("parmetis", doc);
922 : #else
923 : petscMissingCapability("parmetis", doc);
924 : #endif
925 : }
926 :
927 : {
928 62754 : const auto doc = "Chaco graph partitioning library";
929 : #ifdef LIBMESH_PETSC_HAVE_CHACO
930 : haveCapability("chaco", doc);
931 : #else
932 62754 : petscMissingCapability("chaco", doc);
933 : #endif
934 : }
935 :
936 : {
937 62754 : const auto doc = "Party matrix or graph partitioning library";
938 : #ifdef LIBMESH_PETSC_HAVE_PARTY
939 : haveCapability("party", doc);
940 : #else
941 62754 : petscMissingCapability("party", doc);
942 : #endif
943 : }
944 :
945 : {
946 62754 : const auto doc = "PT-Scotch graph partitioning library";
947 : #ifdef LIBMESH_PETSC_HAVE_PTSCOTCH
948 62754 : haveCapability("ptscotch", doc);
949 : #else
950 : petscMissingCapability("ptscotch", doc);
951 : #endif
952 : }
953 :
954 : {
955 62754 : const auto doc = "Scalable Library for Eigenvalue Problem Computations (SLEPc)";
956 : #ifdef LIBMESH_HAVE_SLEPC
957 62754 : const auto version = QUOTE(LIBMESH_DETECTED_SLEPC_VERSION_MAJOR) "." QUOTE(
958 : LIBMESH_DETECTED_SLEPC_VERSION_MINOR) "." QUOTE(LIBMESH_DETECTED_SLEPC_VERSION_SUBMINOR);
959 62754 : haveCapabilityVersion("slepc", doc, version);
960 : #else
961 : petscMissingCapability("slepc", doc);
962 : #endif
963 : }
964 :
965 : {
966 62754 : const auto doc = "Exodus mesh file format library";
967 : #ifdef LIBMESH_HAVE_EXODUS_API
968 62754 : const std::string version = QUOTE(LIBMESH_DETECTED_EXODUS_VERSION_MAJOR) "." QUOTE(
969 : LIBMESH_DETECTED_EXODUS_VERSION_MINOR);
970 62754 : haveCapabilityVersion("exodus", doc, version);
971 : #else
972 : libmeshMissingCapability("exodus", doc, "--enable-exodus");
973 : #endif
974 62754 : }
975 :
976 : {
977 62754 : const auto doc = "Netgen meshing library";
978 : #ifdef LIBMESH_HAVE_NETGEN
979 62754 : haveCapability("netgen", doc);
980 : #else
981 : libmeshMissingCapability("netgen", doc, "--enable-netgen");
982 : #endif
983 : }
984 :
985 : {
986 62754 : const auto doc = "Visualization Toolkit (VTK)";
987 : #ifdef LIBMESH_HAVE_VTK
988 : const std::string version = QUOTE(LIBMESH_DETECTED_VTK_VERSION_MAJOR) "." QUOTE(
989 62754 : LIBMESH_DETECTED_VTK_VERSION_MINOR) "." QUOTE(LIBMESH_DETECTED_VTK_VERSION_SUBMINOR);
990 62754 : haveCapabilityVersion("vtk", doc, version);
991 : #else
992 : libmeshMissingCapability("vtk", doc, "--disable-vtk and --enable-vtk-required");
993 : #endif
994 62754 : }
995 :
996 : {
997 62754 : const auto doc = "libcurl - the multiprotocol file transfer library";
998 : #ifdef LIBMESH_HAVE_CURL
999 : haveCapability("curl", doc);
1000 : #else
1001 62754 : libmeshMissingCapability("curl", doc, "--enable-curl");
1002 : #endif
1003 : }
1004 :
1005 : {
1006 62754 : const auto doc = "Tecplot post-processing tools API";
1007 : #ifdef LIBMESH_HAVE_TECPLOT_API
1008 : haveCapability("tecplot", doc);
1009 : #else
1010 62754 : libmeshMissingCapability("tecplot", doc, "--enable-tecplot");
1011 : #endif
1012 : }
1013 :
1014 : {
1015 62754 : const auto doc = "Boost C++ library";
1016 : #ifdef LIBMESH_HAVE_EXTERNAL_BOOST
1017 : haveCapability("boost", doc);
1018 : #else
1019 62754 : libmeshMissingCapability("boost", doc, "--with-boost");
1020 : #endif
1021 : }
1022 :
1023 : // libmesh stuff
1024 : {
1025 62754 : const auto doc = "Adaptive mesh refinement";
1026 : #ifdef LIBMESH_ENABLE_AMR
1027 62754 : haveCapability("amr", doc);
1028 : #else
1029 : libmeshMissingCapability("amr", doc, "--disable-amr");
1030 : #endif
1031 : }
1032 :
1033 : {
1034 62754 : const auto doc = "nanoflann library for Nearest Neighbor (NN) search with KD-trees";
1035 : #ifdef LIBMESH_HAVE_NANOFLANN
1036 62754 : haveCapability("nanoflann", doc);
1037 : #else
1038 : libmeshMissingCapability("nanoflann", doc, "--disable-nanoflann");
1039 : #endif
1040 : }
1041 :
1042 : #ifdef LIBMESH_HAVE_FPARSER
1043 : #ifdef LIBMESH_HAVE_FPARSER_JIT
1044 62754 : addCapability("fparser", "jit", "FParser enabled with just in time compilation support.");
1045 : #else
1046 : addCapability("fparser", "byte_code", "FParser enabled.");
1047 : #endif
1048 : #else
1049 : addCapability("fparser",
1050 : false,
1051 : "FParser is disabled, libMesh was likely configured with --disable-fparser.");
1052 : #endif
1053 :
1054 : #ifdef LIBMESH_HAVE_DLOPEN
1055 188262 : addCapability(
1056 125508 : "dlopen", true, "The dlopen() system call is available to dynamically load libraries.");
1057 : #else
1058 : addCapability("dlopen",
1059 : false,
1060 : "The dlopen() system call is not available. Dynamic library loading is "
1061 : "not supported on this system.");
1062 : #endif
1063 :
1064 : {
1065 62754 : const auto doc = "LibMesh support for threaded execution";
1066 : #ifdef LIBMESH_USING_THREADS
1067 62754 : haveCapability("threads", doc);
1068 : #else
1069 : libmeshMissingCapability("threads", doc, "--with-thread-model=tbb,pthread,openmp,auto,none");
1070 : #endif
1071 : }
1072 :
1073 : {
1074 62754 : const auto doc = "OpenMP multi-platform shared-memory parallel programming API";
1075 : #ifdef LIBMESH_HAVE_OPENMP
1076 62754 : haveCapability("openmp", doc);
1077 : #else
1078 : libmeshMissingCapability("openmp", doc, "--with-thread-model=tbb,pthread,openmp,auto,none");
1079 : #endif
1080 : }
1081 : {
1082 62754 : const auto doc = "oneAPI Threading Building Blocks (TBB) API";
1083 : #ifdef LIBMESH_HAVE_TBB_API
1084 : haveCapability("tbb", doc);
1085 : #else
1086 62754 : libmeshMissingCapability("tbb", doc, "--with-thread-model=tbb,pthread,openmp,auto,none");
1087 : #endif
1088 : }
1089 :
1090 : {
1091 62754 : const auto doc = "libMesh unique ID support";
1092 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
1093 62754 : haveCapability("unique_id", doc);
1094 : #else
1095 : libmeshMissingCapability("unique_id", doc, "--enable-unique-id");
1096 : #endif
1097 : }
1098 :
1099 : {
1100 62754 : const auto doc = "libMesh default mesh mode";
1101 : #ifdef LIBMESH_ENABLE_PARMESH
1102 : addCapability("mesh_mode", "distributed", doc);
1103 : #else
1104 62754 : addCapability("mesh_mode", "replicated", doc);
1105 : #endif
1106 : }
1107 :
1108 62754 : addCapability("dof_id_bytes",
1109 62754 : static_cast<int>(sizeof(dof_id_type)),
1110 125508 : "Degree of freedom (DOF) identifiers use " + Moose::stringify(sizeof(dof_id_type)) +
1111 : " bytes for storage. This is controlled by the "
1112 : "--with-dof-id-bytes=<1|2|4|8> libMesh configure option.");
1113 :
1114 : // compiler
1115 : {
1116 62754 : const auto doc = "Compiler used to build the MOOSE framework.";
1117 : #if defined(__clang__)
1118 : addCapability("compiler", "clang", doc);
1119 : #elif defined(__GNUC__) || defined(__GNUG__)
1120 62754 : addCapability("compiler", "gcc", doc);
1121 : #elif defined(_MSC_VER)
1122 : addCapability("compiler", "msvc", doc);
1123 : #else
1124 : addCapability("compiler", false, "Unknown compiler");
1125 : #endif
1126 : }
1127 :
1128 : // OS related
1129 : {
1130 62754 : const auto doc = "Operating system this executable is running on.";
1131 : #ifdef __APPLE__
1132 : addCapability("platform", "darwin", doc);
1133 : #elif __WIN32__
1134 : addCapability("platform", "win32", doc);
1135 : #elif __linux__
1136 62754 : addCapability("platform", "linux", doc);
1137 : #elif __unix__ // all unices not caught above
1138 : addCapability("platform", "unix", doc);
1139 : #endif
1140 : }
1141 62754 : }
1142 :
1143 343518 : MooseApp::~MooseApp()
1144 : {
1145 : #ifdef HAVE_GPERFTOOLS
1146 : // CPU profiling stop
1147 : if (_cpu_profiling)
1148 : ProfilerStop();
1149 : // Heap profiling stop
1150 : if (_heap_profiling)
1151 : HeapProfilerStop();
1152 : #endif
1153 57253 : _action_warehouse.clear();
1154 57253 : _the_warehouse.reset();
1155 57253 : _executioner.reset();
1156 :
1157 : // Don't wait for implicit destruction of input parameter storage
1158 57253 : _input_parameter_warehouse.reset();
1159 :
1160 : // This is dirty, but I don't know what else to do. Obviously, others
1161 : // have had similar problems if you look above. In specific, the
1162 : // dlclose below on macs is destructing some data that does not
1163 : // belong to it in garbage collection. So... don't even give
1164 : // dlclose an option
1165 57253 : _restartable_data.clear();
1166 :
1167 : // Remove this app's parameters from the AppFactory
1168 57253 : AppFactory::instance().clearAppParams(parameters(), {});
1169 :
1170 : #ifdef LIBMESH_HAVE_DLOPEN
1171 : // Close any open dynamic libraries
1172 57261 : for (const auto & lib_pair : _lib_handles)
1173 8 : dlclose(lib_pair.second.library_handle);
1174 : #endif
1175 57253 : }
1176 :
1177 : std::string
1178 0 : MooseApp::getFrameworkVersion() const
1179 : {
1180 0 : return MOOSE_VERSION;
1181 : }
1182 :
1183 : std::string
1184 34 : MooseApp::getVersion() const
1185 : {
1186 34 : return MOOSE_VERSION;
1187 : }
1188 :
1189 : std::string
1190 34 : MooseApp::getPrintableVersion() const
1191 : {
1192 68 : return getPrintableName() + " Version: " + getVersion();
1193 : }
1194 :
1195 : void
1196 62537 : MooseApp::setupOptions()
1197 : {
1198 62537 : TIME_SECTION("setupOptions", 5, "Setting Up Options");
1199 :
1200 : // Print the header, this is as early as possible
1201 62537 : if (header().length() && !getParam<bool>("suppress_header"))
1202 30 : _console << header() << std::endl;
1203 :
1204 62537 : if (getParam<bool>("error_unused"))
1205 602 : setCheckUnusedFlag(true);
1206 61935 : else if (getParam<bool>("allow_unused"))
1207 119 : setCheckUnusedFlag(false);
1208 :
1209 62537 : if (getParam<bool>("error_override"))
1210 59391 : setErrorOverridden();
1211 :
1212 62537 : _distributed_mesh_on_command_line = getParam<bool>("distributed_mesh");
1213 :
1214 62537 : _test_checkpoint_half_transient = getParam<bool>("test_checkpoint_half_transient");
1215 :
1216 62537 : if (getParam<bool>("trap_fpe"))
1217 : {
1218 0 : _trap_fpe = true;
1219 0 : _perf_graph.setActive(false);
1220 0 : if (getParam<bool>("no_trap_fpe"))
1221 0 : mooseError("Cannot use both \"--trap-fpe\" and \"--no-trap-fpe\" flags.");
1222 : }
1223 62537 : else if (getParam<bool>("no_trap_fpe"))
1224 118 : _trap_fpe = false;
1225 :
1226 : // Turn all warnings in MOOSE to errors (almost see next logic block)
1227 62537 : Moose::_warnings_are_errors = getParam<bool>("error");
1228 :
1229 : // Deprecated messages can be toggled to errors independently from everything else.
1230 62537 : Moose::_deprecated_is_error = getParam<bool>("error_deprecated");
1231 :
1232 62537 : if (isUltimateMaster()) // makes sure coloring isn't reset incorrectly in multi-app settings
1233 : {
1234 : // Set from command line
1235 51148 : auto color = getParam<MooseEnum>("color");
1236 51148 : if (!isParamSetByUser("color"))
1237 : {
1238 : // Set from deprecated --no-color
1239 50855 : if (getParam<bool>("no_color"))
1240 0 : color = "off";
1241 : // Set from environment
1242 : else
1243 : {
1244 50855 : char * c_color = std::getenv("MOOSE_COLOR");
1245 50855 : if (c_color)
1246 0 : color.assign(std::string(c_color), "While assigning environment variable MOOSE_COLOR");
1247 : }
1248 : }
1249 :
1250 51148 : if (color == "auto")
1251 0 : Moose::setColorConsole(true);
1252 51148 : else if (color == "on")
1253 50855 : Moose::setColorConsole(true, true);
1254 293 : else if (color == "off")
1255 293 : Moose::setColorConsole(false);
1256 : else
1257 : mooseAssert(false, "Should not hit");
1258 :
1259 : // After setting color so that non-yellow deprecated is honored
1260 51148 : if (getParam<bool>("no_color"))
1261 0 : mooseDeprecated("The --no-color flag is deprecated. Use '--color off' instead.");
1262 51148 : }
1263 :
1264 : // If there's no threading model active, but the user asked for
1265 : // --n-threads > 1 on the command line, throw a mooseError. This is
1266 : // intended to prevent situations where the user has potentially
1267 : // built MOOSE incorrectly (neither TBB nor pthreads found) and is
1268 : // asking for multiple threads, not knowing that there will never be
1269 : // any threads launched.
1270 : #if !LIBMESH_USING_THREADS
1271 : if (libMesh::command_line_value("--n-threads", 1) > 1)
1272 : mooseError("You specified --n-threads > 1, but there is no threading model active!");
1273 : #endif
1274 :
1275 : // Build a minimal running application, ignoring the input file.
1276 62537 : if (getParam<bool>("minimal"))
1277 1 : createMinimalApp();
1278 :
1279 62536 : else if (getParam<bool>("display_version"))
1280 : {
1281 34 : Moose::out << getPrintableVersion() << std::endl;
1282 34 : _early_exit_param = "--version";
1283 34 : _ready_to_exit = true;
1284 34 : return;
1285 : }
1286 62502 : else if (getParam<bool>("help"))
1287 : {
1288 15 : _command_line->printUsage();
1289 15 : _early_exit_param = "--help";
1290 15 : _ready_to_exit = true;
1291 : }
1292 62487 : else if (getParam<bool>("dump") || isParamSetByUser("dump_search"))
1293 : {
1294 : const std::string search =
1295 18 : isParamSetByUser("dump_search") ? getParam<std::string>("dump_search") : "";
1296 :
1297 18 : JsonSyntaxTree tree(search);
1298 :
1299 : {
1300 18 : TIME_SECTION("dump", 1, "Building Syntax Tree");
1301 18 : _builder.buildJsonSyntaxTree(tree);
1302 18 : }
1303 :
1304 : // Check if second arg is valid or not
1305 18 : if ((tree.getRoot()).is_object())
1306 : {
1307 : // Turn off live printing so that it doesn't mess with the dump
1308 14 : _perf_graph.disableLivePrint();
1309 :
1310 14 : JsonInputFileFormatter formatter;
1311 14 : Moose::out << "\n### START DUMP DATA ###\n"
1312 14 : << formatter.toString(tree.getRoot()) << "\n### END DUMP DATA ###" << std::endl;
1313 14 : _early_exit_param = "--dump";
1314 14 : _ready_to_exit = true;
1315 14 : }
1316 : else
1317 4 : mooseError("Search parameter '", search, "' was not found in the registered syntax.");
1318 14 : }
1319 62469 : else if (getParam<bool>("registry"))
1320 : {
1321 10 : _perf_graph.disableLivePrint();
1322 :
1323 10 : Moose::out << "Label\tType\tName\tClass\tFile\n";
1324 :
1325 10 : auto & objmap = Registry::allObjects();
1326 30 : for (auto & entry : objmap)
1327 14930 : for (auto & obj : entry.second)
1328 29820 : Moose::out << entry.first << "\tobject\t" << obj->name() << "\t" << obj->_classname << "\t"
1329 14910 : << obj->_file << "\n";
1330 :
1331 10 : auto & actmap = Registry::allActions();
1332 30 : for (auto & entry : actmap)
1333 : {
1334 2106 : for (auto & act : entry.second)
1335 2086 : Moose::out << entry.first << "\taction\t" << act->_name << "\t" << act->_classname << "\t"
1336 2086 : << act->_file << "\n";
1337 : }
1338 10 : _early_exit_param = "--registry";
1339 10 : _ready_to_exit = true;
1340 : }
1341 62459 : else if (getParam<bool>("registry_hit"))
1342 : {
1343 10 : _perf_graph.disableLivePrint();
1344 :
1345 10 : Moose::out << "### START REGISTRY DATA ###\n";
1346 :
1347 10 : hit::Section root("");
1348 10 : auto sec = new hit::Section("registry");
1349 10 : root.addChild(sec);
1350 10 : auto objsec = new hit::Section("objects");
1351 10 : sec->addChild(objsec);
1352 :
1353 10 : auto & objmap = Registry::allObjects();
1354 30 : for (auto & entry : objmap)
1355 14930 : for (auto & obj : entry.second)
1356 : {
1357 14910 : auto ent = new hit::Section("entry");
1358 14910 : objsec->addChild(ent);
1359 14910 : ent->addChild(new hit::Field("label", hit::Field::Kind::String, entry.first));
1360 14910 : ent->addChild(new hit::Field("type", hit::Field::Kind::String, "object"));
1361 14910 : ent->addChild(new hit::Field("name", hit::Field::Kind::String, obj->name()));
1362 14910 : ent->addChild(new hit::Field("class", hit::Field::Kind::String, obj->_classname));
1363 14910 : ent->addChild(new hit::Field("file", hit::Field::Kind::String, obj->_file));
1364 : }
1365 :
1366 10 : auto actsec = new hit::Section("actions");
1367 10 : sec->addChild(actsec);
1368 10 : auto & actmap = Registry::allActions();
1369 30 : for (auto & entry : actmap)
1370 2106 : for (auto & act : entry.second)
1371 : {
1372 2086 : auto ent = new hit::Section("entry");
1373 2086 : actsec->addChild(ent);
1374 2086 : ent->addChild(new hit::Field("label", hit::Field::Kind::String, entry.first));
1375 2086 : ent->addChild(new hit::Field("type", hit::Field::Kind::String, "action"));
1376 2086 : ent->addChild(new hit::Field("task", hit::Field::Kind::String, act->_name));
1377 2086 : ent->addChild(new hit::Field("class", hit::Field::Kind::String, act->_classname));
1378 2086 : ent->addChild(new hit::Field("file", hit::Field::Kind::String, act->_file));
1379 : }
1380 :
1381 10 : Moose::out << root.render();
1382 :
1383 10 : Moose::out << "\n### END REGISTRY DATA ###\n";
1384 10 : _early_exit_param = "--registry_hit";
1385 10 : _ready_to_exit = true;
1386 10 : }
1387 62449 : else if (getParam<bool>("definition"))
1388 : {
1389 130 : _perf_graph.disableLivePrint();
1390 :
1391 130 : JsonSyntaxTree tree("");
1392 130 : _builder.buildJsonSyntaxTree(tree);
1393 130 : SONDefinitionFormatter formatter;
1394 130 : Moose::out << "%-START-SON-DEFINITION-%\n"
1395 130 : << formatter.toString(tree.getRoot()) << "\n%-END-SON-DEFINITION-%\n";
1396 130 : _early_exit_param = "--definition";
1397 130 : _ready_to_exit = true;
1398 130 : }
1399 62319 : else if (getParam<bool>("yaml") || isParamSetByUser("yaml_search"))
1400 : {
1401 : const std::string search =
1402 20 : isParamSetByUser("yaml_search") ? getParam<std::string>("yaml_search") : "";
1403 20 : _perf_graph.disableLivePrint();
1404 :
1405 20 : _builder.initSyntaxFormatter(Moose::Builder::YAML, true);
1406 20 : _builder.buildFullTree(search);
1407 :
1408 20 : _early_exit_param = "--yaml";
1409 20 : _ready_to_exit = true;
1410 20 : }
1411 62299 : else if (getParam<bool>("json") || isParamSetByUser("json_search"))
1412 : {
1413 : const std::string search =
1414 35 : isParamSetByUser("json_search") ? getParam<std::string>("json_search") : "";
1415 35 : _perf_graph.disableLivePrint();
1416 :
1417 35 : JsonSyntaxTree tree(search);
1418 35 : _builder.buildJsonSyntaxTree(tree);
1419 :
1420 35 : outputMachineReadableData(
1421 70 : "json", "**START JSON DATA**\n", "\n**END JSON DATA**", tree.getRoot().dump(2));
1422 35 : _early_exit_param = "--json";
1423 35 : _ready_to_exit = true;
1424 35 : }
1425 62264 : else if (getParam<bool>("syntax"))
1426 : {
1427 0 : _perf_graph.disableLivePrint();
1428 :
1429 0 : std::multimap<std::string, Syntax::ActionInfo> syntax = _syntax.getAssociatedActions();
1430 0 : std::stringstream ss;
1431 0 : for (const auto & it : syntax)
1432 0 : ss << it.first << "\n";
1433 0 : outputMachineReadableData("syntax", "**START SYNTAX DATA**\n", "**END SYNTAX DATA**", ss.str());
1434 0 : _early_exit_param = "--syntax";
1435 0 : _ready_to_exit = true;
1436 0 : }
1437 62264 : else if (getParam<bool>("show_type"))
1438 : {
1439 10 : _perf_graph.disableLivePrint();
1440 :
1441 10 : Moose::out << "MooseApp Type: " << type() << std::endl;
1442 10 : _early_exit_param = "--show-type";
1443 10 : _ready_to_exit = true;
1444 : }
1445 62254 : else if (getParam<bool>("show_capabilities"))
1446 : {
1447 34 : _perf_graph.disableLivePrint();
1448 34 : outputMachineReadableData("show_capabilities",
1449 : "**START JSON DATA**\n",
1450 : "\n**END JSON DATA**",
1451 68 : Moose::Capabilities::getCapabilityRegistry().dump());
1452 34 : _ready_to_exit = true;
1453 : }
1454 62220 : else if (isParamValid("check_capabilities"))
1455 : {
1456 5 : _perf_graph.disableLivePrint();
1457 5 : const auto & capabilities = getParam<std::string>("check_capabilities");
1458 5 : auto [status, reason, doc] = Moose::Capabilities::getCapabilityRegistry().check(capabilities);
1459 5 : const bool pass = status == CapabilityUtils::CERTAIN_PASS;
1460 5 : _console << "Capabilities '" << capabilities << "' are " << (pass ? "" : "not ") << "fulfilled."
1461 5 : << std::endl;
1462 5 : _ready_to_exit = true;
1463 5 : if (!pass)
1464 0 : _exit_code = 77;
1465 5 : return;
1466 5 : }
1467 62215 : else if (!getInputFileNames().empty())
1468 : {
1469 62193 : if (isParamSetByUser("recover"))
1470 : {
1471 : // We need to set the flag manually here since the recover parameter is a string type (takes
1472 : // an optional filename)
1473 3841 : _recover = true;
1474 3841 : const auto & recover = getParam<std::string>("recover");
1475 3841 : if (recover.size())
1476 44 : _restart_recover_base = recover;
1477 : }
1478 :
1479 : // In the event that we've parsed once before already in MooseMain, we
1480 : // won't need to parse again
1481 62193 : if (!_parser->root())
1482 7 : _parser->parse();
1483 :
1484 62190 : _builder.build();
1485 :
1486 61987 : if (isParamValid("required_capabilities"))
1487 : {
1488 2841 : _perf_graph.disableLivePrint();
1489 :
1490 2841 : const auto required_capabilities = getParam<std::string>("required_capabilities");
1491 2841 : auto [status, reason, doc] =
1492 2841 : Moose::Capabilities::getCapabilityRegistry().check(required_capabilities);
1493 2841 : if (status < CapabilityUtils::UNKNOWN)
1494 : {
1495 50 : mooseInfo("Required capabilities '", required_capabilities, "' not fulfilled.");
1496 50 : _ready_to_exit = true;
1497 : // we use code 77 as "skip" in the Testharness
1498 50 : _exit_code = 77;
1499 50 : return;
1500 : }
1501 2791 : if (status == CapabilityUtils::UNKNOWN)
1502 4 : mooseError("Required capabilities '",
1503 : required_capabilities,
1504 : "' are not specific enough. A comparison test is performed on an undefined "
1505 : "capability. Disambiguate this requirement by adding an existence/non-existence "
1506 : "requirement. Example: 'unknown<1.2.3' should become 'unknown & unknown<1.2.3' "
1507 : "or '!unknown | unknown<1.2.3'");
1508 2887 : }
1509 :
1510 : // Lambda to check for mutually exclusive parameters
1511 : auto isExclusiveParamSetByUser =
1512 185889 : [this](const std::vector<std::string> & group, const std::string & param)
1513 : {
1514 178611 : auto is_set = isParamSetByUser(param);
1515 178611 : if (is_set)
1516 14556 : for (const auto & p : group)
1517 10917 : if (p != param && isParamSetByUser(p))
1518 0 : mooseError("Parameters '" + p + "' and '" + param +
1519 : "' are mutually exclusive. Please choose only one of them.");
1520 178611 : return is_set;
1521 61933 : };
1522 :
1523 : // The following parameters set the final task and so are mutually exclusive.
1524 : const std::vector<std::string> final_task_params = {
1525 247732 : "mesh_only", "split_mesh", "parse_neml2_only"};
1526 61933 : if (isExclusiveParamSetByUser(final_task_params, "mesh_only"))
1527 : {
1528 : // If we are looking to just check the input, there is no need to
1529 : // call MeshOnlyAction and generate a mesh
1530 3549 : if (_check_input)
1531 18 : _action_warehouse.setFinalTask("setup_mesh_complete");
1532 : else
1533 : {
1534 3531 : _syntax.registerTaskName("mesh_only", true);
1535 3531 : _syntax.addDependency("mesh_only", "setup_mesh_complete");
1536 3531 : _syntax.addDependency("determine_system_type", "mesh_only");
1537 3531 : _action_warehouse.setFinalTask("mesh_only");
1538 : }
1539 : }
1540 58384 : else if (isExclusiveParamSetByUser(final_task_params, "split_mesh"))
1541 : {
1542 90 : _split_mesh = true;
1543 90 : _syntax.registerTaskName("split_mesh", true);
1544 90 : _syntax.addDependency("split_mesh", "setup_mesh_complete");
1545 90 : _syntax.addDependency("determine_system_type", "split_mesh");
1546 90 : _action_warehouse.setFinalTask("split_mesh");
1547 : }
1548 58294 : else if (isExclusiveParamSetByUser(final_task_params, "parse_neml2_only"))
1549 : {
1550 0 : _syntax.registerTaskName("parse_neml2");
1551 0 : _syntax.addDependency("determine_system_type", "parse_neml2");
1552 0 : _action_warehouse.setFinalTask("parse_neml2");
1553 : }
1554 61933 : _action_warehouse.build();
1555 :
1556 : // Setup the AppFileBase for use by the Outputs or other systems that need output file info
1557 : {
1558 : // Extract the CommonOutputAction
1559 61933 : const auto common_actions = _action_warehouse.getActions<CommonOutputAction>();
1560 : mooseAssert(common_actions.size() <= 1, "Should not be more than one CommonOutputAction");
1561 61933 : const Action * common = common_actions.empty() ? nullptr : *common_actions.begin();
1562 :
1563 : // If file_base is set in CommonOutputAction through parsing input, obtain the file_base
1564 61933 : if (common && common->isParamValid("file_base"))
1565 : {
1566 13892 : _output_file_base = common->getParam<std::string>("file_base");
1567 13892 : _file_base_set_by_user = true;
1568 : }
1569 48041 : else if (isUltimateMaster())
1570 : {
1571 : // if this app is a master, we use the first input file name as the default file base.
1572 : // use proximate here because the input file is an absolute path
1573 36674 : const auto & base = getLastInputFileName();
1574 36674 : size_t pos = base.find_last_of('.');
1575 36674 : _output_file_base = base.substr(0, pos);
1576 : // Note: we did not append "_out" in the file base here because we do not want to
1577 : // have it in between the input file name and the object name for Output/*
1578 : // syntax.
1579 : }
1580 : // default file base for multiapps is set by MultiApp
1581 61933 : }
1582 61933 : }
1583 : // No input file provided but we have other arguments (so don't just show print usage)
1584 22 : else if (!isParamSetByUser("input_file") && _command_line->getArguments().size() > 2)
1585 : {
1586 : mooseAssert(getInputFileNames().empty(), "Should be empty");
1587 :
1588 8 : if (_check_input)
1589 4 : mooseError("You specified --check-input, but did not provide an input file. Add -i "
1590 : "<inputfile> to your command line.");
1591 :
1592 4 : mooseError("No input files specified. Add -i <inputfile> to your command line.");
1593 : }
1594 14 : else if (isParamValid("language_server") && getParam<bool>("language_server"))
1595 : {
1596 0 : _perf_graph.disableLivePrint();
1597 :
1598 : // Reset output to the buffer what was cached before it was turned it off
1599 0 : if (!Moose::out.rdbuf() && _output_buffer_cache)
1600 0 : Moose::out.rdbuf(_output_buffer_cache);
1601 :
1602 : // Start a language server that communicates using an iostream connection
1603 0 : MooseServer moose_server(*this);
1604 :
1605 0 : moose_server.run();
1606 :
1607 0 : _early_exit_param = "--language-server";
1608 0 : _ready_to_exit = true;
1609 0 : }
1610 :
1611 : else /* The catch-all case for bad options or missing options, etc. */
1612 : {
1613 14 : _command_line->printUsage();
1614 14 : _early_exit_param = "bad or missing";
1615 14 : _ready_to_exit = true;
1616 14 : _exit_code = 1;
1617 : }
1618 :
1619 62226 : Moose::out << std::flush;
1620 186185 : }
1621 :
1622 : const std::vector<std::string> &
1623 144512 : MooseApp::getInputFileNames() const
1624 : {
1625 : mooseAssert(_parser, "Parser is not set");
1626 144512 : return _parser->getInputFileNames();
1627 : }
1628 :
1629 : const std::string &
1630 36674 : MooseApp::getLastInputFileName() const
1631 : {
1632 : mooseAssert(_parser, "Parser is not set");
1633 36674 : return _parser->getLastInputFileName();
1634 : }
1635 :
1636 : std::string
1637 139937 : MooseApp::getOutputFileBase(bool for_non_moose_build_output) const
1638 : {
1639 139937 : if (_file_base_set_by_user || for_non_moose_build_output || _multiapp_level)
1640 45124 : return _output_file_base;
1641 : else
1642 94813 : return _output_file_base + "_out";
1643 : }
1644 :
1645 : void
1646 11367 : MooseApp::setOutputFileBase(const std::string & output_file_base)
1647 : {
1648 11367 : _output_file_base = output_file_base;
1649 :
1650 : // Reset the file base in the outputs
1651 11367 : _output_warehouse.resetFileBase();
1652 :
1653 : // Reset the file base in multiapps (if they have been constructed yet)
1654 11367 : if (getExecutioner())
1655 0 : for (auto & multi_app : feProblem().getMultiAppWarehouse().getObjects())
1656 0 : multi_app->setAppOutputFileBase();
1657 :
1658 11367 : _file_base_set_by_user = true;
1659 11367 : }
1660 :
1661 : void
1662 62307 : MooseApp::runInputFile()
1663 : {
1664 62307 : TIME_SECTION("runInputFile", 3);
1665 :
1666 : // If early exit param has been set, then just return
1667 62307 : if (_ready_to_exit)
1668 381 : return;
1669 :
1670 61926 : _action_warehouse.executeAllActions();
1671 :
1672 59046 : if (isParamSetByUser("mesh_only"))
1673 : {
1674 3037 : _early_exit_param = "--mesh-only";
1675 3037 : _ready_to_exit = true;
1676 : }
1677 56009 : else if (isParamSetByUser("split_mesh"))
1678 : {
1679 90 : _early_exit_param = "--split-mesh";
1680 90 : _ready_to_exit = true;
1681 : }
1682 55919 : else if (isParamSetByUser("parse_neml2_only"))
1683 : {
1684 0 : _early_exit_param = "--parse-neml2-only";
1685 0 : _ready_to_exit = true;
1686 : }
1687 55919 : else if (getParam<bool>("list_constructed_objects"))
1688 : {
1689 : // TODO: ask multiapps for their constructed objects
1690 0 : _early_exit_param = "--list-constructed-objects";
1691 0 : _ready_to_exit = true;
1692 0 : std::stringstream ss;
1693 0 : for (const auto & obj : _factory.getConstructedObjects())
1694 0 : ss << obj << '\n';
1695 0 : outputMachineReadableData(
1696 0 : "list_constructed_objects", "**START OBJECT DATA**\n", "\n**END OBJECT DATA**", ss.str());
1697 0 : }
1698 59444 : }
1699 :
1700 : void
1701 54214 : MooseApp::errorCheck()
1702 : {
1703 54214 : bool warn = _enable_unused_check == WARN_UNUSED;
1704 54214 : bool err = _enable_unused_check == ERROR_UNUSED;
1705 :
1706 54214 : _builder.errorCheck(*_comm, warn, err);
1707 :
1708 : // Return early for mesh only mode, since we want error checking to run even though
1709 : // an executor is not created for this case
1710 54179 : if (isParamSetByUser("mesh_only"))
1711 14 : return;
1712 :
1713 54165 : if (!_executor.get() && !_executioner.get())
1714 : {
1715 0 : if (!_early_exit_param.empty())
1716 : {
1717 : mooseAssert(_check_input,
1718 : "Something went wrong, we should only get here if _check_input is true.");
1719 0 : mooseError(
1720 : "Incompatible command line arguments provided. --check-input cannot be called with ",
1721 0 : _early_exit_param,
1722 : ".");
1723 : }
1724 : // We should never get here
1725 0 : mooseError("The Executor is being called without being initialized. This is likely "
1726 : "caused by "
1727 : "incompatible command line arguments");
1728 : }
1729 :
1730 54165 : auto apps = feProblem().getMultiAppWarehouse().getObjects();
1731 60822 : for (auto app : apps)
1732 16832 : for (unsigned int i = 0; i < app->numLocalApps(); i++)
1733 16832 : app->localApp(i)->errorCheck();
1734 54161 : }
1735 :
1736 : void
1737 48063 : MooseApp::executeExecutioner()
1738 : {
1739 48063 : TIME_SECTION("executeExecutioner", 3);
1740 :
1741 : // If ready to exit has been set, then just return
1742 48063 : if (_ready_to_exit)
1743 3490 : return;
1744 :
1745 : // run the simulation
1746 44573 : if (_use_executor && _executor)
1747 : {
1748 20 : LibmeshPetscCall(Moose::PetscSupport::petscSetupOutput(_command_line.get()));
1749 20 : _executor->init();
1750 20 : errorCheck();
1751 20 : auto result = _executor->exec();
1752 20 : if (!result.convergedAll())
1753 0 : mooseError(result.str());
1754 20 : }
1755 44553 : else if (_executioner)
1756 : {
1757 44553 : LibmeshPetscCall(Moose::PetscSupport::petscSetupOutput(_command_line.get()));
1758 44553 : _executioner->init();
1759 43992 : errorCheck();
1760 43961 : _executioner->execute();
1761 43466 : if (!_executioner->lastSolveConverged())
1762 217 : setExitCode(1);
1763 : }
1764 : else
1765 0 : mooseError("No executioner was specified (go fix your input file)");
1766 46976 : }
1767 :
1768 : bool
1769 1348461 : MooseApp::isRecovering() const
1770 : {
1771 1348461 : return _recover;
1772 : }
1773 :
1774 : bool
1775 528407 : MooseApp::isRestarting() const
1776 : {
1777 528407 : return _restart;
1778 : }
1779 :
1780 : bool
1781 174763 : MooseApp::isSplitMesh() const
1782 : {
1783 174763 : return _split_mesh;
1784 : }
1785 :
1786 : bool
1787 0 : MooseApp::hasRestartRecoverFileBase() const
1788 : {
1789 0 : return !_restart_recover_base.empty();
1790 : }
1791 :
1792 : bool
1793 0 : MooseApp::hasRecoverFileBase() const
1794 : {
1795 0 : mooseDeprecated("MooseApp::hasRecoverFileBase is deprecated, use "
1796 : "MooseApp::hasRestartRecoverFileBase() instead.");
1797 0 : return !_restart_recover_base.empty();
1798 : }
1799 :
1800 : void
1801 867775 : MooseApp::registerRestartableNameWithFilter(const std::string & name,
1802 : Moose::RESTARTABLE_FILTER filter)
1803 : {
1804 : using Moose::RESTARTABLE_FILTER;
1805 867775 : switch (filter)
1806 : {
1807 867775 : case RESTARTABLE_FILTER::RECOVERABLE:
1808 867775 : _recoverable_data_names.insert(name);
1809 867775 : break;
1810 0 : default:
1811 0 : mooseError("Unknown filter");
1812 : }
1813 867775 : }
1814 :
1815 : std::vector<std::filesystem::path>
1816 10607 : MooseApp::backup(const std::filesystem::path & folder_base)
1817 : {
1818 10607 : TIME_SECTION("backup", 2, "Backing Up Application to File");
1819 :
1820 10607 : preBackup();
1821 :
1822 10607 : RestartableDataWriter writer(*this, _restartable_data);
1823 21210 : return writer.write(folder_base);
1824 10603 : }
1825 :
1826 : std::unique_ptr<Backup>
1827 31232 : MooseApp::backup()
1828 : {
1829 31232 : TIME_SECTION("backup", 2, "Backing Up Application");
1830 :
1831 31232 : RestartableDataWriter writer(*this, _restartable_data);
1832 :
1833 31232 : preBackup();
1834 :
1835 31232 : auto backup = std::make_unique<Backup>();
1836 31232 : writer.write(*backup->header, *backup->data);
1837 :
1838 62464 : return backup;
1839 31232 : }
1840 :
1841 : void
1842 3317 : MooseApp::restore(const std::filesystem::path & folder_base, const bool for_restart)
1843 : {
1844 3317 : TIME_SECTION("restore", 2, "Restoring Application from File");
1845 :
1846 3317 : const DataNames filter_names = for_restart ? getRecoverableData() : DataNames{};
1847 :
1848 3317 : _rd_reader.setInput(folder_base);
1849 3317 : _rd_reader.restore(filter_names);
1850 :
1851 3276 : postRestore(for_restart);
1852 3276 : }
1853 :
1854 : void
1855 9905 : MooseApp::restore(std::unique_ptr<Backup> backup, const bool for_restart)
1856 : {
1857 9905 : TIME_SECTION("restore", 2, "Restoring Application");
1858 :
1859 9905 : const DataNames filter_names = for_restart ? getRecoverableData() : DataNames{};
1860 :
1861 9905 : if (!backup)
1862 0 : mooseError("MooseApp::restore(): Provided backup is not initialized");
1863 :
1864 9905 : auto header = std::move(backup->header);
1865 : mooseAssert(header, "Header not available");
1866 :
1867 9905 : auto data = std::move(backup->data);
1868 : mooseAssert(data, "Data not available");
1869 :
1870 9905 : _rd_reader.setInput(std::move(header), std::move(data));
1871 9905 : _rd_reader.restore(filter_names);
1872 :
1873 9905 : postRestore(for_restart);
1874 9905 : }
1875 :
1876 : void
1877 989 : MooseApp::restoreFromInitialBackup(const bool for_restart)
1878 : {
1879 : mooseAssert(hasInitialBackup(), "Missing initial backup");
1880 989 : restore(std::move(*_initial_backup), for_restart);
1881 989 : }
1882 :
1883 : std::unique_ptr<Backup>
1884 13181 : MooseApp::finalizeRestore()
1885 : {
1886 13181 : if (!_rd_reader.isRestoring())
1887 0 : mooseError("MooseApp::finalizeRestore(): Not currently restoring");
1888 :
1889 : // This gives us access to the underlying streams so that we can return it if needed
1890 13181 : auto input_streams = _rd_reader.clear();
1891 :
1892 13181 : std::unique_ptr<Backup> backup;
1893 :
1894 : // Give them back a backup if this restore started from a Backup, in which case
1895 : // the two streams in the Backup are formed into StringInputStreams
1896 13181 : if (auto header_string_input = dynamic_cast<StringInputStream *>(input_streams.header.get()))
1897 : {
1898 9905 : auto data_string_input = dynamic_cast<StringInputStream *>(input_streams.data.get());
1899 : mooseAssert(data_string_input, "Should also be a string input");
1900 :
1901 9905 : auto header_sstream = header_string_input->release();
1902 : mooseAssert(header_sstream, "Header not available");
1903 :
1904 9905 : auto data_sstream = data_string_input->release();
1905 : mooseAssert(data_sstream, "Data not available");
1906 :
1907 9905 : backup = std::make_unique<Backup>();
1908 9905 : backup->header = std::move(header_sstream);
1909 9905 : backup->data = std::move(data_sstream);
1910 9905 : }
1911 :
1912 26362 : return backup;
1913 13181 : }
1914 :
1915 : void
1916 721 : MooseApp::setCheckUnusedFlag(bool warn_is_error)
1917 : {
1918 721 : _enable_unused_check = warn_is_error ? ERROR_UNUSED : WARN_UNUSED;
1919 721 : }
1920 :
1921 : void
1922 0 : MooseApp::disableCheckUnusedFlag()
1923 : {
1924 0 : _enable_unused_check = OFF;
1925 0 : }
1926 :
1927 : FEProblemBase &
1928 10187408 : MooseApp::feProblem() const
1929 : {
1930 : mooseAssert(_executor.get() || _executioner.get(), "No executioner yet, calling too early!");
1931 10187408 : return _executor.get() ? _executor->feProblem() : _executioner->feProblem();
1932 : }
1933 :
1934 : void
1935 60 : MooseApp::addExecutor(const std::string & type,
1936 : const std::string & name,
1937 : const InputParameters & params)
1938 : {
1939 60 : std::shared_ptr<Executor> executor = _factory.create<Executor>(type, name, params);
1940 :
1941 60 : if (_executors.count(executor->name()) > 0)
1942 0 : mooseError("an executor with name '", executor->name(), "' already exists");
1943 60 : _executors[executor->name()] = executor;
1944 60 : }
1945 :
1946 : void
1947 68 : MooseApp::addExecutorParams(const std::string & type,
1948 : const std::string & name,
1949 : const InputParameters & params)
1950 : {
1951 68 : _executor_params[name] = std::make_pair(type, std::make_unique<InputParameters>(params));
1952 68 : }
1953 :
1954 : Parser &
1955 1369956 : MooseApp::parser()
1956 : {
1957 : mooseAssert(_parser, "Not set");
1958 1369956 : return *_parser;
1959 : }
1960 :
1961 : void
1962 72 : MooseApp::recursivelyCreateExecutors(const std::string & current_executor_name,
1963 : std::list<std::string> & possible_roots,
1964 : std::list<std::string> & current_branch)
1965 : {
1966 : // Did we already make this one?
1967 72 : if (_executors.find(current_executor_name) != _executors.end())
1968 0 : return;
1969 :
1970 : // Is this one already on the current branch (i.e. there is a cycle)
1971 72 : if (std::find(current_branch.begin(), current_branch.end(), current_executor_name) !=
1972 144 : current_branch.end())
1973 : {
1974 4 : std::stringstream exec_names_string;
1975 :
1976 4 : auto branch_it = current_branch.begin();
1977 :
1978 4 : exec_names_string << *branch_it++;
1979 :
1980 8 : for (; branch_it != current_branch.end(); ++branch_it)
1981 4 : exec_names_string << ", " << *branch_it;
1982 :
1983 4 : exec_names_string << ", " << current_executor_name;
1984 :
1985 4 : mooseError("Executor cycle detected: ", exec_names_string.str());
1986 0 : }
1987 :
1988 68 : current_branch.push_back(current_executor_name);
1989 :
1990 : // Build the dependencies first
1991 68 : const auto & params = *_executor_params[current_executor_name].second;
1992 :
1993 3096 : for (const auto & param : params)
1994 : {
1995 3036 : if (params.have_parameter<ExecutorName>(param.first))
1996 : {
1997 132 : const auto & dependency_name = params.get<ExecutorName>(param.first);
1998 :
1999 132 : possible_roots.remove(dependency_name);
2000 :
2001 132 : if (!dependency_name.empty())
2002 40 : recursivelyCreateExecutors(dependency_name, possible_roots, current_branch);
2003 : }
2004 : }
2005 :
2006 : // Add this Executor
2007 60 : const auto & type = _executor_params[current_executor_name].first;
2008 60 : addExecutor(type, current_executor_name, params);
2009 :
2010 60 : current_branch.pop_back();
2011 : }
2012 :
2013 : void
2014 57637 : MooseApp::createExecutors()
2015 : {
2016 : // Do we have any?
2017 57637 : if (_executor_params.empty())
2018 57609 : return;
2019 :
2020 : // Holds the names of Executors that may be the root executor
2021 28 : std::list<std::string> possibly_root;
2022 :
2023 : // What is already built
2024 28 : std::map<std::string, bool> already_built;
2025 :
2026 : // The Executors that are currently candidates for being roots
2027 28 : std::list<std::string> possible_roots;
2028 :
2029 : // The current line of dependencies - used for finding cycles
2030 28 : std::list<std::string> current_branch;
2031 :
2032 : // Build the NullExecutor
2033 : {
2034 28 : auto params = _factory.getValidParams("NullExecutor");
2035 28 : _null_executor = _factory.create<NullExecutor>("NullExecutor", "_null_executor", params);
2036 28 : }
2037 :
2038 84 : for (const auto & params_entry : _executor_params)
2039 : {
2040 60 : const auto & name = params_entry.first;
2041 :
2042 : // Did we already make this one?
2043 60 : if (_executors.find(name) != _executors.end())
2044 28 : continue;
2045 :
2046 32 : possible_roots.emplace_back(name);
2047 :
2048 32 : recursivelyCreateExecutors(name, possible_roots, current_branch);
2049 : }
2050 :
2051 : // If there is more than one possible root - error
2052 24 : if (possible_roots.size() > 1)
2053 : {
2054 4 : auto root_string_it = possible_roots.begin();
2055 :
2056 4 : std::stringstream roots_string;
2057 :
2058 4 : roots_string << *root_string_it++;
2059 :
2060 8 : for (; root_string_it != possible_roots.end(); ++root_string_it)
2061 4 : roots_string << ", " << *root_string_it;
2062 :
2063 4 : mooseError("Multiple Executor roots found: ", roots_string.str());
2064 0 : }
2065 :
2066 : // Set the root executor
2067 20 : _executor = _executors[possible_roots.front()];
2068 20 : }
2069 :
2070 : Executor &
2071 28 : MooseApp::getExecutor(const std::string & name, bool fail_if_not_found)
2072 : {
2073 28 : auto it = _executors.find(name);
2074 :
2075 28 : if (it != _executors.end())
2076 28 : return *it->second;
2077 :
2078 0 : if (fail_if_not_found)
2079 0 : mooseError("Executor not found: ", name);
2080 :
2081 0 : return *_null_executor;
2082 : }
2083 :
2084 : Executioner *
2085 3518351 : MooseApp::getExecutioner() const
2086 : {
2087 3518351 : return _executioner.get() ? _executioner.get() : _executor.get();
2088 : }
2089 :
2090 : void
2091 59391 : MooseApp::setErrorOverridden()
2092 : {
2093 59391 : _error_overridden = true;
2094 59391 : }
2095 :
2096 : void
2097 51176 : MooseApp::run()
2098 : {
2099 51176 : TIME_SECTION("run", 3);
2100 51176 : if (getParam<bool>("show_docs"))
2101 : {
2102 0 : auto binname = appBinaryName();
2103 0 : if (binname == "")
2104 0 : mooseError("could not locate installed tests to run (unresolved binary/app name)");
2105 0 : auto docspath = MooseUtils::docsDir(binname);
2106 0 : if (docspath == "")
2107 0 : mooseError("no installed documentation found");
2108 :
2109 0 : auto docmsgfile = MooseUtils::pathjoin(docspath, "docmsg.txt");
2110 0 : std::string docmsg = "file://" + MooseUtils::realpath(docspath) + "/index.html";
2111 0 : if (MooseUtils::pathExists(docmsgfile) && MooseUtils::checkFileReadable(docmsgfile))
2112 : {
2113 0 : std::ifstream ifs(docmsgfile);
2114 : std::string content((std::istreambuf_iterator<char>(ifs)),
2115 0 : (std::istreambuf_iterator<char>()));
2116 0 : content.replace(content.find("$LOCAL_SITE_HOME"), content.length(), docmsg);
2117 0 : docmsg = content;
2118 0 : }
2119 :
2120 0 : Moose::out << docmsg << "\n";
2121 0 : _early_exit_param = "--docs";
2122 0 : _ready_to_exit = true;
2123 0 : return;
2124 0 : }
2125 :
2126 51176 : if (showInputs() || copyInputs() || runInputs())
2127 : {
2128 21 : _early_exit_param = "--show-input, --copy-inputs, or --run";
2129 21 : _ready_to_exit = true;
2130 21 : return;
2131 : }
2132 :
2133 : try
2134 : {
2135 51148 : TIME_SECTION("setup", 2, "Setting Up");
2136 51148 : setupOptions();
2137 50922 : runInputFile();
2138 48111 : }
2139 21 : catch (std::exception & err)
2140 : {
2141 21 : mooseError(err.what());
2142 5 : }
2143 :
2144 48090 : if (!_check_input)
2145 : {
2146 48063 : TIME_SECTION("execute", 2, "Executing");
2147 48063 : executeExecutioner();
2148 46976 : }
2149 : else
2150 : {
2151 27 : errorCheck();
2152 : // Output to stderr, so it is easier for peacock to get the result
2153 23 : Moose::err << "Syntax OK" << std::endl;
2154 : }
2155 47025 : }
2156 :
2157 : bool
2158 51176 : MooseApp::showInputs() const
2159 : {
2160 51176 : if (getParam<bool>("show_inputs"))
2161 : {
2162 7 : const auto show_inputs_syntax = _pars.getCommandLineMetadata("show_inputs").switches;
2163 7 : std::vector<std::string> dirs;
2164 7 : const auto installable_inputs = getInstallableInputs();
2165 :
2166 7 : if (installable_inputs == "")
2167 : {
2168 : Moose::out
2169 : << "Show inputs has not been overriden in this application.\nContact the developers of "
2170 0 : "this appication and request that they override \"MooseApp::getInstallableInputs\".\n";
2171 : }
2172 : else
2173 : {
2174 : mooseAssert(!show_inputs_syntax.empty(), "show_inputs sytnax should not be empty");
2175 :
2176 7 : MooseUtils::tokenize(installable_inputs, dirs, 1, " ");
2177 7 : Moose::out << "The following directories are installable into a user-writeable directory:\n\n"
2178 7 : << installable_inputs << '\n'
2179 7 : << "\nTo install one or more directories of inputs, execute the binary with the \""
2180 7 : << show_inputs_syntax[0] << "\" flag. e.g.:\n$ "
2181 14 : << _command_line->getExecutableName() << ' ' << show_inputs_syntax[0] << ' '
2182 7 : << dirs[0] << '\n';
2183 : }
2184 7 : return true;
2185 7 : }
2186 51169 : return false;
2187 : }
2188 :
2189 : std::string
2190 0 : MooseApp::getInstallableInputs() const
2191 : {
2192 0 : return "tests";
2193 : }
2194 :
2195 : bool
2196 51169 : MooseApp::copyInputs()
2197 : {
2198 51169 : if (isParamSetByUser("copy_inputs"))
2199 : {
2200 14 : if (comm().size() > 1)
2201 0 : mooseError("The --copy-inputs option should not be ran in parallel");
2202 :
2203 : // Get command line argument following --copy-inputs on command line
2204 14 : auto dir_to_copy = getParam<std::string>("copy_inputs");
2205 :
2206 14 : if (dir_to_copy.empty())
2207 0 : mooseError("Error retrieving directory to copy");
2208 14 : if (dir_to_copy.back() != '/')
2209 14 : dir_to_copy += '/';
2210 :
2211 : // This binary name is the actual binary. That is, if we called a symlink it'll
2212 : // be the name of what the symlink points to
2213 14 : auto binname = appBinaryName();
2214 14 : if (binname == "")
2215 0 : mooseError("could not locate installed tests to run (unresolved binary/app name)");
2216 :
2217 : auto src_dir = MooseUtils::installedInputsDir(
2218 : binname,
2219 : dir_to_copy,
2220 28 : "Rerun binary with " + _pars.getCommandLineMetadata("show_inputs").switches[0] +
2221 14 : " to get a list of installable directories.");
2222 :
2223 : // Use the command line here because if we have a symlink to another binary,
2224 : // we want to dump into a directory that is named after the symlink not the true binary
2225 14 : auto dst_dir = _command_line->getExecutableNameBase() + "/" + dir_to_copy;
2226 14 : auto cmdname = _command_line->getExecutableName();
2227 14 : if (cmdname.find_first_of("/") != std::string::npos)
2228 0 : cmdname = cmdname.substr(cmdname.find_first_of("/") + 1, std::string::npos);
2229 :
2230 14 : if (MooseUtils::pathExists(dst_dir))
2231 7 : mooseError(
2232 : "The directory \"./",
2233 : dst_dir,
2234 : "\" already exists.\nTo update/recopy the contents of this directory, rename (\"mv ",
2235 : dst_dir,
2236 : " new_dir_name\") or remove (\"rm -r ",
2237 : dst_dir,
2238 : "\") the existing directory.\nThen re-run \"",
2239 : cmdname,
2240 : " --copy-inputs ",
2241 : dir_to_copy,
2242 : "\".");
2243 :
2244 7 : std::string cmd = "mkdir -p " + dst_dir + "; rsync -av " + src_dir + " " + dst_dir;
2245 :
2246 7 : TIME_SECTION("copy_inputs", 2, "Copying Inputs");
2247 :
2248 : mooseAssert(comm().size() == 1, "Should be run in serial");
2249 7 : const auto return_value = system(cmd.c_str());
2250 7 : if (!WIFEXITED(return_value))
2251 0 : mooseError("Process exited unexpectedly");
2252 7 : setExitCode(WEXITSTATUS(return_value));
2253 7 : if (exitCode() == 0)
2254 7 : Moose::out << "Directory successfully copied into ./" << dst_dir << '\n';
2255 7 : return true;
2256 7 : }
2257 51155 : return false;
2258 : }
2259 :
2260 : bool
2261 51155 : MooseApp::runInputs()
2262 : {
2263 51155 : if (isParamSetByUser("run"))
2264 : {
2265 7 : if (comm().size() > 1)
2266 0 : mooseError("The --run option should not be ran in parallel");
2267 :
2268 : // Pass everything after --run on the cli to the TestHarness
2269 7 : const auto find_run_it = std::as_const(*_command_line).findCommandLineParam("run");
2270 7 : const auto & cl_entries = std::as_const(*_command_line).getEntries();
2271 : mooseAssert(find_run_it != cl_entries.end(), "Didn't find the option");
2272 7 : std::string test_args;
2273 14 : for (auto it = std::next(find_run_it); it != cl_entries.end(); ++it)
2274 14 : for (const auto & arg : it->raw_args)
2275 : {
2276 7 : test_args += " " + arg;
2277 7 : libMesh::add_command_line_name(arg);
2278 : }
2279 :
2280 7 : auto working_dir = MooseUtils::getCurrentWorkingDir();
2281 7 : if (MooseUtils::findTestRoot() == "")
2282 : {
2283 0 : auto bin_name = appBinaryName();
2284 0 : if (bin_name == "")
2285 0 : mooseError("Could not locate binary name relative to installed location");
2286 :
2287 0 : auto cmd_name = Moose::getExecutableName();
2288 0 : mooseError(
2289 : "Could not locate installed tests from the current working directory:",
2290 : working_dir,
2291 : ".\nMake sure you are executing this command from within a writable installed inputs ",
2292 : "directory.\nRun \"",
2293 : cmd_name,
2294 : " --copy-inputs <dir>\" to copy the contents of <dir> to a \"./",
2295 : bin_name,
2296 : "_<dir>\" directory.\nChange into that directory and try \"",
2297 : cmd_name,
2298 : " --run <dir>\" again.");
2299 0 : }
2300 :
2301 : // Set this application as the app name for the moose_test_runner script that we're running
2302 7 : setenv("MOOSE_TEST_RUNNER_APP_NAME", appBinaryName().c_str(), true);
2303 :
2304 7 : const std::string cmd = MooseUtils::runTestsExecutable() + test_args;
2305 7 : Moose::out << "Working Directory: " << working_dir << "\nRunning Command: " << cmd << std::endl;
2306 : mooseAssert(comm().size() == 1, "Should be run in serial");
2307 7 : const auto return_value = system(cmd.c_str());
2308 7 : if (!WIFEXITED(return_value))
2309 0 : mooseError("Process exited unexpectedly");
2310 7 : setExitCode(WEXITSTATUS(return_value));
2311 7 : return true;
2312 7 : }
2313 :
2314 51148 : return false;
2315 : }
2316 :
2317 : void
2318 3078 : MooseApp::setOutputPosition(const Point & p)
2319 : {
2320 3078 : _output_position_set = true;
2321 3078 : _output_position = p;
2322 3078 : _output_warehouse.meshChanged();
2323 :
2324 3078 : if (_executioner.get())
2325 72 : _executioner->parentOutputPositionChanged();
2326 3078 : }
2327 :
2328 : std::list<std::string>
2329 2892 : MooseApp::getCheckpointDirectories() const
2330 : {
2331 : // Storage for the directory names
2332 2892 : std::list<std::string> checkpoint_dirs;
2333 :
2334 : // Add the directories added with Outputs/checkpoint=true input syntax
2335 2892 : checkpoint_dirs.push_back(getOutputFileBase() + "_cp");
2336 :
2337 : // Add the directories from any existing checkpoint output objects
2338 2892 : const auto & actions = _action_warehouse.getActionListByName("add_output");
2339 17514 : for (const auto & action : actions)
2340 : {
2341 : // Get the parameters from the MooseObjectAction
2342 14622 : MooseObjectAction * moose_object_action = dynamic_cast<MooseObjectAction *>(action);
2343 14622 : if (!moose_object_action)
2344 2973 : continue;
2345 :
2346 11649 : const InputParameters & params = moose_object_action->getObjectParams();
2347 11649 : if (moose_object_action->getParam<std::string>("type") == "Checkpoint")
2348 : {
2349 : // Unless file_base was explicitly set by user, we cannot rely on it, as it will be changed
2350 : // later
2351 : const std::string cp_dir =
2352 32 : _file_base_set_by_user ? params.get<std::string>("file_base")
2353 36 : : (getOutputFileBase(true) + "_" + moose_object_action->name());
2354 34 : checkpoint_dirs.push_back(cp_dir + "_cp");
2355 34 : }
2356 : }
2357 2892 : return checkpoint_dirs;
2358 0 : }
2359 :
2360 : std::list<std::string>
2361 2892 : MooseApp::getCheckpointFiles() const
2362 : {
2363 2892 : auto checkpoint_dirs = getCheckpointDirectories();
2364 5784 : return MooseUtils::getFilesInDirs(checkpoint_dirs, false);
2365 2892 : }
2366 :
2367 : void
2368 3793 : MooseApp::setStartTime(Real time)
2369 : {
2370 3793 : _start_time_set = true;
2371 3793 : _start_time = time;
2372 3793 : }
2373 :
2374 : std::string
2375 40 : MooseApp::getFileName(bool stripLeadingPath) const
2376 : {
2377 40 : return _builder.getPrimaryFileName(stripLeadingPath);
2378 : }
2379 :
2380 : OutputWarehouse &
2381 30226937 : MooseApp::getOutputWarehouse()
2382 : {
2383 30226937 : return _output_warehouse;
2384 : }
2385 :
2386 : const OutputWarehouse &
2387 82267 : MooseApp::getOutputWarehouse() const
2388 : {
2389 82267 : return _output_warehouse;
2390 : }
2391 :
2392 : std::string
2393 10 : MooseApp::appNameToLibName(const std::string & app_name) const
2394 : {
2395 10 : std::string library_name(app_name);
2396 :
2397 : // Strip off the App part (should always be the last 3 letters of the name)
2398 10 : size_t pos = library_name.find("App");
2399 10 : if (pos != library_name.length() - 3)
2400 0 : mooseError("Invalid application name: ", library_name);
2401 10 : library_name.erase(pos);
2402 :
2403 : // Now get rid of the camel case, prepend lib, and append the method and suffix
2404 20 : return std::string("lib") + MooseUtils::camelCaseToUnderscore(library_name) + '-' +
2405 20 : QUOTE(METHOD) + ".la";
2406 10 : }
2407 :
2408 : std::string
2409 0 : MooseApp::libNameToAppName(const std::string & library_name) const
2410 : {
2411 0 : std::string app_name(library_name);
2412 :
2413 : // Strip off the leading "lib" and trailing ".la"
2414 0 : if (pcrecpp::RE("lib(.+?)(?:-\\w+)?\\.la").Replace("\\1", &app_name) == 0)
2415 0 : mooseError("Invalid library name: ", app_name);
2416 :
2417 0 : return MooseUtils::underscoreToCamelCase(app_name, true);
2418 0 : }
2419 :
2420 : RestartableDataValue &
2421 3506250 : MooseApp::registerRestartableData(std::unique_ptr<RestartableDataValue> data,
2422 : THREAD_ID tid,
2423 : bool read_only,
2424 : const RestartableDataMapName & metaname)
2425 : {
2426 3506250 : if (!metaname.empty() && tid != 0)
2427 0 : mooseError(
2428 : "The meta data storage for '", metaname, "' is not threaded, so the tid must be zero.");
2429 :
2430 : mooseAssert(metaname.empty() ||
2431 : _restartable_meta_data.find(metaname) != _restartable_meta_data.end(),
2432 : "The desired meta data name does not exist: " + metaname);
2433 :
2434 : // Select the data store for saving this piece of restartable data (mesh or everything else)
2435 : auto & data_map =
2436 3506250 : metaname.empty() ? _restartable_data[tid] : _restartable_meta_data[metaname].first;
2437 :
2438 3506250 : RestartableDataValue * stored_data = data_map.findData(data->name());
2439 3506250 : if (stored_data)
2440 : {
2441 1169882 : if (data->typeId() != stored_data->typeId())
2442 0 : mooseError("Type mismatch found in RestartableData registration of '",
2443 0 : data->name(),
2444 : "'\n\n Stored type: ",
2445 0 : stored_data->type(),
2446 : "\n New type: ",
2447 0 : data->type());
2448 : }
2449 : else
2450 2336368 : stored_data = &data_map.addData(std::move(data));
2451 :
2452 3506250 : if (!read_only)
2453 2336360 : stored_data->setDeclared({});
2454 :
2455 3506250 : return *stored_data;
2456 : }
2457 :
2458 : RestartableDataValue &
2459 0 : MooseApp::registerRestartableData(const std::string & libmesh_dbg_var(name),
2460 : std::unique_ptr<RestartableDataValue> data,
2461 : THREAD_ID tid,
2462 : bool read_only,
2463 : const RestartableDataMapName & metaname)
2464 : {
2465 0 : mooseDeprecated("The use of MooseApp::registerRestartableData with a data name is "
2466 : "deprecated.\n\nUse the call without a name instead.");
2467 :
2468 : mooseAssert(name == data->name(), "Inconsistent name");
2469 0 : return registerRestartableData(std::move(data), tid, read_only, metaname);
2470 : }
2471 :
2472 : bool
2473 182471 : MooseApp::hasRestartableMetaData(const std::string & name,
2474 : const RestartableDataMapName & metaname) const
2475 : {
2476 182471 : auto it = _restartable_meta_data.find(metaname);
2477 182471 : if (it == _restartable_meta_data.end())
2478 0 : return false;
2479 182471 : return it->second.first.hasData(name);
2480 : }
2481 :
2482 : RestartableDataValue &
2483 1098 : MooseApp::getRestartableMetaData(const std::string & name,
2484 : const RestartableDataMapName & metaname,
2485 : THREAD_ID tid)
2486 : {
2487 1098 : if (tid != 0)
2488 0 : mooseError(
2489 : "The meta data storage for '", metaname, "' is not threaded, so the tid must be zero.");
2490 :
2491 : // Get metadata reference from RestartableDataMap and return a (non-const) reference to its value
2492 1098 : auto & restartable_data_map = getRestartableDataMap(metaname);
2493 1098 : RestartableDataValue * const data = restartable_data_map.findData(name);
2494 1098 : if (!data)
2495 0 : mooseError("Unable to find RestartableDataValue object with name " + name +
2496 : " in RestartableDataMap");
2497 :
2498 1098 : return *data;
2499 : }
2500 :
2501 : void
2502 6299 : MooseApp::possiblyLoadRestartableMetaData(const RestartableDataMapName & name,
2503 : const std::filesystem::path & folder_base)
2504 : {
2505 6299 : const auto & map_name = getRestartableDataMapName(name);
2506 6299 : const auto meta_data_folder_base = metaDataFolderBase(folder_base, map_name);
2507 6299 : if (RestartableDataReader::isAvailable(meta_data_folder_base))
2508 : {
2509 3222 : RestartableDataReader reader(*this, getRestartableDataMap(name), forceRestart());
2510 3222 : reader.setErrorOnLoadWithDifferentNumberOfProcessors(false);
2511 3222 : reader.setInput(meta_data_folder_base);
2512 3222 : reader.restore();
2513 3222 : }
2514 6299 : }
2515 :
2516 : void
2517 2928 : MooseApp::loadRestartableMetaData(const std::filesystem::path & folder_base)
2518 : {
2519 5856 : for (const auto & name_map_pair : _restartable_meta_data)
2520 2928 : possiblyLoadRestartableMetaData(name_map_pair.first, folder_base);
2521 2928 : }
2522 :
2523 : std::vector<std::filesystem::path>
2524 9572 : MooseApp::writeRestartableMetaData(const RestartableDataMapName & name,
2525 : const std::filesystem::path & folder_base)
2526 : {
2527 9572 : if (processor_id() != 0)
2528 0 : mooseError("MooseApp::writeRestartableMetaData(): Should only run on processor 0");
2529 :
2530 9572 : const auto & map_name = getRestartableDataMapName(name);
2531 9572 : const auto meta_data_folder_base = metaDataFolderBase(folder_base, map_name);
2532 :
2533 9572 : RestartableDataWriter writer(*this, getRestartableDataMap(name));
2534 19144 : return writer.write(meta_data_folder_base);
2535 9572 : }
2536 :
2537 : std::vector<std::filesystem::path>
2538 9508 : MooseApp::writeRestartableMetaData(const std::filesystem::path & folder_base)
2539 : {
2540 9508 : std::vector<std::filesystem::path> paths;
2541 :
2542 9508 : if (processor_id() == 0)
2543 19016 : for (const auto & name_map_pair : _restartable_meta_data)
2544 : {
2545 9508 : const auto map_paths = writeRestartableMetaData(name_map_pair.first, folder_base);
2546 9508 : paths.insert(paths.end(), map_paths.begin(), map_paths.end());
2547 9508 : }
2548 :
2549 9508 : return paths;
2550 0 : }
2551 :
2552 : void
2553 5 : MooseApp::dynamicAppRegistration(const std::string & app_name,
2554 : std::string library_path,
2555 : const std::string & library_name,
2556 : bool lib_load_deps)
2557 : {
2558 : #ifdef LIBMESH_HAVE_DLOPEN
2559 5 : Parameters params;
2560 5 : params.set<std::string>("app_name") = app_name;
2561 5 : params.set<RegistrationType>("reg_type") = APPLICATION;
2562 5 : params.set<std::string>("registration_method") = app_name + "__registerApps";
2563 5 : params.set<std::string>("library_path") = library_path;
2564 :
2565 : const auto effective_library_name =
2566 5 : library_name.empty() ? appNameToLibName(app_name) : library_name;
2567 5 : params.set<std::string>("library_name") = effective_library_name;
2568 5 : params.set<bool>("library_load_dependencies") = lib_load_deps;
2569 :
2570 5 : const auto paths = getLibrarySearchPaths(library_path);
2571 5 : std::ostringstream oss;
2572 :
2573 5 : auto successfully_loaded = false;
2574 5 : if (paths.empty())
2575 : oss << '"' << app_name << "\" is not a registered application name.\n"
2576 : << "No search paths were set. We made no attempts to locate the corresponding library "
2577 1 : "file.\n";
2578 : else
2579 : {
2580 4 : dynamicRegistration(params);
2581 :
2582 : // At this point the application should be registered so check it
2583 4 : if (!AppFactory::instance().isRegistered(app_name))
2584 : {
2585 : oss << '"' << app_name << "\" is not a registered application name.\n"
2586 : << "Unable to locate library archive for \"" << app_name
2587 : << "\".\nWe attempted to locate the library archive \"" << effective_library_name
2588 2 : << "\" in the following paths:\n\t";
2589 2 : std::copy(paths.begin(), paths.end(), infix_ostream_iterator<std::string>(oss, "\n\t"));
2590 : }
2591 : else
2592 2 : successfully_loaded = true;
2593 : }
2594 :
2595 5 : if (!successfully_loaded)
2596 : {
2597 : oss << "\nMake sure you have compiled the library and either set the \"library_path\" "
2598 3 : "variable in your input file or exported \"MOOSE_LIBRARY_PATH\".\n";
2599 :
2600 3 : mooseError(oss.str());
2601 : }
2602 :
2603 : #else
2604 : libmesh_ignore(app_name, library_path, library_name, lib_load_deps);
2605 : mooseError("Dynamic Loading is either not supported or was not detected by libMesh configure.");
2606 : #endif
2607 2 : }
2608 :
2609 : void
2610 9 : MooseApp::dynamicAllRegistration(const std::string & app_name,
2611 : Factory * factory,
2612 : ActionFactory * action_factory,
2613 : Syntax * syntax,
2614 : std::string library_path,
2615 : const std::string & library_name)
2616 : {
2617 : #ifdef LIBMESH_HAVE_DLOPEN
2618 9 : Parameters params;
2619 9 : params.set<std::string>("app_name") = app_name;
2620 9 : params.set<RegistrationType>("reg_type") = REGALL;
2621 9 : params.set<std::string>("registration_method") = app_name + "__registerAll";
2622 9 : params.set<std::string>("library_path") = library_path;
2623 18 : params.set<std::string>("library_name") =
2624 27 : library_name.empty() ? appNameToLibName(app_name) : library_name;
2625 :
2626 9 : params.set<Factory *>("factory") = factory;
2627 9 : params.set<Syntax *>("syntax") = syntax;
2628 9 : params.set<ActionFactory *>("action_factory") = action_factory;
2629 9 : params.set<bool>("library_load_dependencies") = false;
2630 :
2631 9 : dynamicRegistration(params);
2632 : #else
2633 : libmesh_ignore(app_name, factory, action_factory, syntax, library_path, library_name);
2634 : mooseError("Dynamic Loading is either not supported or was not detected by libMesh configure.");
2635 : #endif
2636 9 : }
2637 :
2638 : void
2639 13 : MooseApp::dynamicRegistration(const Parameters & params)
2640 : {
2641 13 : const auto paths = getLibrarySearchPaths(params.get<std::string>("library_path"));
2642 13 : const auto library_name = params.get<std::string>("library_name");
2643 :
2644 : // Attempt to dynamically load the library
2645 26 : for (const auto & path : paths)
2646 13 : if (MooseUtils::checkFileReadable(path + '/' + library_name, false, false))
2647 10 : loadLibraryAndDependencies(
2648 20 : path + '/' + library_name, params, params.get<bool>("library_load_dependencies"));
2649 13 : }
2650 :
2651 : void
2652 10 : MooseApp::loadLibraryAndDependencies(const std::string & library_filename,
2653 : const Parameters & params,
2654 : const bool load_dependencies)
2655 : {
2656 10 : std::string line;
2657 10 : std::string dl_lib_filename;
2658 :
2659 : // This RE looks for absolute path libtool filenames (i.e. begins with a slash and ends with a
2660 : // .la)
2661 10 : pcrecpp::RE re_deps("(/\\S*\\.la)");
2662 :
2663 10 : std::ifstream la_handle(library_filename.c_str());
2664 10 : if (la_handle.is_open())
2665 : {
2666 200 : while (std::getline(la_handle, line))
2667 : {
2668 : // Look for the system dependent dynamic library filename to open
2669 200 : if (line.find("dlname=") != std::string::npos)
2670 : // Magic numbers are computed from length of this string "dlname=' and line minus that
2671 : // string plus quotes"
2672 10 : dl_lib_filename = line.substr(8, line.size() - 9);
2673 :
2674 200 : if (line.find("dependency_libs=") != std::string::npos)
2675 : {
2676 10 : if (load_dependencies)
2677 : {
2678 0 : pcrecpp::StringPiece input(line);
2679 0 : pcrecpp::StringPiece depend_library;
2680 0 : while (re_deps.FindAndConsume(&input, &depend_library))
2681 : // Recurse here to load dependent libraries in depth-first order
2682 0 : loadLibraryAndDependencies(depend_library.as_string(), params, load_dependencies);
2683 : }
2684 :
2685 : // There's only one line in the .la file containing the dependency libs so break after
2686 : // finding it
2687 10 : break;
2688 : }
2689 : }
2690 10 : la_handle.close();
2691 : }
2692 :
2693 : // This should only occur if we have static linkage.
2694 10 : if (dl_lib_filename.empty())
2695 0 : return;
2696 :
2697 10 : const auto & [dir, file_name] = MooseUtils::splitFileName(library_filename);
2698 :
2699 : // Time to load the library, First see if we've already loaded this particular dynamic library
2700 : // 1) make sure we haven't already loaded this library
2701 : // AND 2) make sure we have a library name (we won't for static linkage)
2702 : // Note: Here was are going to assume uniqueness based on the filename alone. This has significant
2703 : // implications for applications that have "diamond" inheritance of libraries (usually
2704 : // modules). We will only load one of those libraries, versions be damned.
2705 10 : auto dyn_lib_it = _lib_handles.find(file_name);
2706 10 : if (dyn_lib_it == _lib_handles.end())
2707 : {
2708 : // Assemble the actual filename using the base path of the *.la file and the dl_lib_filename
2709 10 : const auto dl_lib_full_path = MooseUtils::pathjoin(dir, dl_lib_filename);
2710 :
2711 10 : MooseUtils::checkFileReadable(dl_lib_full_path, false, /*throw_on_unreadable=*/true);
2712 :
2713 : #ifdef LIBMESH_HAVE_DLOPEN
2714 10 : void * const lib_handle = dlopen(dl_lib_full_path.c_str(), RTLD_LAZY);
2715 : #else
2716 : void * const lib_handle = nullptr;
2717 : #endif
2718 :
2719 10 : if (!lib_handle)
2720 0 : mooseError("The library file \"",
2721 : dl_lib_full_path,
2722 : "\" exists and has proper permissions, but cannot by dynamically loaded.\nThis "
2723 : "generally means that the loader was unable to load one or more of the "
2724 : "dependencies listed in the supplied library (see otool or ldd).\n",
2725 0 : dlerror());
2726 :
2727 10 : DynamicLibraryInfo lib_info;
2728 10 : lib_info.library_handle = lib_handle;
2729 10 : lib_info.full_path = library_filename;
2730 :
2731 10 : auto insert_ret = _lib_handles.insert(std::make_pair(file_name, lib_info));
2732 : mooseAssert(insert_ret.second == true, "Error inserting into lib_handles map");
2733 :
2734 10 : dyn_lib_it = insert_ret.first;
2735 10 : }
2736 :
2737 : // Library has been loaded, check to see if we've called the requested registration method
2738 10 : const auto registration_method = params.get<std::string>("registration_method");
2739 10 : auto & entry_sym_from_curr_lib = dyn_lib_it->second.entry_symbols;
2740 :
2741 10 : if (entry_sym_from_curr_lib.find(registration_method) == entry_sym_from_curr_lib.end())
2742 : {
2743 : // get the pointer to the method in the library. The dlsym()
2744 : // function returns a null pointer if the symbol cannot be found,
2745 : // we also explicitly set the pointer to NULL if dlsym is not
2746 : // available.
2747 : #ifdef LIBMESH_HAVE_DLOPEN
2748 : void * registration_handle =
2749 10 : dlsym(dyn_lib_it->second.library_handle, registration_method.c_str());
2750 : #else
2751 : void * registration_handle = nullptr;
2752 : #endif
2753 :
2754 10 : if (registration_handle)
2755 : {
2756 10 : switch (params.get<RegistrationType>("reg_type"))
2757 : {
2758 2 : case APPLICATION:
2759 : {
2760 : using register_app_t = void (*)();
2761 2 : register_app_t * const reg_ptr = reinterpret_cast<register_app_t *>(®istration_handle);
2762 2 : (*reg_ptr)();
2763 2 : break;
2764 : }
2765 8 : case REGALL:
2766 : {
2767 : using register_app_t = void (*)(Factory *, ActionFactory *, Syntax *);
2768 8 : register_app_t * const reg_ptr = reinterpret_cast<register_app_t *>(®istration_handle);
2769 8 : (*reg_ptr)(params.get<Factory *>("factory"),
2770 8 : params.get<ActionFactory *>("action_factory"),
2771 8 : params.get<Syntax *>("syntax"));
2772 8 : break;
2773 : }
2774 0 : default:
2775 0 : mooseError("Unhandled RegistrationType");
2776 : }
2777 :
2778 10 : entry_sym_from_curr_lib.insert(registration_method);
2779 : }
2780 : else
2781 : {
2782 :
2783 : #if defined(DEBUG) && defined(LIBMESH_HAVE_DLOPEN)
2784 : // We found a dynamic library that doesn't have a dynamic
2785 : // registration method in it. This shouldn't be an error, so
2786 : // we'll just move on.
2787 : if (!registration_handle)
2788 : mooseWarning("Unable to find extern \"C\" method \"",
2789 : registration_method,
2790 : "\" in library: ",
2791 : dyn_lib_it->first,
2792 : ".\n",
2793 : "This doesn't necessarily indicate an error condition unless you believe that "
2794 : "the method should exist in that library.\n",
2795 : dlerror());
2796 : #endif
2797 : }
2798 : }
2799 10 : }
2800 :
2801 : std::set<std::string>
2802 19 : MooseApp::getLoadedLibraryPaths() const
2803 : {
2804 : // Return the paths but not the open file handles
2805 19 : std::set<std::string> paths;
2806 21 : for (const auto & it : _lib_handles)
2807 2 : paths.insert(it.first);
2808 :
2809 19 : return paths;
2810 0 : }
2811 :
2812 : std::set<std::string>
2813 18 : MooseApp::getLibrarySearchPaths(const std::string & library_path) const
2814 : {
2815 18 : std::set<std::string> paths;
2816 :
2817 18 : if (!library_path.empty())
2818 : {
2819 17 : std::vector<std::string> tmp_paths;
2820 17 : MooseUtils::tokenize(library_path, tmp_paths, 1, ":");
2821 :
2822 17 : paths.insert(tmp_paths.begin(), tmp_paths.end());
2823 17 : }
2824 :
2825 18 : char * moose_lib_path_env = std::getenv("MOOSE_LIBRARY_PATH");
2826 18 : if (moose_lib_path_env)
2827 : {
2828 0 : std::string moose_lib_path(moose_lib_path_env);
2829 0 : std::vector<std::string> tmp_paths;
2830 0 : MooseUtils::tokenize(moose_lib_path, tmp_paths, 1, ":");
2831 :
2832 0 : paths.insert(tmp_paths.begin(), tmp_paths.end());
2833 0 : }
2834 :
2835 18 : return paths;
2836 0 : }
2837 :
2838 : InputParameterWarehouse &
2839 7876564 : MooseApp::getInputParameterWarehouse()
2840 : {
2841 7876564 : return *_input_parameter_warehouse;
2842 : }
2843 :
2844 : std::string
2845 33 : MooseApp::header() const
2846 : {
2847 33 : return std::string("");
2848 : }
2849 :
2850 : void
2851 11783 : MooseApp::setRestart(bool value)
2852 : {
2853 11783 : _restart = value;
2854 11783 : }
2855 :
2856 : void
2857 11393 : MooseApp::setRecover(bool value)
2858 : {
2859 11393 : _recover = value;
2860 11393 : }
2861 :
2862 : void
2863 1 : MooseApp::createMinimalApp()
2864 : {
2865 1 : TIME_SECTION("createMinimalApp", 3, "Creating Minimal App");
2866 :
2867 : // SetupMeshAction
2868 : {
2869 : // Build the Action parameters
2870 1 : InputParameters action_params = _action_factory.getValidParams("SetupMeshAction");
2871 1 : action_params.set<std::string>("type") = "GeneratedMesh";
2872 :
2873 : // Create The Action
2874 : std::shared_ptr<MooseObjectAction> action = std::static_pointer_cast<MooseObjectAction>(
2875 1 : _action_factory.create("SetupMeshAction", "Mesh", action_params));
2876 :
2877 : // Set the object parameters
2878 1 : InputParameters & params = action->getObjectParams();
2879 1 : params.set<MooseEnum>("dim") = "1";
2880 1 : params.set<unsigned int>("nx") = 1;
2881 :
2882 : // Add Action to the warehouse
2883 1 : _action_warehouse.addActionBlock(action);
2884 1 : }
2885 :
2886 : // Executioner
2887 : {
2888 : // Build the Action parameters
2889 1 : InputParameters action_params = _action_factory.getValidParams("CreateExecutionerAction");
2890 1 : action_params.set<std::string>("type") = "Transient";
2891 :
2892 : // Create the action
2893 : std::shared_ptr<MooseObjectAction> action = std::static_pointer_cast<MooseObjectAction>(
2894 1 : _action_factory.create("CreateExecutionerAction", "Executioner", action_params));
2895 :
2896 : // Set the object parameters
2897 1 : InputParameters & params = action->getObjectParams();
2898 1 : params.set<unsigned int>("num_steps") = 1;
2899 1 : params.set<Real>("dt") = 1;
2900 :
2901 : // Add Action to the warehouse
2902 1 : _action_warehouse.addActionBlock(action);
2903 1 : }
2904 :
2905 : // Problem
2906 : {
2907 : // Build the Action parameters
2908 1 : InputParameters action_params = _action_factory.getValidParams("CreateProblemDefaultAction");
2909 1 : action_params.set<bool>("_solve") = false;
2910 :
2911 : // Create the action
2912 : std::shared_ptr<Action> action = std::static_pointer_cast<Action>(
2913 1 : _action_factory.create("CreateProblemDefaultAction", "Problem", action_params));
2914 :
2915 : // Add Action to the warehouse
2916 1 : _action_warehouse.addActionBlock(action);
2917 1 : }
2918 :
2919 : // Outputs
2920 : {
2921 : // Build the Action parameters
2922 1 : InputParameters action_params = _action_factory.getValidParams("CommonOutputAction");
2923 1 : action_params.set<bool>("console") = false;
2924 :
2925 : // Create action
2926 : std::shared_ptr<Action> action =
2927 1 : _action_factory.create("CommonOutputAction", "Outputs", action_params);
2928 :
2929 : // Add Action to the warehouse
2930 1 : _action_warehouse.addActionBlock(action);
2931 1 : }
2932 :
2933 1 : _action_warehouse.build();
2934 1 : }
2935 :
2936 : bool
2937 0 : MooseApp::hasRelationshipManager(const std::string & name) const
2938 : {
2939 0 : return std::find_if(_relationship_managers.begin(),
2940 : _relationship_managers.end(),
2941 0 : [&name](const std::shared_ptr<RelationshipManager> & rm)
2942 0 : { return rm->name() == name; }) != _relationship_managers.end();
2943 : }
2944 :
2945 : namespace
2946 : {
2947 : void
2948 451897 : donateForWhom(const RelationshipManager & donor, RelationshipManager & acceptor)
2949 : {
2950 451897 : auto & existing_for_whom = acceptor.forWhom();
2951 :
2952 : // Take all the for_whoms from the donor, and give them to the acceptor
2953 909030 : for (auto & fw : donor.forWhom())
2954 : {
2955 457133 : if (std::find(existing_for_whom.begin(), existing_for_whom.end(), fw) ==
2956 914266 : existing_for_whom.end())
2957 92054 : acceptor.addForWhom(fw);
2958 : }
2959 451897 : }
2960 : }
2961 :
2962 : bool
2963 560900 : MooseApp::addRelationshipManager(std::shared_ptr<RelationshipManager> new_rm)
2964 : {
2965 : // We prefer to always add geometric RMs. There is no hurt to add RMs for replicated mesh
2966 : // since MeshBase::delete_remote_elements{} is a no-op (empty) for replicated mesh.
2967 : // The motivation here is that MooseMesh::_use_distributed_mesh may not be properly set
2968 : // at the time we are adding geometric relationship managers. We deleted the following
2969 : // old logic to add all geometric RMs regardless of there is a distributed mesh or not.
2970 : // Otherwise, all geometric RMs will be improperly ignored for a distributed mesh generator.
2971 :
2972 : // if (!_action_warehouse.mesh()->isDistributedMesh() && !_split_mesh &&
2973 : // (relationship_manager->isType(Moose::RelationshipManagerType::GEOMETRIC) &&
2974 : // !(relationship_manager->isType(Moose::RelationshipManagerType::ALGEBRAIC) ||
2975 : // relationship_manager->isType(Moose::RelationshipManagerType::COUPLING))))
2976 : // return false;
2977 :
2978 560900 : bool add = true;
2979 :
2980 560900 : std::set<std::shared_ptr<RelationshipManager>> rms_to_erase;
2981 :
2982 977852 : for (const auto & existing_rm : _relationship_managers)
2983 : {
2984 864868 : if (*existing_rm >= *new_rm)
2985 : {
2986 447916 : add = false;
2987 447916 : donateForWhom(*new_rm, *existing_rm);
2988 447916 : break;
2989 : }
2990 : // The new rm did not provide less or the same amount/type of ghosting as the existing rm, but
2991 : // what about the other way around?
2992 416952 : else if (*new_rm >= *existing_rm)
2993 3981 : rms_to_erase.emplace(existing_rm);
2994 : }
2995 :
2996 560900 : if (add)
2997 : {
2998 112984 : _relationship_managers.emplace(new_rm);
2999 116965 : for (const auto & rm_to_erase : rms_to_erase)
3000 : {
3001 3981 : donateForWhom(*rm_to_erase, *new_rm);
3002 3981 : removeRelationshipManager(rm_to_erase);
3003 : }
3004 : }
3005 :
3006 : // Inform the caller whether the object was added or not
3007 560900 : return add;
3008 560900 : }
3009 :
3010 : const std::string &
3011 16489 : MooseApp::checkpointSuffix()
3012 : {
3013 16489 : static const std::string suffix = "-mesh.cpa.gz";
3014 16489 : return suffix;
3015 : }
3016 :
3017 : std::filesystem::path
3018 15871 : MooseApp::metaDataFolderBase(const std::filesystem::path & folder_base,
3019 : const std::string & map_suffix)
3020 : {
3021 31742 : return RestartableDataIO::restartableDataFolder(folder_base /
3022 47613 : std::filesystem::path("meta_data" + map_suffix));
3023 : }
3024 :
3025 : std::filesystem::path
3026 13924 : MooseApp::restartFolderBase(const std::filesystem::path & folder_base) const
3027 : {
3028 13924 : auto folder = folder_base;
3029 13924 : folder += "-restart-" + std::to_string(processor_id());
3030 27848 : return RestartableDataIO::restartableDataFolder(folder);
3031 13924 : }
3032 :
3033 : const hit::Node *
3034 2469623 : MooseApp::getCurrentActionHitNode() const
3035 : {
3036 2469623 : if (const auto action = _action_warehouse.getCurrentAction())
3037 1099043 : return action->parameters().getHitNode();
3038 1370580 : return nullptr;
3039 : }
3040 :
3041 : bool
3042 27 : MooseApp::hasRMClone(const RelationshipManager & template_rm, const MeshBase & mesh) const
3043 : {
3044 27 : auto it = _template_to_clones.find(&template_rm);
3045 : // C++ does short circuiting so we're safe here
3046 27 : return (it != _template_to_clones.end()) && (it->second.find(&mesh) != it->second.end());
3047 : }
3048 :
3049 : RelationshipManager &
3050 27 : MooseApp::getRMClone(const RelationshipManager & template_rm, const MeshBase & mesh) const
3051 : {
3052 27 : auto outer_it = _template_to_clones.find(&template_rm);
3053 27 : if (outer_it == _template_to_clones.end())
3054 0 : mooseError("The template rm does not exist in our _template_to_clones map");
3055 :
3056 27 : auto & mesh_to_clone_map = outer_it->second;
3057 27 : auto inner_it = mesh_to_clone_map.find(&mesh);
3058 27 : if (inner_it == mesh_to_clone_map.end())
3059 0 : mooseError("We should have the mesh key in our mesh");
3060 :
3061 54 : return *inner_it->second;
3062 : }
3063 :
3064 : void
3065 3981 : MooseApp::removeRelationshipManager(std::shared_ptr<RelationshipManager> rm)
3066 : {
3067 3981 : auto * const mesh = _action_warehouse.mesh().get();
3068 3981 : if (!mesh)
3069 0 : mooseError("The MooseMesh should exist");
3070 :
3071 3981 : const MeshBase * const undisp_lm_mesh = mesh->getMeshPtr();
3072 3981 : RelationshipManager * undisp_clone = nullptr;
3073 3981 : if (undisp_lm_mesh && hasRMClone(*rm, *undisp_lm_mesh))
3074 : {
3075 27 : undisp_clone = &getRMClone(*rm, *undisp_lm_mesh);
3076 27 : const_cast<MeshBase *>(undisp_lm_mesh)->remove_ghosting_functor(*undisp_clone);
3077 : }
3078 :
3079 3981 : auto & displaced_mesh = _action_warehouse.displacedMesh();
3080 3981 : MeshBase * const disp_lm_mesh = displaced_mesh ? &displaced_mesh->getMesh() : nullptr;
3081 3981 : RelationshipManager * disp_clone = nullptr;
3082 3981 : if (disp_lm_mesh && hasRMClone(*rm, *disp_lm_mesh))
3083 : {
3084 0 : disp_clone = &getRMClone(*rm, *disp_lm_mesh);
3085 0 : disp_lm_mesh->remove_ghosting_functor(*disp_clone);
3086 : }
3087 :
3088 3981 : if (_executioner)
3089 : {
3090 27 : auto & problem = feProblem();
3091 27 : if (undisp_clone)
3092 : {
3093 27 : problem.removeAlgebraicGhostingFunctor(*undisp_clone);
3094 27 : problem.removeCouplingGhostingFunctor(*undisp_clone);
3095 : }
3096 :
3097 27 : auto * dp = problem.getDisplacedProblem().get();
3098 27 : if (dp && disp_clone)
3099 0 : dp->removeAlgebraicGhostingFunctor(*disp_clone);
3100 : }
3101 :
3102 3981 : _factory.releaseSharedObjects(*rm);
3103 3981 : _relationship_managers.erase(rm);
3104 3981 : }
3105 :
3106 : RelationshipManager &
3107 181216 : MooseApp::createRMFromTemplateAndInit(const RelationshipManager & template_rm,
3108 : MooseMesh & moose_mesh,
3109 : MeshBase & mesh,
3110 : const DofMap * const dof_map)
3111 : {
3112 181216 : auto & mesh_to_clone = _template_to_clones[&template_rm];
3113 181216 : auto it = mesh_to_clone.find(&mesh);
3114 181216 : if (it != mesh_to_clone.end())
3115 : {
3116 : // We've already created a clone for this mesh
3117 71384 : auto & clone_rm = *it->second;
3118 71384 : if (!clone_rm.dofMap() && dof_map)
3119 : // We didn't have a DofMap before, but now we do, so we should re-init
3120 7187 : clone_rm.init(moose_mesh, mesh, dof_map);
3121 64197 : else if (clone_rm.dofMap() && dof_map && (clone_rm.dofMap() != dof_map))
3122 0 : mooseError("Attempting to create and initialize an existing clone with a different DofMap. "
3123 : "This should not happen.");
3124 :
3125 71384 : return clone_rm;
3126 : }
3127 :
3128 : // It's possible that this method is going to get called for multiple different MeshBase
3129 : // objects. If that happens, then we *cannot* risk having a MeshBase object with a ghosting
3130 : // functor that is init'd with another MeshBase object. So the safe thing to do is to make a
3131 : // different RM for every MeshBase object that gets called here. Then the
3132 : // RelationshipManagers stored here in MooseApp are serving as a template only
3133 109832 : auto pr = mesh_to_clone.emplace(
3134 219664 : std::make_pair(&const_cast<const MeshBase &>(mesh),
3135 219664 : dynamic_pointer_cast<RelationshipManager>(template_rm.clone())));
3136 : mooseAssert(pr.second, "An insertion should have happened");
3137 109832 : auto & clone_rm = *pr.first->second;
3138 109832 : clone_rm.init(moose_mesh, mesh, dof_map);
3139 109832 : return clone_rm;
3140 : }
3141 :
3142 : void
3143 64340 : MooseApp::attachRelationshipManagers(MeshBase & mesh, MooseMesh & moose_mesh)
3144 : {
3145 164180 : for (auto & rm : _relationship_managers)
3146 : {
3147 99840 : if (rm->isType(Moose::RelationshipManagerType::GEOMETRIC))
3148 : {
3149 61090 : if (rm->attachGeometricEarly())
3150 46108 : mesh.add_ghosting_functor(createRMFromTemplateAndInit(*rm, moose_mesh, mesh));
3151 : else
3152 : {
3153 : // If we have a geometric ghosting functor that can't be attached early, then we have to
3154 : // prevent the mesh from deleting remote elements
3155 14982 : moose_mesh.allowRemoteElementRemoval(false);
3156 :
3157 14982 : if (const MeshBase * const moose_mesh_base = moose_mesh.getMeshPtr())
3158 : {
3159 0 : if (moose_mesh_base != &mesh)
3160 0 : mooseError("The MooseMesh MeshBase and the MeshBase we're trying to attach "
3161 : "relationship managers to are different");
3162 : }
3163 : else
3164 : // The MeshBase isn't attached to the MooseMesh yet, so have to tell it not to remove
3165 : // remote elements independently
3166 14982 : mesh.allow_remote_element_removal(false);
3167 : }
3168 : }
3169 : }
3170 64340 : }
3171 :
3172 : void
3173 229340 : MooseApp::attachRelationshipManagers(Moose::RelationshipManagerType rm_type,
3174 : bool attach_geometric_rm_final)
3175 : {
3176 641360 : for (auto & rm : _relationship_managers)
3177 : {
3178 412020 : if (!rm->isType(rm_type))
3179 221199 : continue;
3180 :
3181 : // RM is already attached (this also handles the geometric early case)
3182 190821 : if (_attached_relationship_managers[rm_type].count(rm.get()))
3183 42296 : continue;
3184 :
3185 148525 : if (rm_type == Moose::RelationshipManagerType::GEOMETRIC)
3186 : {
3187 : // The problem is not built yet - so the ActionWarehouse currently owns the mesh
3188 74118 : MooseMesh * const mesh = _action_warehouse.mesh().get();
3189 :
3190 : // "attach_geometric_rm_final = true" inidicate that it is the last chance to attach
3191 : // geometric RMs. Therefore, we need to attach them.
3192 74118 : if (!rm->attachGeometricEarly() && !attach_geometric_rm_final)
3193 : // Will attach them later (during algebraic). But also, we need to tell the mesh that we
3194 : // shouldn't be deleting remote elements yet
3195 14905 : mesh->allowRemoteElementRemoval(false);
3196 : else
3197 : {
3198 59213 : MeshBase & undisp_mesh_base = mesh->getMesh();
3199 : const DofMap * const undisp_sys_dof_map =
3200 59213 : _executioner ? &feProblem().getSolverSystem(0).dofMap() : nullptr;
3201 59213 : undisp_mesh_base.add_ghosting_functor(
3202 59213 : createRMFromTemplateAndInit(*rm, *mesh, undisp_mesh_base, undisp_sys_dof_map));
3203 :
3204 : // In the final stage, if there is a displaced mesh, we need to
3205 : // clone ghosting functors for displacedMesh
3206 59213 : if (auto & disp_moose_mesh = _action_warehouse.displacedMesh();
3207 59213 : attach_geometric_rm_final && disp_moose_mesh)
3208 : {
3209 1488 : MeshBase & disp_mesh_base = _action_warehouse.displacedMesh()->getMesh();
3210 1488 : const DofMap * disp_sys_dof_map = nullptr;
3211 1488 : if (_executioner && feProblem().getDisplacedProblem())
3212 1488 : disp_sys_dof_map = &feProblem().getDisplacedProblem()->solverSys(0).dofMap();
3213 1488 : disp_mesh_base.add_ghosting_functor(
3214 1488 : createRMFromTemplateAndInit(*rm, *disp_moose_mesh, disp_mesh_base, disp_sys_dof_map));
3215 : }
3216 57725 : else if (_action_warehouse.displacedMesh())
3217 0 : mooseError("The displaced mesh should not yet exist at the time that we are attaching "
3218 : "early geometric relationship managers.");
3219 :
3220 : // Mark this RM as attached
3221 : mooseAssert(!_attached_relationship_managers[rm_type].count(rm.get()), "Already attached");
3222 59213 : _attached_relationship_managers[rm_type].insert(rm.get());
3223 : }
3224 : }
3225 : else // rm_type is algebraic or coupling
3226 : {
3227 74407 : if (!_executioner && !_executor)
3228 0 : mooseError("We must have an executioner by now or else we do not have to data to add "
3229 : "algebraic or coupling functors to in MooseApp::attachRelationshipManagers");
3230 :
3231 : // Now we've built the problem, so we can use it
3232 74407 : auto & problem = feProblem();
3233 74407 : auto & undisp_moose_mesh = problem.mesh();
3234 74407 : auto & undisp_sys = feProblem().getSolverSystem(0);
3235 74407 : auto & undisp_sys_dof_map = undisp_sys.dofMap();
3236 74407 : auto & undisp_mesh = undisp_moose_mesh.getMesh();
3237 :
3238 74407 : if (rm->useDisplacedMesh() && problem.getDisplacedProblem())
3239 : {
3240 4334 : if (rm_type == Moose::RelationshipManagerType::COUPLING)
3241 : // We actually need to add this to the FEProblemBase NonlinearSystemBase's DofMap
3242 : // because the DisplacedProblem "nonlinear" DisplacedSystem doesn't have any matrices
3243 : // for which to do coupling. It's actually horrifying to me that we are adding a
3244 : // coupling functor, that is going to determine its couplings based on a displaced
3245 : // MeshBase object, to a System associated with the undisplaced MeshBase object (there
3246 : // is only ever one EquationSystems object per MeshBase object and visa versa). So here
3247 : // I'm left with the choice of whether to pass in a MeshBase object that is *not* the
3248 : // MeshBase object that will actually determine the couplings or to pass in the MeshBase
3249 : // object that is inconsistent with the System DofMap that we are adding the coupling
3250 : // functor for! Let's err on the side of *libMesh* consistency and pass properly paired
3251 : // MeshBase-DofMap
3252 184 : problem.addCouplingGhostingFunctor(
3253 92 : createRMFromTemplateAndInit(*rm, undisp_moose_mesh, undisp_mesh, &undisp_sys_dof_map),
3254 : /*to_mesh = */ false);
3255 :
3256 4242 : else if (rm_type == Moose::RelationshipManagerType::ALGEBRAIC)
3257 : {
3258 4242 : auto & displaced_problem = *problem.getDisplacedProblem();
3259 4242 : auto & disp_moose_mesh = displaced_problem.mesh();
3260 4242 : auto & disp_mesh = disp_moose_mesh.getMesh();
3261 4242 : const DofMap * const disp_nl_dof_map = &displaced_problem.solverSys(0).dofMap();
3262 8484 : displaced_problem.addAlgebraicGhostingFunctor(
3263 4242 : createRMFromTemplateAndInit(*rm, disp_moose_mesh, disp_mesh, disp_nl_dof_map),
3264 : /*to_mesh = */ false);
3265 : }
3266 : }
3267 : else // undisplaced
3268 : {
3269 70073 : if (rm_type == Moose::RelationshipManagerType::COUPLING)
3270 86642 : problem.addCouplingGhostingFunctor(
3271 43321 : createRMFromTemplateAndInit(*rm, undisp_moose_mesh, undisp_mesh, &undisp_sys_dof_map),
3272 : /*to_mesh = */ false);
3273 :
3274 26752 : else if (rm_type == Moose::RelationshipManagerType::ALGEBRAIC)
3275 53504 : problem.addAlgebraicGhostingFunctor(
3276 26752 : createRMFromTemplateAndInit(*rm, undisp_moose_mesh, undisp_mesh, &undisp_sys_dof_map),
3277 : /*to_mesh = */ false);
3278 : }
3279 :
3280 : // Mark this RM as attached
3281 : mooseAssert(!_attached_relationship_managers[rm_type].count(rm.get()), "Already attached");
3282 74407 : _attached_relationship_managers[rm_type].insert(rm.get());
3283 : }
3284 : }
3285 229340 : }
3286 :
3287 : std::vector<std::pair<std::string, std::string>>
3288 95 : MooseApp::getRelationshipManagerInfo() const
3289 : {
3290 95 : std::vector<std::pair<std::string, std::string>> info_strings;
3291 95 : info_strings.reserve(_relationship_managers.size());
3292 :
3293 387 : for (const auto & rm : _relationship_managers)
3294 : {
3295 292 : std::stringstream oss;
3296 292 : oss << rm->getInfo();
3297 :
3298 292 : auto & for_whom = rm->forWhom();
3299 :
3300 292 : if (!for_whom.empty())
3301 : {
3302 292 : oss << " for ";
3303 :
3304 292 : std::copy(for_whom.begin(), for_whom.end(), infix_ostream_iterator<std::string>(oss, ", "));
3305 : }
3306 :
3307 292 : info_strings.emplace_back(std::make_pair(Moose::stringify(rm->getType()), oss.str()));
3308 292 : }
3309 :
3310 : // List the libMesh GhostingFunctors - Not that in libMesh all of the algebraic and coupling
3311 : // Ghosting Functors are also attached to the mesh. This should catch them all.
3312 95 : const auto & mesh = _action_warehouse.getMesh();
3313 95 : if (mesh)
3314 : {
3315 : // Let us use an ordered map to avoid stochastic console behaviors.
3316 : // I believe we won't have many RMs, and there is no performance issue.
3317 : // Deterministic behaviors are good for setting up regression tests
3318 95 : std::map<std::string, unsigned int> counts;
3319 :
3320 190 : for (auto & gf : as_range(mesh->getMesh().ghosting_functors_begin(),
3321 767 : mesh->getMesh().ghosting_functors_end()))
3322 : {
3323 482 : const auto * gf_ptr = dynamic_cast<const RelationshipManager *>(gf);
3324 482 : if (!gf_ptr)
3325 : // Count how many occurences of the same Ghosting Functor types we are encountering
3326 305 : counts[demangle(typeid(*gf).name())]++;
3327 : }
3328 :
3329 285 : for (const auto & pair : counts)
3330 190 : info_strings.emplace_back(std::make_pair(
3331 380 : "Default", pair.first + (pair.second > 1 ? " x " + std::to_string(pair.second) : "")));
3332 95 : }
3333 :
3334 : // List the libMesh GhostingFunctors - Not that in libMesh all of the algebraic and coupling
3335 : // Ghosting Functors are also attached to the mesh. This should catch them all.
3336 95 : const auto & d_mesh = _action_warehouse.getDisplacedMesh();
3337 95 : if (d_mesh)
3338 : {
3339 : // Let us use an ordered map to avoid stochastic console behaviors.
3340 : // I believe we won't have many RMs, and there is no performance issue.
3341 : // Deterministic behaviors are good for setting up regression tests
3342 10 : std::map<std::string, unsigned int> counts;
3343 :
3344 20 : for (auto & gf : as_range(d_mesh->getMesh().ghosting_functors_begin(),
3345 90 : d_mesh->getMesh().ghosting_functors_end()))
3346 : {
3347 60 : const auto * gf_ptr = dynamic_cast<const RelationshipManager *>(gf);
3348 60 : if (!gf_ptr)
3349 : // Count how many occurences of the same Ghosting Functor types we are encountering
3350 30 : counts[demangle(typeid(*gf).name())]++;
3351 : }
3352 :
3353 30 : for (const auto & pair : counts)
3354 20 : info_strings.emplace_back(
3355 40 : std::make_pair("Default",
3356 40 : pair.first + (pair.second > 1 ? " x " + std::to_string(pair.second) : "") +
3357 : " for DisplacedMesh"));
3358 10 : }
3359 :
3360 95 : return info_strings;
3361 0 : }
3362 :
3363 : void
3364 60983 : MooseApp::checkMetaDataIntegrity() const
3365 : {
3366 121966 : for (auto map_iter = _restartable_meta_data.begin(); map_iter != _restartable_meta_data.end();
3367 60983 : ++map_iter)
3368 : {
3369 60983 : const RestartableDataMapName & name = map_iter->first;
3370 60983 : const RestartableDataMap & meta_data = map_iter->second.first;
3371 :
3372 60983 : std::vector<std::string> not_declared;
3373 :
3374 234832 : for (const auto & data : meta_data)
3375 173849 : if (!data.declared())
3376 0 : not_declared.push_back(data.name());
3377 :
3378 60983 : if (!not_declared.empty())
3379 : {
3380 0 : std::ostringstream oss;
3381 0 : std::copy(
3382 : not_declared.begin(), not_declared.end(), infix_ostream_iterator<std::string>(oss, ", "));
3383 :
3384 0 : mooseError("The following '",
3385 : name,
3386 : "' meta-data properties were retrieved but never declared: ",
3387 0 : oss.str());
3388 0 : }
3389 60983 : }
3390 60983 : }
3391 :
3392 : const RestartableDataMapName MooseApp::MESH_META_DATA = "MeshMetaData";
3393 : const RestartableDataMapName MooseApp::MESH_META_DATA_SUFFIX = "mesh";
3394 :
3395 : RestartableDataMap &
3396 13920 : MooseApp::getRestartableDataMap(const RestartableDataMapName & name)
3397 : {
3398 13920 : auto iter = _restartable_meta_data.find(name);
3399 13920 : if (iter == _restartable_meta_data.end())
3400 4 : mooseError("Unable to find RestartableDataMap object for the supplied name '",
3401 : name,
3402 : "', did you call registerRestartableDataMapName in the application constructor?");
3403 13916 : return iter->second.first;
3404 : }
3405 :
3406 : bool
3407 0 : MooseApp::hasRestartableDataMap(const RestartableDataMapName & name) const
3408 : {
3409 0 : return _restartable_meta_data.count(name);
3410 : }
3411 :
3412 : void
3413 62754 : MooseApp::registerRestartableDataMapName(const RestartableDataMapName & name, std::string suffix)
3414 : {
3415 62754 : if (!suffix.empty())
3416 62754 : std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
3417 62754 : suffix.insert(0, "_");
3418 62754 : _restartable_meta_data.emplace(
3419 125508 : std::make_pair(name, std::make_pair(RestartableDataMap(), suffix)));
3420 62754 : }
3421 :
3422 : const std::string &
3423 15871 : MooseApp::getRestartableDataMapName(const RestartableDataMapName & name) const
3424 : {
3425 15871 : const auto it = _restartable_meta_data.find(name);
3426 15871 : if (it == _restartable_meta_data.end())
3427 0 : mooseError("MooseApp::getRestartableDataMapName: The name '", name, "' is not registered");
3428 15871 : return it->second.second;
3429 : }
3430 :
3431 : PerfGraph &
3432 62755 : MooseApp::createRecoverablePerfGraph()
3433 : {
3434 62755 : registerRestartableNameWithFilter("perf_graph", Moose::RESTARTABLE_FILTER::RECOVERABLE);
3435 :
3436 : auto perf_graph =
3437 : std::make_unique<RestartableData<PerfGraph>>("perf_graph",
3438 0 : this,
3439 125510 : type() + " (" + name() + ')',
3440 : *this,
3441 : getParam<bool>("perf_graph_live_all"),
3442 188265 : !getParam<bool>("disable_perf_graph_live"));
3443 :
3444 62755 : return dynamic_cast<RestartableData<PerfGraph> &>(
3445 125510 : registerRestartableData(std::move(perf_graph), 0, false))
3446 125510 : .set();
3447 62755 : }
3448 :
3449 : SolutionInvalidity &
3450 62755 : MooseApp::createRecoverableSolutionInvalidity()
3451 : {
3452 62755 : registerRestartableNameWithFilter("solution_invalidity", Moose::RESTARTABLE_FILTER::RECOVERABLE);
3453 :
3454 : auto solution_invalidity =
3455 62755 : std::make_unique<RestartableData<SolutionInvalidity>>("solution_invalidity", nullptr, *this);
3456 :
3457 62755 : return dynamic_cast<RestartableData<SolutionInvalidity> &>(
3458 125510 : registerRestartableData(std::move(solution_invalidity), 0, false))
3459 125510 : .set();
3460 62755 : }
3461 :
3462 : bool
3463 285320 : MooseApp::constructingMeshGenerators() const
3464 : {
3465 336855 : return _action_warehouse.getCurrentTaskName() == "create_added_mesh_generators" ||
3466 336855 : _mesh_generator_system.appendingMeshGenerators();
3467 : }
3468 :
3469 : #ifdef LIBTORCH_ENABLED
3470 : torch::DeviceType
3471 6988 : MooseApp::determineLibtorchDeviceType(const MooseEnum & device_enum) const
3472 : {
3473 6988 : if (device_enum == "cuda")
3474 : {
3475 : #ifdef __linux__
3476 62 : if (!torch::cuda::is_available())
3477 0 : mooseError("--libtorch-device=cuda: CUDA is not available");
3478 62 : return torch::kCUDA;
3479 : #else
3480 : mooseError("--libtorch-device=cuda: CUDA is not supported on your platform");
3481 : #endif
3482 : }
3483 6926 : else if (device_enum == "mps")
3484 : {
3485 : #ifdef __APPLE__
3486 : if (!torch::mps::is_available())
3487 : mooseError("--libtorch-device=mps: MPS is not available");
3488 : return torch::kMPS;
3489 : #else
3490 0 : mooseError("--libtorch-device=mps: MPS is not supported on your platform");
3491 : #endif
3492 : }
3493 :
3494 : mooseAssert(device_enum == "cpu", "Should be cpu");
3495 6926 : return torch::kCPU;
3496 : }
3497 : #endif
3498 :
3499 : void
3500 69 : MooseApp::outputMachineReadableData(const std::string & param,
3501 : const std::string & start_marker,
3502 : const std::string & end_marker,
3503 : const std::string & data) const
3504 : {
3505 : // Bool parameter, just to screen
3506 69 : if (_pars.have_parameter<bool>(param))
3507 : {
3508 69 : Moose::out << start_marker << data << end_marker << std::endl;
3509 69 : return;
3510 : }
3511 :
3512 : // String parameter, to file
3513 0 : const auto & filename = getParam<std::string>(param);
3514 : // write to file
3515 0 : std::ofstream out(filename.c_str());
3516 0 : if (out.is_open())
3517 : {
3518 0 : std::ofstream out(filename.c_str());
3519 0 : out << data << std::flush;
3520 0 : out.close();
3521 0 : }
3522 : else
3523 0 : mooseError("Unable to open file `", filename, "` for writing ", param, " data to it.");
3524 0 : }
3525 :
3526 : void
3527 2063894 : MooseApp::addCapability(const std::string & capability,
3528 : CapabilityUtils::Type value,
3529 : const std::string & doc)
3530 : {
3531 2063894 : Moose::Capabilities::getCapabilityRegistry().add(capability, value, doc);
3532 2063894 : }
3533 :
3534 : void
3535 258004 : MooseApp::addCapability(const std::string & capability, const char * value, const std::string & doc)
3536 : {
3537 258004 : Moose::Capabilities::getCapabilityRegistry().add(capability, std::string(value), doc);
3538 258004 : }
|