LCOV - code coverage report
Current view: top level - src/base - MooseApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 1345 1550 86.8 %
Date: 2025-07-17 01:28:37 Functions: 96 107 89.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14