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