LCOV - code coverage report
Current view: top level - src/base - MooseApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33187 (5aa0b2) with base d7c4bd Lines: 1331 1541 86.4 %
Date: 2026-06-30 12:18:20 Functions: 99 110 90.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14