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