LCOV - code coverage report
Current view: top level - src/base - MooseApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 1379 1590 86.7 %
Date: 2025-08-08 20:01:16 Functions: 99 110 90.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14