LCOV - code coverage report
Current view: top level - src/base - MooseApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31761 (28487c) with base 701993 Lines: 1406 1622 86.7 %
Date: 2025-11-11 13:51:07 Functions: 100 111 90.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14