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

Generated by: LCOV version 1.14