https://mooseframework.inl.gov
MultiApp.C
Go to the documentation of this file.
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 // MOOSE includes
11 #include "MultiApp.h"
12 
13 #include "AppFactory.h"
14 #include "AuxiliarySystem.h"
15 #include "DisplacedProblem.h"
16 #include "Console.h"
17 #include "Executioner.h"
18 #include "FEProblem.h"
19 #include "MooseMesh.h"
20 #include "MooseUtils.h"
21 #include "OutputWarehouse.h"
22 #include "SetupInterface.h"
23 #include "UserObject.h"
24 #include "CommandLine.h"
25 #include "Conversion.h"
26 #include "NonlinearSystemBase.h"
27 #include "DelimitedFileReader.h"
28 #include "MooseAppCoordTransform.h"
29 #include "MultiAppTransfer.h"
30 #include "Positions.h"
31 #include "Transient.h"
32 #include "Backup.h"
33 #include "Parser.h"
34 
35 #include "libmesh/mesh_tools.h"
36 #include "libmesh/numeric_vector.h"
37 
38 // C++ includes
39 #include <fstream>
40 #include <iomanip>
41 #include <iterator>
42 #include <algorithm>
43 
44 // Call to "uname"
45 #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
46 #include <sys/utsname.h>
47 #endif
48 
51 {
53  params += SetupInterface::validParams();
54 
55  params.addParam<bool>("use_displaced_mesh",
56  false,
57  "Whether or not this object should use the "
58  "displaced mesh for computation. Note that "
59  "in the case this is true but no "
60  "displacements are provided in the Mesh block "
61  "the undisplaced mesh will still be used.");
62 
63  std::ostringstream app_types_strings;
64  for (const auto & name_bi_pair : AppFactory::instance().registeredObjects())
65  app_types_strings << name_bi_pair.first << " ";
66  MooseEnum app_types_options(app_types_strings.str(), "", true);
67 
68  // Dynamic loading
69  params.addParam<MooseEnum>("app_type",
70  app_types_options,
71  "The type of application to build (applications not "
72  "registered can be loaded with dynamic libraries. Parent "
73  "application type will be used if not provided.");
74  params.addParam<std::string>("library_path",
75  "",
76  "Path to search for dynamic libraries (please "
77  "avoid committing absolute paths in addition to "
78  "MOOSE_LIBRARY_PATH)");
79  params.addParam<std::string>(
80  "library_name",
81  "",
82  "The file name of the library (*.la file) that will be dynamically loaded.");
83  params.addParam<bool>("library_load_dependencies",
84  false,
85  "Tells MOOSE to manually load library dependencies. This should not be "
86  "necessary and is here for debugging/troubleshooting.");
87 
88  // Subapp positions
89  params.addParam<std::vector<Point>>(
90  "positions",
91  "The positions of the App locations. Each set of 3 values will represent a "
92  "Point. This and 'positions_file' cannot be both supplied. If this and "
93  "'positions_file'/'_objects' are not supplied, a single position (0,0,0) will be used");
94  params.addParam<std::vector<FileName>>("positions_file",
95  "Filename(s) that should be looked in for positions. Each"
96  " set of 3 values in that file will represent a Point. "
97  "This and 'positions(_objects)' cannot be both supplied");
98  params.addParam<std::vector<PositionsName>>("positions_objects",
99  "The name of a Positions object that will contain "
100  "the locations of the sub-apps created. This and "
101  "'positions(_file)' cannot be both supplied");
102  params.addParam<bool>(
103  "output_in_position",
104  false,
105  "If true this will cause the output from the MultiApp to be 'moved' by its position vector");
106  params.addParam<bool>(
107  "run_in_position",
108  false,
109  "If true this will cause the mesh from the MultiApp to be 'moved' by its position vector");
110 
111  params.addRequiredParam<std::vector<FileName>>(
112  "input_files",
113  "The input file for each App. If this parameter only contains one input file "
114  "it will be used for all of the Apps. When using 'positions_from_file' it is "
115  "also admissable to provide one input_file per file.");
116  params.addParam<Real>("bounding_box_inflation",
117  0.01,
118  "Relative amount to 'inflate' the bounding box of this MultiApp.");
119  params.addParam<Point>("bounding_box_padding",
120  RealVectorValue(),
121  "Additional padding added to the dimensions of the bounding box. The "
122  "values are added to the x, y and z dimension respectively.");
123 
124  params.addPrivateParam<MPI_Comm>("_mpi_comm");
125 
126  // Set the default execution time
127  params.set<ExecFlagEnum>("execute_on", true) = EXEC_TIMESTEP_BEGIN;
128  // Add the POST_ADAPTIVITY execution flag.
129 #ifdef LIBMESH_ENABLE_AMR
130  ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on");
132  params.setDocString("execute_on", exec_enum.getDocString());
133 #endif
134 
135  params.addParam<processor_id_type>("max_procs_per_app",
137  "Maximum number of processors to give to each App in this "
138  "MultiApp. Useful for restricting small solves to just a few "
139  "procs so they don't get spread out");
140  params.addParam<processor_id_type>("min_procs_per_app",
141  1,
142  "Minimum number of processors to give to each App in this "
143  "MultiApp. Useful for larger, distributed mesh solves.");
144  params.addParam<bool>(
145  "wait_for_first_app_init",
146  false,
147  "Create the first sub-application on rank 0, then MPI_Barrier before "
148  "creating the next N-1 apps (on all ranks). "
149  "This is only needed if your sub-application needs to perform some setup "
150  "actions in quiet, without other sub-applications working at the same time.");
151 
152  params.addParam<Real>("global_time_offset",
153  0,
154  "The time offset relative to the parent application for the purpose of "
155  "starting a subapp at a different time from the parent application. The "
156  "global time will be ahead by the offset specified here.");
157 
158  // Resetting subapps
159  params.addParam<std::vector<Real>>(
160  "reset_time",
161  {},
162  "The time(s) at which to reset Apps given by the 'reset_apps' parameter. "
163  "Resetting an App means that it is destroyed and recreated, possibly "
164  "modeling the insertion of 'new' material for that app.");
165  params.addParam<std::vector<unsigned int>>(
166  "reset_apps",
167  {},
168  "The Apps that will be reset when 'reset_time' is hit. These are the App "
169  "'numbers' starting with 0 corresponding to the order of the App positions. "
170  "Resetting an App means that it is destroyed and recreated, possibly modeling "
171  "the insertion of 'new' material for that app.");
172 
173  // Moving subapps
174  params.addParam<Real>(
175  "move_time",
177  "The time at which Apps designated by move_apps are moved to move_positions.");
178 
179  params.addParam<std::vector<unsigned int>>(
180  "move_apps",
181  {},
182  "Apps, designated by their 'numbers' starting with 0 corresponding to the order "
183  "of the App positions, to be moved at move_time to move_positions");
184  params.addParam<std::vector<Point>>(
185  "move_positions", {}, "The positions corresponding to each move_app.");
186 
187  params.addParam<std::vector<CLIArgString>>(
188  "cli_args",
189  {},
190  "Additional command line arguments to pass to the sub apps. If one set is provided the "
191  "arguments are applied to all, otherwise there must be a set for each sub app.");
192 
193  params.addParam<std::vector<FileName>>(
194  "cli_args_files",
195  "File names that should be looked in for additional command line arguments "
196  "to pass to the sub apps. Each line of a file is set to each sub app. If only "
197  "one line is provided, it will be applied to all sub apps.");
198 
199  // Fixed point iterations
200  params.addRangeCheckedParam<Real>("relaxation_factor",
201  1.0,
202  "relaxation_factor>0 & relaxation_factor<2",
203  "Fraction of newly computed value to keep."
204  "Set between 0 and 2.");
205  params.addDeprecatedParam<std::vector<std::string>>(
206  "relaxed_variables",
207  {},
208  "Use transformed_variables.",
209  "List of subapp variables to relax during Multiapp coupling iterations");
210  params.addParam<std::vector<std::string>>(
211  "transformed_variables",
212  {},
213  "List of subapp variables to use coupling algorithm on during Multiapp coupling iterations");
214  params.addParam<std::vector<PostprocessorName>>(
215  "transformed_postprocessors",
216  {},
217  "List of subapp postprocessors to use coupling "
218  "algorithm on during Multiapp coupling iterations");
219  params.addParam<bool>("keep_solution_during_restore",
220  false,
221  "This is useful when doing MultiApp coupling iterations. It takes the "
222  "final solution from the previous coupling iteration"
223  "and re-uses it as the initial guess for the next coupling iteration");
224  params.addParam<bool>("keep_aux_solution_during_restore",
225  false,
226  "This is useful when doing MultiApp coupling iterations. It takes the "
227  "final auxiliary solution from the previous coupling iteration"
228  "and re-uses it as the initial guess for the next coupling iteration");
229  params.addParam<bool>(
230  "no_backup_and_restore",
231  false,
232  "True to turn off restore for this multiapp. This is useful when doing steady-state "
233  "Picard iterations where we want to use the solution of previous Picard iteration as the "
234  "initial guess of the current Picard iteration.");
235  params.addParam<unsigned int>(
236  "max_multiapp_level",
237  10,
238  "Integer set by user that will stop the simulation if the multiapp level "
239  "exceeds it. Useful for preventing infinite loops with multiapp simulations");
240  params.deprecateParam("no_backup_and_restore", "no_restore", "01/01/2025");
241 
242  params.addDeprecatedParam<bool>("clone_master_mesh",
243  false,
244  "True to clone parent app mesh and use it for this MultiApp.",
245  "clone_master_mesh is deprecated, use clone_parent_mesh instead");
246  params.addParam<bool>(
247  "clone_parent_mesh", false, "True to clone parent app mesh and use it for this MultiApp.");
248 
249  params.addPrivateParam<bool>("use_positions", true);
250  params.declareControllable("enable");
251  params.declareControllable("cli_args", {EXEC_PRE_MULTIAPP_SETUP});
252  params.registerBase("MultiApp");
253 
254  params.addParamNamesToGroup("use_displaced_mesh wait_for_first_app_init max_multiapp_level",
255  "Advanced");
256  params.addParamNamesToGroup("positions positions_file positions_objects run_in_position "
257  "output_in_position",
258  "Positions / transformations of the MultiApp frame of reference");
259  params.addParamNamesToGroup("min_procs_per_app max_procs_per_app", "Parallelism");
260  params.addParamNamesToGroup("reset_time reset_apps", "Reset MultiApp");
261  params.addParamNamesToGroup("move_time move_apps move_positions", "Timed move of MultiApps");
262  params.addParamNamesToGroup("relaxation_factor transformed_variables transformed_postprocessors "
263  "keep_solution_during_restore keep_aux_solution_during_restore "
264  "no_restore",
265  "Fixed point iteration");
266  params.addParamNamesToGroup("library_name library_path library_load_dependencies",
267  "Dynamic loading");
268  params.addParamNamesToGroup("cli_args cli_args_files", "Passing command line argument");
269  return params;
270 }
271 
273  : MooseObject(parameters),
274  SetupInterface(this),
275  Restartable(this, "MultiApps"),
276  PerfGraphInterface(this, std::string("MultiApp::") + _name),
277  _fe_problem(*getCheckedPointerParam<FEProblemBase *>("_fe_problem_base")),
278  _app_type(isParamValid("app_type") ? std::string(getParam<MooseEnum>("app_type"))
279  : _fe_problem.getMooseApp().type()),
280  _use_positions(getParam<bool>("use_positions")),
281  _input_files(getParam<std::vector<FileName>>("input_files")),
282  _wait_for_first_app_init(getParam<bool>("wait_for_first_app_init")),
283  _total_num_apps(0),
284  _my_num_apps(0),
285  _first_local_app(0),
286  _orig_comm(_communicator.get()),
287  _my_communicator(),
288  _my_comm(_my_communicator.get()),
289  _my_rank(0),
290  _inflation(getParam<Real>("bounding_box_inflation")),
291  _bounding_box_padding(getParam<Point>("bounding_box_padding")),
292  _max_procs_per_app(getParam<processor_id_type>("max_procs_per_app")),
293  _min_procs_per_app(getParam<processor_id_type>("min_procs_per_app")),
294  _output_in_position(getParam<bool>("output_in_position")),
295  _global_time_offset(getParam<Real>("global_time_offset")),
296  _reset_times(getParam<std::vector<Real>>("reset_time")),
297  _reset_apps(getParam<std::vector<unsigned int>>("reset_apps")),
298  _reset_happened(false),
299  _move_time(getParam<Real>("move_time")),
300  _move_apps(getParam<std::vector<unsigned int>>("move_apps")),
301  _move_positions(getParam<std::vector<Point>>("move_positions")),
302  _move_happened(false),
303  _has_an_app(true),
304  _cli_args(getParam<std::vector<CLIArgString>>("cli_args")),
305  _keep_solution_during_restore(getParam<bool>("keep_solution_during_restore")),
306  _keep_aux_solution_during_restore(getParam<bool>("keep_aux_solution_during_restore")),
307  _no_restore(getParam<bool>("no_restore")),
308  _run_in_position(getParam<bool>("run_in_position")),
309  _sub_app_backups(declareRestartableDataWithContext<SubAppBackups>("sub_app_backups", this)),
310  _solve_step_timer(registerTimedSection("solveStep", 3, "Executing MultiApps", false)),
311  _init_timer(registerTimedSection("init", 3, "Initializing MultiApp")),
312  _backup_timer(registerTimedSection("backup", 3, "Backing Up MultiApp")),
313  _restore_timer(registerTimedSection("restore", 3, "Restoring MultiApp")),
314  _reset_timer(registerTimedSection("resetApp", 3, "Resetting MultiApp"))
315 {
316  if (parameters.isParamSetByUser("cli_args") && parameters.isParamValid("cli_args") &&
317  parameters.isParamValid("cli_args_files"))
318  paramError("cli_args",
319  "'cli_args' and 'cli_args_files' cannot be specified simultaneously in MultiApp ");
320 
321  if (!_use_positions && (isParamValid("positions") || isParamValid("positions_file") ||
322  isParamValid("positions_objects")))
323  paramError("use_positions",
324  "This MultiApps has been set to not use positions, "
325  "but a 'positions' parameter has been set.");
326 
327  if ((_reset_apps.size() > 0 && _reset_times.size() == 0) ||
328  (_reset_apps.size() == 0 && _reset_times.size() > 0))
329  mooseError("reset_time and reset_apps may only be specified together");
330 
331  // Check that the reset times are sorted by the user
332  auto sorted_times = _reset_times;
333  std::sort(sorted_times.begin(), sorted_times.end());
334  if (_reset_times.size() && _reset_times != sorted_times)
335  paramError("reset_time", "List of reset times must be sorted in increasing order");
336 }
337 
338 void
339 MultiApp::init(unsigned int num_apps, bool batch_mode)
340 {
341  auto config = rankConfig(
342  processor_id(), n_processors(), num_apps, _min_procs_per_app, _max_procs_per_app, batch_mode);
343  init(num_apps, config);
344 }
345 
346 void
347 MultiApp::init(unsigned int num_apps, const LocalRankConfig & config)
348 {
349  TIME_SECTION(_init_timer);
350 
351  _total_num_apps = num_apps;
352  _rank_config = config;
353  buildComm();
355 
356  _has_bounding_box.resize(_my_num_apps, false);
357  _reset_happened.resize(_reset_times.size(), false);
358  _bounding_box.resize(_my_num_apps);
359 
360  if ((_cli_args.size() > 1) && (_total_num_apps != _cli_args.size()))
361  paramError("cli_args",
362  "The number of items supplied must be 1 or equal to the number of sub apps.");
363 
364  // if cliArgs() != _cli_args, then cliArgs() was overridden and we need to check it
365  auto cla = cliArgs();
366  if (cla != std::vector<std::string>(_cli_args.begin(), _cli_args.end()))
367  {
368  if ((cla.size() > 1) && (_total_num_apps != cla.size()))
369  mooseError("The number of items supplied as command line argument to subapps must be 1 or "
370  "equal to the number of sub apps. Note: you use a multiapp that provides its own "
371  "command line parameters so the error is not in cli_args");
372  }
373 }
374 
375 void
377 {
378  if (_use_positions)
379  {
380  fillPositions();
381  init(_positions.size());
382  createApps();
383  }
384 }
385 
386 void
388 {
389  if (!_has_an_app)
390  return;
391 
392  TIME_SECTION("createApps", 2, "Instantiating Sub-Apps", false);
393 
394  // Read commandLine arguments that will be used when creating apps
396 
398 
399  _apps.resize(_my_num_apps);
400 
401  // If the user provided an unregistered app type, see if we can load it dynamically
402  if (!AppFactory::instance().isRegistered(_app_type))
404  getParam<std::string>("library_path"),
405  getParam<std::string>("library_name"),
406  getParam<bool>("library_load_dependencies"));
407 
408  bool rank_did_quiet_init = false;
409  unsigned int local_app = libMesh::invalid_uint;
411  {
412  if (hasLocalApp(0))
413  {
414  rank_did_quiet_init = true;
415  local_app = globalAppToLocal(0);
416  createLocalApp(local_app);
417  }
418 
419  MPI_Barrier(_orig_comm);
420  }
421 
422  for (unsigned int i = 0; i < _my_num_apps; i++)
423  {
424  if (rank_did_quiet_init && i == local_app)
425  continue;
426  createLocalApp(i);
427  }
428 }
429 
430 void
431 MultiApp::createLocalApp(const unsigned int i)
432 {
434 }
435 
436 void
438 {
439  if (!_use_positions)
440  // if not using positions, we create the sub-apps in initialSetup instead of right after
441  // construction of MultiApp
442  createApps();
443 }
444 
445 void
447 {
448  if (isParamValid("cli_args_files"))
449  {
450  _cli_args_from_file.clear();
451 
452  std::vector<FileName> cli_args_files = getParam<std::vector<FileName>>("cli_args_files");
453  std::vector<FileName> input_files = getParam<std::vector<FileName>>("input_files");
454 
455  // If we use parameter "cli_args_files", at least one file should be provided
456  if (!cli_args_files.size())
457  paramError("cli_args_files", "You need to provide at least one commandLine argument file ");
458 
459  // If we multiple input files, then we need to check if the number of input files
460  // match with the number of argument files
461  if (cli_args_files.size() != 1 && cli_args_files.size() != input_files.size())
462  paramError("cli_args_files",
463  "The number of commandLine argument files ",
464  cli_args_files.size(),
465  " for MultiApp ",
466  name(),
467  " must either be only one or match the number of input files ",
468  input_files.size());
469 
470  // Go through all argument files
471  std::vector<std::string> cli_args;
472  for (unsigned int p_file_it = 0; p_file_it < cli_args_files.size(); p_file_it++)
473  {
474  std::string cli_args_file = cli_args_files[p_file_it];
475  // Clear up
476  cli_args.clear();
477  // Read the file on the root processor then broadcast it
478  if (processor_id() == 0)
479  {
480  MooseUtils::checkFileReadable(cli_args_file);
481 
482  std::ifstream is(cli_args_file.c_str());
483  // Read by line rather than space separated like the cli_args parameter
484  std::string line;
485  while (std::getline(is, line))
486  cli_args.push_back(line);
487 
488  // We do not allow empty files
489  if (!cli_args.size())
490  paramError("cli_args_files",
491  "There is no commandLine argument in the commandLine argument file ",
492  cli_args_file);
493 
494  // If we have position files, we need to
495  // make sure the number of commandLine argument strings
496  // match with the number of positions
497  if (_npositions_inputfile.size())
498  {
499  auto num_positions = _npositions_inputfile[p_file_it];
500  // Check if the number of commandLine argument strings equal to
501  // the number of positions
502  if (cli_args.size() == 1)
503  for (MooseIndex(num_positions) num = 0; num < num_positions; num++)
504  _cli_args_from_file.push_back(cli_args.front());
505  else if (cli_args.size() == num_positions)
506  for (auto && cli_arg : cli_args)
507  _cli_args_from_file.push_back(cli_arg);
508  else if (cli_args.size() != num_positions)
509  paramError("cli_args_files",
510  "The number of commandLine argument strings ",
511  cli_args.size(),
512  " in the file ",
513  cli_args_file,
514  " must either be only one or match the number of positions ",
515  num_positions);
516  }
517  else
518  {
519  // If we do not have position files, we will check if the number of
520  // commandLine argument strings match with the total number of subapps
521  for (auto && cli_arg : cli_args)
522  _cli_args_from_file.push_back(cli_arg);
523  }
524  }
525  }
526 
527  // Broad cast all arguments to everyone
529  }
530 
531  if (_cli_args_from_file.size() && _cli_args_from_file.size() != 1 &&
533  mooseError(" The number of commandLine argument strings ",
534  _cli_args_from_file.size(),
535  " must either be only one or match the total "
536  "number of sub apps ",
538 
539  if (_cli_args_from_file.size() && cliArgs().size())
540  mooseError("Cannot set commandLine arguments from both input_file and external files");
541 }
542 
543 void
545 {
546  if (_move_apps.size() != _move_positions.size())
547  mooseError("The number of apps to move and the positions to move them to must be the same for "
548  "MultiApp ",
549  _name);
550 
551  if (isParamValid("positions") + isParamValid("positions_file") +
552  isParamValid("positions_objects") >
553  1)
554  mooseError("Only one 'positions' parameter may be specified");
555 
556  if (isParamValid("positions"))
557  {
558  _positions = getParam<std::vector<Point>>("positions");
559 
560  if (_positions.size() < _input_files.size())
561  mooseError("Not enough positions for the number of input files provided in MultiApp ",
562  name());
563  }
564  else if (isParamValid("positions_file"))
565  {
566  std::vector<FileName> positions_files = getParam<std::vector<FileName>>("positions_file");
567  std::vector<FileName> input_files = getParam<std::vector<FileName>>("input_files");
568 
569  if (input_files.size() != 1 && positions_files.size() != input_files.size())
570  mooseError("Number of input_files for MultiApp ",
571  name(),
572  " must either be only one or match the number of positions_file files");
573 
574  // Clear out the _input_files because we're going to rebuild it
575  if (input_files.size() != 1)
576  _input_files.clear();
577 
578  for (unsigned int p_file_it = 0; p_file_it < positions_files.size(); p_file_it++)
579  {
580  std::string positions_file = positions_files[p_file_it];
581  MooseUtils::DelimitedFileReader file(positions_file, &_communicator);
583  file.read();
584 
585  const std::vector<Point> & data = file.getDataAsPoints();
586  for (const auto & d : data)
587  _positions.push_back(d);
588 
589  // Save the number of positions for this input file
590  _npositions_inputfile.push_back(data.size());
591 
592  for (unsigned int i = 0; i < data.size(); ++i)
593  if (input_files.size() != 1)
594  _input_files.push_back(input_files[p_file_it]);
595  }
596  }
597  else if (isParamValid("positions_objects"))
598  {
599  const auto & positions_param_objs = getParam<std::vector<PositionsName>>("positions_objects");
600  const auto & input_files = getParam<std::vector<FileName>>("input_files");
601 
602  if (input_files.size() != 1 && positions_param_objs.size() != input_files.size())
603  mooseError("Number of input_files for MultiApp ",
604  name(),
605  " must either be only one or match the number of positions_objects specified");
606 
607  // Clear out the _input_files because we're going to rebuild it
608  if (input_files.size() != 1)
609  _input_files.clear();
610 
611  // Keeps track of where each positions object start in terms of subapp numbers
612  unsigned int offset = 0;
613 
614  for (const auto p_obj_it : index_range(positions_param_objs))
615  {
616  const std::string & positions_name = positions_param_objs[p_obj_it];
617  auto positions_obj = &_fe_problem.getPositionsObject(positions_name);
618 
619  const auto & data = positions_obj->getPositions(true);
620 
621  // Append all positions from this object
622  for (const auto & d : data)
623  _positions.push_back(d);
624 
625  // Save the number of positions for this input file
626  _npositions_inputfile.push_back(data.size());
627 
628  if (!positions_obj)
629  paramError("positions_objects",
630  "'" + positions_name + "' is not of the expected type. Should be a Positions");
631 
632  // Keep track of which positions is tied to what subapp
633  for (unsigned int i = 0; i < data.size(); ++i)
634  {
635  if (input_files.size() != 1)
636  _input_files.push_back(input_files[p_obj_it]);
637  _positions_objs.push_back(positions_obj);
638  _positions_index_offsets.push_back(offset);
639  }
640  offset += data.size();
641  }
642  }
643  else
644  {
645  _positions = {Point()};
646 
647  if (_positions.size() < _input_files.size())
648  mooseError("Not enough positions for the number of input files provided in MultiApp ",
649  name());
650  }
651 
652  mooseAssert(_input_files.size() == 1 || _positions.size() == _input_files.size(),
653  "Number of positions and input files are not the same!");
654 }
655 
656 void
657 MultiApp::preTransfer(Real /*dt*/, Real target_time)
658 {
659  // Get a transient executioner to get a user-set tolerance
660  Real timestep_tol = 1e-13;
661  if (dynamic_cast<TransientBase *>(_fe_problem.getMooseApp().getExecutioner()))
662  timestep_tol =
663  dynamic_cast<TransientBase *>(_fe_problem.getMooseApp().getExecutioner())->timestepTol();
664 
665  // Determination on whether we need to backup the app due to changes below
666  bool backup_apps = false;
667 
668  // First, see if any Apps need to be reset
669  for (unsigned int i = 0; i < _reset_times.size(); i++)
670  {
671  if (!_reset_happened[i] && (target_time + timestep_tol >= _reset_times[i]))
672  {
673  _reset_happened[i] = true;
674  if (_reset_apps.size() > 0)
675  for (auto & app : _reset_apps)
676  resetApp(app);
677 
678  // If we reset an application, then we delete the old objects, including the coordinate
679  // transformation classes. Consequently we need to reset the coordinate transformation classes
680  // in the associated transfer classes
681  for (auto * const transfer : _associated_transfers)
682  transfer->getAppInfo();
683 
684  // Similarly we need to transform the mesh again
685  if (_run_in_position)
686  for (const auto i : make_range(_my_num_apps))
687  {
688  auto app_ptr = _apps[i];
689  if (usingPositions())
690  app_ptr->getExecutioner()->feProblem().coordTransform().transformMesh(
691  app_ptr->getExecutioner()->feProblem().mesh(), _positions[_first_local_app + i]);
692  else
693  app_ptr->getExecutioner()->feProblem().coordTransform().transformMesh(
694  app_ptr->getExecutioner()->feProblem().mesh(), Point(0, 0, 0));
695  }
696 
697  // If the time step covers multiple reset times, set them all as having 'happened'
698  for (unsigned int j = i; j < _reset_times.size(); j++)
699  if (target_time + timestep_tol >= _reset_times[j])
700  _reset_happened[j] = true;
701 
702  // Backup in case the next solve fails
703  backup_apps = true;
704 
705  break;
706  }
707  }
708 
709  // Now move any apps that should be moved
710  if (_use_positions && !_move_happened && target_time + timestep_tol >= _move_time)
711  {
712  _move_happened = true;
713  for (unsigned int i = 0; i < _move_apps.size(); i++)
715 
716  // Backup in case the next solve fails
717  backup_apps = true;
718  }
719 
720  if (backup_apps)
721  backup();
722 }
723 
724 Executioner *
725 MultiApp::getExecutioner(unsigned int app)
726 {
727  if (!_has_an_app)
728  mooseError("No app for ", name(), " on processor ", _orig_rank);
729 
730  return _apps[globalAppToLocal(app)]->getExecutioner();
731 }
732 
733 void
735 {
736  for (const auto & app_ptr : _apps)
737  {
738  auto * executioner = app_ptr->getExecutioner();
739  mooseAssert(executioner, "Executioner is nullptr");
740 
741  executioner->feProblem().execute(EXEC_FINAL);
742  executioner->feProblem().outputStep(EXEC_FINAL);
743  }
744 }
745 
746 void
748 {
749  for (const auto & app_ptr : _apps)
750  {
751  auto * executioner = app_ptr->getExecutioner();
752  mooseAssert(executioner, "Executioner is nullptr");
753 
754  executioner->postExecute();
755  }
756 }
757 
758 void
760 {
761  TIME_SECTION(_backup_timer);
762 
764  _console << "Backed up MultiApp ... ";
765 
766  for (unsigned int i = 0; i < _my_num_apps; i++)
767  _sub_app_backups[i] = _apps[i]->backup();
768 
770  _console << name() << std::endl;
771 }
772 
773 void
774 MultiApp::restore(bool force)
775 {
776  TIME_SECTION(_restore_timer);
777 
778  if (force || needsRestoration())
779  {
780  // Must be restarting / recovering from main app so hold off on restoring
781  // Instead - the restore will happen in sub-apps' initialSetup()
782  // Note that _backups was already populated by dataLoad() in the main app
784  return;
785 
786  // We temporarily copy and store solutions for all subapps
788  {
790 
791  for (unsigned int i = 0; i < _my_num_apps; i++)
792  {
793  _end_solutions[i].resize(_apps[i]->getExecutioner()->feProblem().numSolverSystems());
794  for (unsigned int j = 0; j < _apps[i]->getExecutioner()->feProblem().numSolverSystems();
795  j++)
796  {
797  _end_solutions[i][j] = _apps[i]
798  ->getExecutioner()
799  ->feProblem()
800  .getSolverSystem(/*solver_sys=*/j)
801  .solution()
802  .clone();
803  }
804  auto & sub_multiapps =
805  _apps[i]->getExecutioner()->feProblem().getMultiAppWarehouse().getObjects();
806 
807  // multiapps of each subapp should do the same things
808  // It is implemented recursively
809  for (auto & multi_app : sub_multiapps)
810  multi_app->keepSolutionDuringRestore(_keep_solution_during_restore);
811  }
812  }
813 
814  // We temporarily copy and store solutions for all subapps
816  {
818 
819  for (unsigned int i = 0; i < _my_num_apps; i++)
820  _end_aux_solutions[i] =
822  }
823 
825  _console << "Restoring MultiApp ... ";
826 
827  for (unsigned int i = 0; i < _my_num_apps; i++)
828  {
829  _apps[i]->restore(std::move(_sub_app_backups[i]), false);
830  _sub_app_backups[i] = _apps[i]->finalizeRestore();
831  mooseAssert(_sub_app_backups[i], "Should have a backup");
832  }
833 
835  _console << name() << std::endl;
836 
837  // Now copy the latest solutions back for each subapp
839  {
840  for (unsigned int i = 0; i < _my_num_apps; i++)
841  {
842  for (unsigned int j = 0; j < _apps[i]->getExecutioner()->feProblem().numSolverSystems();
843  j++)
844  {
845  _apps[i]->getExecutioner()->feProblem().getSolverSystem(/*solver_sys=*/j).solution() =
846  *_end_solutions[i][j];
847 
848  // We need to synchronize solution so that local_solution has the right values
849  _apps[i]->getExecutioner()->feProblem().getSolverSystem(/*solver_sys=*/j).update();
850  }
851  }
852 
853  _end_solutions.clear();
854  }
855  // Now copy the latest auxiliary solutions back for each subapp
857  {
858  for (unsigned int i = 0; i < _my_num_apps; i++)
859  {
860  _apps[i]->getExecutioner()->feProblem().getAuxiliarySystem().solution() =
861  *_end_aux_solutions[i];
862 
863  // We need to synchronize solution so that local_solution has the right values
864  _apps[i]->getExecutioner()->feProblem().getAuxiliarySystem().update();
865  }
866 
867  _end_aux_solutions.clear();
868  }
869 
870  // Make sure the displaced mesh on the multiapp is up-to-date with displacement variables
871  for (const auto & app_ptr : _apps)
872  if (app_ptr->feProblem().getDisplacedProblem())
873  app_ptr->feProblem().getDisplacedProblem()->updateMesh();
874 
875  // If we are restoring due to a failed solve, make sure reset the solved state in the sub-apps
876  if (!getMooseApp().getExecutioner()->lastSolveConverged())
877  for (auto & app_ptr : _apps)
878  app_ptr->getExecutioner()->fixedPointSolve().clearFixedPointStatus();
879  }
880  else
881  {
882  for (unsigned int i = 0; i < _my_num_apps; i++)
883  {
884  for (auto & sub_app :
885  _apps[i]->getExecutioner()->feProblem().getMultiAppWarehouse().getObjects())
886  sub_app->restore(false);
887  }
888  }
889 }
890 
891 void
892 MultiApp::keepSolutionDuringRestore(bool keep_solution_during_restore)
893 {
894  if (_pars.isParamSetByUser("keep_solution_during_restore"))
895  paramError("keep_solution_during_restore",
896  "This parameter should only be provided in parent app");
897 
898  _keep_solution_during_restore = keep_solution_during_restore;
899 }
900 
901 void
902 MultiApp::transformBoundingBox(BoundingBox & box, const MultiAppCoordTransform & transform)
903 {
904  const Real min_x = box.first(0);
905  const Real max_x = box.second(0);
906  const Real min_y = box.first(1);
907  const Real max_y = box.second(1);
908  const Real min_z = box.first(2);
909  const Real max_z = box.second(2);
910 
911  std::array<Point, 8> box_corners = {{Point(min_x, min_y, min_z),
912  Point(max_x, min_y, min_z),
913  Point(min_x, max_y, min_z),
914  Point(max_x, max_y, min_z),
915  Point(min_x, min_y, max_z),
916  Point(max_x, min_y, max_z),
917  Point(min_x, max_y, max_z),
918  Point(max_x, max_y, max_z)}};
919 
920  // transform each corner
921  for (auto & corner : box_corners)
922  corner = transform(corner);
923 
924  // Create new bounding box
925  Point new_box_min = box_corners[0];
926  Point new_box_max = new_box_min;
927  for (const auto p : make_range(1, 8))
928  for (const auto d : make_range(Moose::dim))
929  {
930  const Point & pt = box_corners[p];
931  if (new_box_min(d) > pt(d))
932  new_box_min(d) = pt(d);
933 
934  if (new_box_max(d) < pt(d))
935  new_box_max(d) = pt(d);
936  }
937  box.first = new_box_min;
938  box.second = new_box_max;
939 }
940 
941 BoundingBox
942 MultiApp::getBoundingBox(unsigned int app,
943  bool displaced_mesh,
944  const MultiAppCoordTransform * const coord_transform)
945 {
946  if (!_has_an_app)
947  mooseError("No app for ", name(), " on processor ", _orig_rank);
948 
949  unsigned int local_app = globalAppToLocal(app);
950  FEProblemBase & fe_problem_base = _apps[local_app]->getExecutioner()->feProblem();
951  MooseMesh & mesh = (displaced_mesh && fe_problem_base.getDisplacedProblem().get() != NULL)
952  ? fe_problem_base.getDisplacedProblem()->mesh()
953  : fe_problem_base.mesh();
954 
955  {
957  if (displaced_mesh)
958  _bounding_box[local_app] = MeshTools::create_bounding_box(mesh);
959  else
960  {
961  if (!_has_bounding_box[local_app])
962  {
963  _bounding_box[local_app] = MeshTools::create_bounding_box(mesh);
964  _has_bounding_box[local_app] = true;
965  }
966  }
967  }
968  BoundingBox bbox = _bounding_box[local_app];
969 
970  Point min = bbox.min();
972  Point max = bbox.max();
974 
975  Point inflation_amount = (max - min) * _inflation;
976 
977  Point inflated_min = min - inflation_amount;
978  Point inflated_max = max + inflation_amount;
979 
980  Point shifted_min = inflated_min;
981  Point shifted_max = inflated_max;
982 
983  if ((!coord_transform || coord_transform->skipCoordinateCollapsing()) &&
984  fe_problem_base.getCoordSystem(*(mesh.meshSubdomains().begin())) == Moose::COORD_RZ)
985  {
986  // If the problem is RZ then we're going to invent a box that would cover the whole "3D" app
987  // FIXME: Assuming all subdomains are the same coordinate system type!
988  shifted_min(0) = -inflated_max(0);
989  shifted_min(1) = inflated_min(1);
990  shifted_min(2) = -inflated_max(0);
991 
992  shifted_max(0) = inflated_max(0);
993  shifted_max(1) = inflated_max(1);
994  shifted_max(2) = inflated_max(0);
995  }
996 
997  if (coord_transform)
998  {
999  BoundingBox transformed_bbox(shifted_min, shifted_max);
1000  transformBoundingBox(transformed_bbox, *coord_transform);
1001  return transformed_bbox;
1002  }
1003  else
1004  {
1005  // This is where the app is located. We need to shift by this amount.
1006  Point p = position(app);
1007 
1008  // Shift them to the position they're supposed to be
1009  shifted_min += p;
1010  shifted_max += p;
1011  return BoundingBox(shifted_min, shifted_max);
1012  }
1013 }
1014 
1015 FEProblemBase &
1016 MultiApp::appProblemBase(unsigned int app)
1017 {
1018  if (!_has_an_app)
1019  mooseError("No app for ", name(), " on processor ", _orig_rank);
1020 
1021  unsigned int local_app = globalAppToLocal(app);
1022 
1023  return _apps[local_app]->getExecutioner()->feProblem();
1024 }
1025 
1026 FEProblem &
1027 MultiApp::appProblem(unsigned int app)
1028 {
1030  "MultiApp::appProblem() is deprecated, call MultiApp::appProblemBase() instead.\n");
1031  if (!_has_an_app)
1032  mooseError("No app for ", name(), " on processor ", _orig_rank);
1033 
1034  unsigned int local_app = globalAppToLocal(app);
1035 
1036  return dynamic_cast<FEProblem &>(_apps[local_app]->getExecutioner()->feProblem());
1037 }
1038 
1039 const UserObject &
1040 MultiApp::appUserObjectBase(unsigned int app, const std::string & name)
1041 {
1042  if (!_has_an_app)
1043  mooseError("No app for ", MultiApp::name(), " on processor ", _orig_rank);
1044 
1045  return appProblemBase(app).getUserObjectBase(name);
1046 }
1047 
1048 Real
1049 MultiApp::appPostprocessorValue(unsigned int app, const std::string & name)
1050 {
1051  if (!_has_an_app)
1052  mooseError("No app for ", MultiApp::name(), " on processor ", _orig_rank);
1053 
1055 }
1056 
1058 MultiApp::appTransferVector(unsigned int app, std::string var_name)
1059 {
1060  return *(appProblemBase(app).getSystem(var_name).solution);
1061 }
1062 
1063 bool
1065 {
1067 }
1068 
1069 bool
1070 MultiApp::hasLocalApp(unsigned int global_app) const
1071 {
1072  if (_has_an_app && global_app >= _first_local_app &&
1073  global_app <= _first_local_app + (_my_num_apps - 1))
1074  return true;
1075 
1076  return false;
1077 }
1078 
1079 MooseApp *
1080 MultiApp::localApp(unsigned int local_app)
1081 {
1082  mooseAssert(local_app < _apps.size(), "Index out of range: " + Moose::stringify(local_app));
1083  return _apps[local_app].get();
1084 }
1085 
1086 void
1087 MultiApp::resetApp(unsigned int global_app, Real time)
1088 {
1089  TIME_SECTION(_reset_timer);
1090 
1092 
1093  if (hasLocalApp(global_app))
1094  {
1095  unsigned int local_app = globalAppToLocal(global_app);
1096 
1097  // Extract the file numbers from the output, so that the numbering is maintained after reset
1098  std::map<std::string, unsigned int> m = _apps[local_app]->getOutputWarehouse().getFileNumbers();
1099 
1100  createApp(local_app, time);
1101 
1102  // Reset the file numbers of the newly reset apps
1103  _apps[local_app]->getOutputWarehouse().setFileNumbers(m);
1104  }
1105 }
1106 
1107 void
1108 MultiApp::moveApp(unsigned int global_app, Point p)
1109 {
1110  if (_use_positions)
1111  {
1112  _positions[global_app] = p;
1113 
1114  if (hasLocalApp(global_app))
1115  {
1116  unsigned int local_app = globalAppToLocal(global_app);
1117 
1118  if (_output_in_position)
1119  _apps[local_app]->setOutputPosition(p);
1120  if (_run_in_position)
1121  paramError("run_in_position", "Moving apps and running apps in position is not supported");
1122  }
1123  }
1124 }
1125 
1126 void
1128 {
1130  for (unsigned int i = 0; i < _apps.size(); i++)
1131  _apps[i]->setOutputPosition(_app.getOutputPosition() + _positions[_first_local_app + i]);
1132 }
1133 
1134 void
1135 MultiApp::createApp(unsigned int i, Real start_time)
1136 {
1137  // Delete the old app if we're resetting
1138  if (_apps[i])
1139  _apps[i].reset();
1140 
1141  // Define the app name
1142  const std::string multiapp_name = getMultiAppName(name(), _first_local_app + i, _total_num_apps);
1143  std::string full_name;
1144 
1145  // Only add parent name if the parent is not the main app
1146  if (_app.multiAppLevel() > 0)
1147  full_name = _app.name() + "_" + multiapp_name;
1148  else
1149  full_name = multiapp_name;
1150 
1152  app_params.set<FEProblemBase *>("_parent_fep") = &_fe_problem;
1153  app_params.set<std::unique_ptr<Backup> *>("_initial_backup") = &_sub_app_backups[i];
1154 
1155  // Build the CommandLine with the relevant options for this subapp and add the
1156  // cli args from the input file
1157  std::vector<std::string> input_cli_args;
1158  if (cliArgs().size() > 0 || _cli_args_from_file.size() > 0)
1159  input_cli_args = getCommandLineArgs(i);
1160  // This will mark all hit CLI command line parameters that are passed to subapps
1161  // as used within the parent app (_app)
1162  auto app_cli = _app.commandLine()->initSubAppCommandLine(name(), multiapp_name, input_cli_args);
1163  app_cli->parse();
1164 
1166  _console << COLOR_CYAN << "Creating MultiApp " << name() << " of type " << _app_type
1167  << " of level " << _app.multiAppLevel() + 1 << " and number " << _first_local_app + i
1168  << " on processor " << processor_id() << " with full name " << full_name
1169  << COLOR_DEFAULT << std::endl;
1170  app_params.set<unsigned int>("_multiapp_level") = _app.multiAppLevel() + 1;
1171  app_params.set<unsigned int>("_multiapp_number") = _first_local_app + i;
1172  app_params.set<const MooseMesh *>("_master_mesh") = &_fe_problem.mesh();
1173 #ifdef MOOSE_MFEM_ENABLED
1174  app_params.set<std::shared_ptr<mfem::Device>>("_mfem_device") =
1176  const auto & mfem_device_set = _app.getMFEMDevices(Moose::PassKey<MultiApp>());
1177  app_params.set<std::set<std::string>>("_mfem_devices") = mfem_device_set;
1178 #endif
1179  if (getParam<bool>("clone_master_mesh") || getParam<bool>("clone_parent_mesh"))
1180  {
1182  _console << COLOR_CYAN << "Cloned parent app mesh will be used for MultiApp " << name()
1183  << COLOR_DEFAULT << std::endl;
1184  app_params.set<bool>("_use_master_mesh") = true;
1186  if (displaced_problem)
1187  app_params.set<const MooseMesh *>("_master_displaced_mesh") = &displaced_problem->mesh();
1188  }
1189 
1190  // If only one input file was provided, use it for all the solves
1191  const auto input_index = _input_files.size() == 1 ? 0 : _first_local_app + i;
1192  const auto & input_file = _input_files[input_index];
1193 
1194  // create new parser tree for the application and parse
1195  auto parser = std::make_unique<Parser>(input_file);
1196  parser->setCommandLineParams(app_cli->buildHitParams());
1197  parser->parse();
1198 
1199  // Checks on app type
1200  const auto & app_type = parser->getAppType();
1201  if (app_type.empty() && _app_type.empty())
1202  mooseWarning("The application type is not specified for ",
1203  full_name,
1204  ". Please use [Application] block to specify the application type.");
1205  if (!app_type.empty() && app_type != _app_type && !AppFactory::instance().isRegistered(app_type))
1206  mooseError("In the ",
1207  full_name,
1208  ", '",
1209  app_type,
1210  "' is not a registered application. The registered application is named: '",
1211  _app_type,
1212  "'. Please double check the [Application] block to make sure the correct "
1213  "application is provided. \n");
1214 
1215  if (parser->getAppType().empty())
1216  parser->setAppType(_app_type);
1217 
1218  app_params.set<std::shared_ptr<Parser>>("_parser") = std::move(parser);
1219  app_params.set<std::shared_ptr<CommandLine>>("_command_line") = std::move(app_cli);
1220  _apps[i] = AppFactory::instance().create(_app_type, full_name, app_params, _my_comm);
1221  auto & app = _apps[i];
1222 
1223  app->setGlobalTimeOffset(start_time);
1224  app->setOutputFileNumbers(_app.getOutputWarehouse().getFileNumbers());
1225  app->setRestart(_app.isRestarting());
1226  app->setRecover(_app.isRecovering());
1227 
1228  if (_use_positions && getParam<bool>("output_in_position"))
1229  app->setOutputPosition(_app.getOutputPosition() + _positions[_first_local_app + i]);
1231  paramError("run_in_position",
1232  "Sub-apps are already displaced, so they are already output in position");
1233 
1234  // Update the MultiApp level for the app that was just created
1235  app->setupOptions();
1236  // if multiapp does not have file base in Outputs input block, output file base will
1237  // be empty here since setupOptions() does not set the default file base with the multiapp
1238  // input file name. Parent app will create the default file base for multiapp by taking the
1239  // output base of the parent app problem and appending the name of the multiapp plus a number to
1240  // it
1241  if (app->getOutputFileBase().empty())
1243  preRunInputFile();
1244  if (_app.multiAppLevel() > getParam<unsigned int>("max_multiapp_level"))
1245  mooseError("Maximum multiapp level has been reached. This is likely caused by an infinite loop "
1246  "in your multiapp system. If additional multiapp levels are needed, "
1247  "max_multiapp_level can be specified in the MuliApps block.");
1248 
1249  // Transfer coupling relaxation information to the subapps
1250  _apps[i]->fixedPointConfig().sub_relaxation_factor = getParam<Real>("relaxation_factor");
1251  _apps[i]->fixedPointConfig().sub_transformed_vars =
1252  getParam<std::vector<std::string>>("transformed_variables");
1253  // Handle deprecated parameter
1254  if (!parameters().isParamSetByAddParam("relaxed_variables"))
1255  _apps[i]->fixedPointConfig().sub_transformed_vars =
1256  getParam<std::vector<std::string>>("relaxed_variables");
1257  _apps[i]->fixedPointConfig().sub_transformed_pps =
1258  getParam<std::vector<PostprocessorName>>("transformed_postprocessors");
1259 
1260  app->runInputFile();
1261  auto fixed_point_solve = &(_apps[i]->getExecutioner()->fixedPointSolve());
1262  if (fixed_point_solve)
1263  fixed_point_solve->allocateStorage(false);
1264 
1265  // Transform the app mesh if requested
1266  if (_run_in_position)
1267  {
1268  if (usingPositions())
1269  app->getExecutioner()->feProblem().coordTransform().transformMesh(
1270  app->getExecutioner()->feProblem().mesh(), _positions[_first_local_app + i]);
1271  else
1272  app->getExecutioner()->feProblem().coordTransform().transformMesh(
1273  app->getExecutioner()->feProblem().mesh(), Point(0, 0, 0));
1274  }
1275 }
1276 
1277 std::vector<std::string>
1278 MultiApp::getCommandLineArgs(const unsigned int local_app)
1279 {
1280  const auto cla = cliArgs();
1281  auto cli_args_param = _cli_args_param;
1282  std::string combined_args;
1283 
1284  // Single set of args from cliArgs() to be provided to all apps
1285  if (cla.size() == 1)
1286  combined_args = cla[0];
1287  // Single "cli_args_files" file to be provided to all apps
1288  else if (_cli_args_from_file.size() == 1)
1289  {
1290  cli_args_param = "cli_args_files";
1291  combined_args = _cli_args_from_file[0];
1292  }
1293  // Unique set of args from cliArgs() to be provided to each app
1294  else if (cla.size())
1295  combined_args = cla[local_app + _first_local_app];
1296  // Unique set of args from "cli_args_files" to be provided to all apps
1297  else
1298  {
1299  cli_args_param = "cli_args_files";
1300  combined_args = _cli_args_from_file[local_app + _first_local_app];
1301  }
1302 
1303  // Remove all of the beginning and end whitespace so we can recognize truly empty
1304  combined_args = MooseUtils::trim(combined_args);
1305 
1306  // MooseUtils::split will return a single empty entry if there is nothing,
1307  // so exit early if we have nothing
1308  if (combined_args.empty())
1309  return {};
1310 
1311  // Split the argument into a vector of arguments, and make sure
1312  // that we don't have any empty arguments
1313  const auto args = MooseUtils::split(combined_args, ";");
1314  for (const auto & arg : args)
1315  {
1316  if (arg.empty())
1317  {
1318  const auto error = "An empty MultiApp command line argument was provided. Your "
1319  "combined command line string has a ';' with no argument after it.";
1320  if (cli_args_param)
1321  paramError(*cli_args_param, error);
1322  else
1323  mooseError(error);
1324  }
1325  }
1326 
1327  return args;
1328 }
1329 
1332  processor_id_type nprocs,
1333  dof_id_type napps,
1334  processor_id_type min_app_procs,
1335  processor_id_type max_app_procs,
1336  bool batch_mode)
1337 {
1338  if (min_app_procs > nprocs)
1339  mooseError("minimum number of procs per app is higher than the available number of procs");
1340  else if (min_app_procs > max_app_procs)
1341  mooseError("minimum number of procs per app must be lower than the max procs per app");
1342 
1343  mooseAssert(rank < nprocs, "rank must be smaller than the number of procs");
1344 
1345  // A "slot" is a group of procs/ranks that are grouped together to run a
1346  // single (sub)app/sim in parallel.
1347 
1348  const processor_id_type slot_size =
1349  std::max(std::min(cast_int<processor_id_type>(nprocs / napps), max_app_procs), min_app_procs);
1350  const processor_id_type nslots = std::min(
1351  nprocs / slot_size,
1352  cast_int<processor_id_type>(std::min(
1353  static_cast<dof_id_type>(std::numeric_limits<processor_id_type>::max()), napps)));
1354  mooseAssert(nprocs >= (nslots * slot_size),
1355  "Ensure that leftover procs is represented by an unsigned type");
1356  const processor_id_type leftover_procs = nprocs - nslots * slot_size;
1357  const dof_id_type apps_per_slot = napps / nslots;
1358  const dof_id_type leftover_apps = napps % nslots;
1359 
1360  std::vector<int> slot_for_rank(nprocs);
1361  processor_id_type slot = 0;
1362  processor_id_type procs_in_slot = 0;
1363  for (processor_id_type rankiter = 0; rankiter <= rank; rankiter++)
1364  {
1365  if (slot < nslots)
1366  slot_for_rank[rankiter] = cast_int<int>(slot);
1367  else
1368  slot_for_rank[rankiter] = -1;
1369  procs_in_slot++;
1370  // this slot keeps growing until we reach slot size plus possibly an extra
1371  // proc if there were any leftover from the slotization of nprocs - this
1372  // must also make sure we don't go over max app procs.
1373  if (procs_in_slot == slot_size + 1 * (slot < leftover_procs && slot_size < max_app_procs))
1374  {
1375  procs_in_slot = 0;
1376  slot++;
1377  }
1378  }
1379 
1380  if (slot_for_rank[rank] < 0)
1381  // ranks assigned a negative slot don't have any apps running on them.
1382  return {0, 0, 0, 0, false, 0};
1383  const processor_id_type slot_num = cast_int<processor_id_type>(slot_for_rank[rank]);
1384 
1385  const bool is_first_local_rank = rank == 0 || (slot_for_rank[rank - 1] != slot_for_rank[rank]);
1386  const dof_id_type n_local_apps = apps_per_slot + 1 * (slot_num < leftover_apps);
1387 
1388  processor_id_type my_first_rank = 0;
1389  for (processor_id_type rankiter = rank; rankiter > 0; rankiter--)
1390  if (slot_for_rank[rank] != slot_for_rank[rankiter])
1391  {
1392  my_first_rank = cast_int<processor_id_type>(slot_for_rank[rankiter + 1]);
1393  break;
1394  }
1395 
1396  dof_id_type app_index = 0;
1397  for (processor_id_type slot = 0; slot < slot_num; slot++)
1398  {
1399  const dof_id_type num_slot_apps = apps_per_slot + 1 * (slot < leftover_apps);
1400  app_index += num_slot_apps;
1401  }
1402 
1403  if (batch_mode)
1404  return {n_local_apps, app_index, 1, slot_num, is_first_local_rank, my_first_rank};
1405  return {n_local_apps, app_index, n_local_apps, app_index, is_first_local_rank, my_first_rank};
1406 }
1407 
1408 void
1410 {
1411  int ierr;
1412 
1413  ierr = MPI_Comm_size(_communicator.get(), &_orig_num_procs);
1414  mooseCheckMPIErr(ierr);
1415  ierr = MPI_Comm_rank(_communicator.get(), &_orig_rank);
1416  mooseCheckMPIErr(ierr);
1417 
1418 #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
1419  struct utsname sysInfo;
1420  uname(&sysInfo);
1421  _node_name = sysInfo.nodename;
1422 #else
1423  _node_name = "Unknown";
1424 #endif
1425 
1426  int rank;
1427  ierr = MPI_Comm_rank(_communicator.get(), &rank);
1428  mooseCheckMPIErr(ierr);
1429 
1432 
1435  mooseError("Internal error, a processor has an undefined app.");
1436 
1437  if (_has_an_app)
1438  {
1440  ierr = MPI_Comm_rank(_my_comm, &_my_rank);
1441  mooseCheckMPIErr(ierr);
1442  }
1443  else
1444  {
1445  _communicator.split(MPI_UNDEFINED, rank, _my_communicator);
1446  _my_rank = 0;
1447  }
1448 }
1449 
1450 unsigned int
1451 MultiApp::globalAppToLocal(unsigned int global_app)
1452 {
1453  if (global_app >= _first_local_app && global_app <= _first_local_app + (_my_num_apps - 1))
1454  return global_app - _first_local_app;
1455 
1456  std::stringstream ss;
1457  ss << "Requesting app " << global_app << ", but processor " << processor_id() << " ";
1458  if (_my_num_apps == 0)
1459  ss << "does not own any apps";
1460  else if (_my_num_apps == 1)
1461  ss << "owns app " << _first_local_app;
1462  else
1463  ss << "owns apps " << _first_local_app << "-" << _first_local_app + (_my_num_apps - 1);
1464  ss << ".";
1465  mooseError("Invalid global_app!\n", ss.str());
1466  return 0;
1467 }
1468 
1469 void
1471 {
1472 }
1473 
1474 void
1476 {
1477  _associated_transfers.push_back(&transfer);
1478 }
1479 
1480 void
1482 {
1483  for (unsigned int i = 0; i < _my_num_apps; ++i)
1485 }
1486 
1487 std::vector<std::string>
1489 {
1490  // So that we can error out with paramError("cli_args", ...);
1491  _cli_args_param = "cli_args";
1492  return std::vector<std::string>(_cli_args.begin(), _cli_args.end());
1493 }
1494 
1495 void
1497 {
1498  const std::string multiapp_name =
1500  _apps[index]->setOutputFileBase(_app.getOutputFileBase() + "_" + multiapp_name);
1501 }
1502 
1503 std::string
1504 MultiApp::getMultiAppName(const std::string & base_name, dof_id_type index, dof_id_type total)
1505 {
1506  std::ostringstream multiapp_name;
1507  multiapp_name << base_name << std::setw(std::ceil(std::log10(total))) << std::setprecision(0)
1508  << std::setfill('0') << std::right << index;
1509  return multiapp_name.str();
1510 }
1511 
1512 const Point &
1513 MultiApp::position(unsigned int app) const
1514 {
1515  // If we're not using positions, it won't have changed
1516  if (_positions_objs.empty())
1517  return _positions[app];
1518  else
1519  // Find which Positions object is specifying it, and query a potentially updated value
1520  return _positions_objs[app]->getPosition(app - _positions_index_offsets[app], false);
1521 }
1522 
1523 void
1524 dataStore(std::ostream & stream, SubAppBackups & backups, void * context)
1525 {
1526  MultiApp * multi_app = static_cast<MultiApp *>(context);
1527  mooseAssert(multi_app, "Not set");
1528 
1529  multi_app->backup();
1530 
1531  dataStore(stream, static_cast<std::vector<std::unique_ptr<Backup>> &>(backups), nullptr);
1532 }
1533 
1534 void
1535 dataLoad(std::istream & stream, SubAppBackups & backups, void * context)
1536 {
1537  MultiApp * multi_app = static_cast<MultiApp *>(context);
1538  mooseAssert(multi_app, "Not set");
1539 
1540  dataLoad(stream, static_cast<std::vector<std::unique_ptr<Backup>> &>(backups), nullptr);
1541 
1542  multi_app->restore();
1543 }
bool isRegistered(const std::string &app_name) const
Returns a Boolean indicating whether an application type has been registered.
Definition: AppFactory.h:169
void keepSolutionDuringRestore(bool keep_solution_during_restore)
Preserve the solution from the previous simulation, and it is used as an initial guess for the next r...
Definition: MultiApp.C:892
bool hasLocalApp(unsigned int global_app) const
Whether or not the given global app number is on this processor.
Definition: MultiApp.C:1070
std::vector< unsigned int > _reset_apps
The apps to be reset.
Definition: MultiApp.h:571
const std::set< std::string > & getMFEMDevices(Moose::PassKey< MultiApp >) const
Get the configured MFEM devices.
Definition: MooseApp.h:1621
bool needsRestoration()
Whether or not this MultiApp should be restored at the beginning of each Picard iteration.
Definition: MultiApp.h:210
virtual libMesh::System & getSystem(const std::string &var_name) override
Returns the equation system containing the variable provided.
A MultiMooseEnum object to hold "execute_on" flags.
Definition: ExecFlagEnum.h:21
A class for creating restricted objects.
Definition: Restartable.h:28
MultiApp(const InputParameters &parameters)
Definition: MultiApp.C:272
std::vector< libMesh::BoundingBox > _bounding_box
This multi-app&#39;s bounding box.
Definition: MultiApp.h:547
const InputParameters & _pars
The object&#39;s parameters.
Definition: MooseBase.h:362
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
std::vector< const Positions * > _positions_objs
The positions of all of the apps, using the Positions system.
Definition: MultiApp.h:490
std::shared_ptr< DisplacedProblem > displaced_problem
const unsigned int invalid_uint
const std::string & _name
The name of this class.
Definition: MooseBase.h:359
virtual void restore(bool force=true)
Restore the state of every Sub App.
Definition: MultiApp.C:774
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:435
virtual void backup()
Save off the state of every Sub App.
Definition: MultiApp.C:759
bool verboseMultiApps() const
Whether or not to use verbose printing for MultiApps.
NumericVector< Number > & solution()
Definition: SystemBase.h:196
const bool _use_positions
Toggle use of "positions".
Definition: MultiApp.h:496
void setDocString(const std::string &name, const std::string &doc)
Set the doc string of a parameter.
void addPrivateParam(const std::string &name, const T &value)
These method add a parameter to the InputParameters object which can be retrieved like any other para...
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
Definition: FEProblem.h:20
const std::vector< CLIArgString > & _cli_args
CommandLine arguments (controllable!)
Definition: MultiApp.h:592
std::vector< unsigned int > _npositions_inputfile
Number of positions for each input file.
Definition: MultiApp.h:505
void dataLoad(std::istream &stream, SubAppBackups &backups, void *context)
Definition: MultiApp.C:1535
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
void setupPositions()
Called just after construction to allow derived classes to set _positions and create sub-apps accordi...
Definition: MultiApp.C:376
std::shared_ptr< CommandLine > commandLine() const
Get the command line.
Definition: MooseApp.h:411
std::vector< unsigned int > _positions_index_offsets
The offsets, in case multiple Positions objects are specified.
Definition: MultiApp.h:492
const std::vector< Point > getDataAsPoints() const
Get the data in Point format.
Real _move_time
The time at which to move apps.
Definition: MultiApp.h:577
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
Real appPostprocessorValue(unsigned int app, const std::string &name)
Get a Postprocessor value for a specified global app.
Definition: MultiApp.C:1049
int _orig_rank
The mpi "rank" of this processor in the original communicator.
Definition: MultiApp.h:532
LocalRankConfig _rank_config
The app configuration resulting from calling init.
Definition: MultiApp.h:614
std::optional< std::string > _cli_args_param
The parameter that was used to set the command line args, if any.
Definition: MultiApp.h:634
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:127
std::string getOutputFileBase(bool for_non_moose_build_output=false) const
Get the output file base name.
Definition: MooseApp.C:1669
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1133
std::vector< std::shared_ptr< MooseApp > > _apps
Pointers to each of the Apps.
Definition: MultiApp.h:541
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
dof_id_type first_local_app_index
The (global) index of the first local app for this rank.
Definition: MultiApp.h:64
FEProblemBase & feProblem()
Return a reference to this Executioner&#39;s FEProblemBase instance.
Definition: Executioner.C:124
unsigned int multiAppLevel() const
The MultiApp Level.
Definition: MooseApp.h:802
virtual void parentOutputPositionChanged()
For apps outputting in position we need to change their output positions if their parent app moves...
Definition: MultiApp.C:1127
MeshBase & mesh
std::vector< Point > _move_positions
The new positions for the apps to be moved.
Definition: MultiApp.h:583
Base class for MOOSE-based applications.
Definition: MooseApp.h:96
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
void dataStore(std::ostream &stream, SubAppBackups &backups, void *context)
Definition: MultiApp.C:1524
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:159
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
Add additional execute_on flags to the list of possible flags.
Definition: ExecFlagEnum.h:82
const PerfID _restore_timer
Definition: MultiApp.h:629
virtual std::unique_ptr< NumericVector< Number > > clone() const =0
const Parallel::Communicator & _communicator
Real _inflation
Relative bounding box inflation.
Definition: MultiApp.h:550
FEProblemBase & _fe_problem
The FEProblemBase this MultiApp is part of.
Definition: MultiApp.h:482
bool isRestarting() const
Whether or not this is a "restart" calculation.
Definition: MooseApp.C:1807
const Positions & getPositionsObject(const std::string &name) const
Get the Positions object by its name.
virtual std::vector< std::string > getCommandLineArgs(const unsigned int local_app)
Definition: MultiApp.C:1278
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
processor_id_type _min_procs_per_app
Minimum number of processors to give to each app.
Definition: MultiApp.h:559
int _orig_num_procs
The number of processors in the original comm.
Definition: MultiApp.h:529
MooseApp & getMooseApp() const
Get the MooseApp this class is associated with.
Definition: MooseBase.h:83
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
const PerfID _backup_timer
Definition: MultiApp.h:628
auto max(const L &left, const R &right)
std::vector< std::string > split(const std::string &str, const std::string &delimiter, std::size_t max_count=std::numeric_limits< std::size_t >::max())
Python like split functions for strings.
Definition: MooseUtils.C:1027
std::vector< Real > _reset_times
The times at which to reset apps.
Definition: MultiApp.h:568
virtual void preTransfer(Real dt, Real target_time)
Gets called just before transfers are done to the MultiApp (Which is just before the MultiApp is solv...
Definition: MultiApp.C:657
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
void createApps()
Create the provided number of apps.
Definition: MultiApp.C:387
static std::unique_ptr< MooseApp > create(const std::string &app_type, const std::vector< std::string > &cli_args={})
Create an app with no input and command line arguments.
Definition: AppFactory.C:62
virtual libMesh::BoundingBox getBoundingBox(unsigned int app, bool displaced_mesh, const MultiAppCoordTransform *coord_transform=nullptr)
Get the BoundingBox for the mesh associated with app The bounding box will be shifted to be in the co...
Definition: MultiApp.C:942
uint8_t processor_id_type
bool isParamSetByAddParam(const std::string &name) const
Returns whether or not the parameter was set due to addParam.
processor_id_type n_processors() const
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
const bool & _wait_for_first_app_init
Whether to create the first app on rank 0 while all other MPI ranks are idle.
Definition: MultiApp.h:502
const auto & registeredObjects() const
Returns a reference to the map from names to AppFactoryBuildInfo pointers.
Definition: AppFactory.h:164
static void transformBoundingBox(libMesh::BoundingBox &box, const MultiAppCoordTransform &transform)
Transform a bounding box according to the transformations in the provided coordinate transformation o...
Definition: MultiApp.C:902
virtual libMesh::NumericVector< libMesh::Number > & appTransferVector(unsigned int app, std::string var_name)
Get the vector to transfer to for this MultiApp.
Definition: MultiApp.C:1058
bool _keep_solution_during_restore
Flag indicates if or not restart from the latest solution.
Definition: MultiApp.h:598
void deprecateParam(const std::string &old_name, const std::string &new_name, const std::string &removal_date)
Every object that can be built by the factory should be derived from this class.
Definition: MooseObject.h:27
std::map< std::string, unsigned int > getFileNumbers()
Extracts the file numbers from the output objects.
processor_id_type _max_procs_per_app
Maximum number of processors to give to each app.
Definition: MultiApp.h:556
virtual std::vector< std::string > cliArgs() const
function that provides cli_args to subapps
Definition: MultiApp.C:1488
void mooseDeprecated(Args &&... args) const
Definition: MooseBase.h:310
const ExecFlagType EXEC_TIMESTEP_BEGIN
Definition: Moose.C:37
virtual void fillPositions()
must fill in _positions with the positions of the sub-aps
Definition: MultiApp.C:544
const ExecFlagType EXEC_PRE_MULTIAPP_SETUP
Definition: Moose.C:54
bool _move_happened
Whether or not the move has happened.
Definition: MultiApp.h:586
std::vector< MultiAppTransfer * > _associated_transfers
Transfers associated with this multiapp.
Definition: MultiApp.h:617
Helper class for holding Sub-app backups.
Definition: MultiApp.h:100
const PerfID _reset_timer
Definition: MultiApp.h:630
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
Checks to see if a file is readable (exists and permissions)
Definition: MooseUtils.C:250
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
std::vector< std::unique_ptr< NumericVector< Real > > > _end_aux_solutions
The auxiliary solution from the end of the previous solve, this is cloned from the auxiliary solution...
Definition: MultiApp.h:611
std::string _app_type
The type of application to build.
Definition: MultiApp.h:485
std::unique_ptr< NumericVector< Number > > solution
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
void split(int color, int key, Communicator &target) const
FEProblemBase & appProblemBase(unsigned int app)
Get the FEProblemBase for the global app desired.
Definition: MultiApp.C:1016
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
PetscErrorCode PetscInt const PetscInt IS * is
std::vector< unsigned int > _move_apps
The apps to be moved.
Definition: MultiApp.h:580
Executioners are objects that do the actual work of solving your problem.
Definition: Executioner.h:30
Base class for transient executioners that use a FixedPointSolve solve object for multiapp-main app i...
Definition: TransientBase.h:27
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:353
void read()
Perform the actual data reading.
const std::vector< Point > & getPositions(bool initial) const
{ Getters for the positions vector for the desired dimension 1D will be the only one guaranteed to su...
Definition: Positions.C:116
void buildComm()
Create an MPI communicator suitable for each app.
Definition: MultiApp.C:1409
virtual void resetApp(unsigned int global_app, Real time=0.0)
"Reset" the App corresponding to the global App number passed in.
Definition: MultiApp.C:1087
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
AuxiliarySystem & getAuxiliarySystem()
static InputParameters validParams()
bool isFirstLocalRank() const
Definition: MultiApp.C:1064
Interface for objects interacting with the PerfGraph.
const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name, std::size_t t_index=0) const
Get a read-only reference to the value associated with a Postprocessor that exists.
unsigned int _total_num_apps
The total number of apps to simulate.
Definition: MultiApp.h:511
void skipCoordinateCollapsing(bool skip_coordinate_collapsing)
set whether coordinate collapsing operations should be skipped
LocalRankConfig rankConfig(processor_id_type rank, processor_id_type nprocs, dof_id_type napps, processor_id_type min_app_procs, processor_id_type max_app_procs, bool batch_mode)
Returns app partitioning information relevant to the given rank for a multiapp scenario with the give...
Definition: MultiApp.C:1331
Executioner * getExecutioner() const
Retrieve the Executioner for this App.
Definition: MooseApp.C:2123
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
Point getOutputPosition() const
Get the output position.
Definition: MooseApp.h:275
unsigned int _my_num_apps
The number of apps this object is involved in simulating.
Definition: MultiApp.h:514
static std::string getMultiAppName(const std::string &base_name, dof_id_type index, dof_id_type total)
Helper for constructing the name of the multiapp.
Definition: MultiApp.C:1504
std::string _node_name
Node Name.
Definition: MultiApp.h:535
static AppFactory & instance()
Get the instance of the AppFactory.
Definition: AppFactory.C:18
bool _has_an_app
Whether or not this processor as an App at all
Definition: MultiApp.h:589
libMesh::Parallel::Communicator _my_communicator
The communicator object that holds the MPI_Comm that we&#39;re going to use.
Definition: MultiApp.h:523
void createApp(unsigned int i, Real start_time)
Helper function for creating an App instance.
Definition: MultiApp.C:1135
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
bool usingPositions() const
Whether or not this MultiApp is using positions or its own way for constructing sub-apps.
Definition: MultiApp.h:363
const PerfID _init_timer
Definition: MultiApp.h:627
unsigned int _first_local_app
The number of the first app on this processor.
Definition: MultiApp.h:517
void addAssociatedTransfer(MultiAppTransfer &transfer)
Add a transfer that is associated with this multiapp.
Definition: MultiApp.C:1475
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
MooseApp * localApp(unsigned int local_app)
Get the local MooseApp object.
Definition: MultiApp.C:1080
virtual void initialSetup() override
Method to be called in main-app initial setup for create sub-apps if using positions is false...
Definition: MultiApp.C:437
Utility class for reading delimited data (e.g., CSV data).
std::vector< std::vector< std::unique_ptr< libMesh::NumericVector< Real > > > > _end_solutions
The solution from the end of the previous solve, this is cloned from the Nonlinear solution during re...
Definition: MultiApp.h:608
Base class for all MultiAppTransfer objects.
bool is_first_local_rank
This is true if this rank is the primary/zero rank for a (sub)app slot.
Definition: MultiApp.h:71
FEProblem & appProblem(unsigned int app)
Get the FEProblem for the global app is part of.
Definition: MultiApp.C:1027
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
Definition: MooseBase.h:295
IntRange< T > make_range(T beg, T end)
SubAppBackups & _sub_app_backups
The cached subapp backups (passed from the parent app)
Definition: MultiApp.h:623
virtual MooseMesh & mesh() override
virtual void postExecute()
Method called at the end of the simulation (after finalize).
Definition: MultiApp.C:747
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
bool _keep_aux_solution_during_restore
Flag indicates if or not restart the auxiliary system from the latest auxiliary solution.
Definition: MultiApp.h:601
bool _output_in_position
Whether or not to move the output of the MultiApp into position.
Definition: MultiApp.h:562
std::vector< Point > _positions
The positions of all of the apps, using input constant vectors (to be deprecated) ...
Definition: MultiApp.h:488
virtual void finalize()
Method called towards the end of the simulation to execute on final.
Definition: MultiApp.C:734
void readCommandLineArguments()
Fill command line arguments for sub apps.
Definition: MultiApp.C:446
int _my_rank
The mpi "rank" of this processor in the sub communicator.
Definition: MultiApp.h:538
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
Moose::CoordinateSystemType getCoordSystem(SubdomainID sid) const
Definition: SubProblem.C:1278
dof_id_type num_local_apps
The number of (sub)apps that should/will be run locally on this rank.
Definition: MultiApp.h:58
virtual void createLocalApp(const unsigned int i)
Create the i-th local app.
Definition: MultiApp.C:431
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::vector< FileName > _input_files
The input file for each app&#39;s simulation.
Definition: MultiApp.h:499
Holds app partitioning information relevant to the a particular rank for a multiapp scenario...
Definition: MultiApp.h:46
virtual void preRunInputFile()
call back executed right before app->runInputFile()
Definition: MultiApp.C:1470
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
InputParameters getValidParams(const std::string &name)
Get valid parameters for the object.
Definition: AppFactory.C:33
const UserObject & getUserObjectBase(const std::string &name, const THREAD_ID tid=0) const
Get the user object by its name.
Point _bounding_box_padding
Additional padding added to the bounding box, useful for 1D meshes.
Definition: MultiApp.h:553
const Real _global_time_offset
The offset time so the MultiApp local time relative to the global time.
Definition: MultiApp.h:565
void init(unsigned int num_apps, bool batch_mode=false)
Build communicators and reserve backups.
Definition: MultiApp.C:339
static InputParameters validParams()
Definition: MooseObject.C:25
const MPI_Comm & _orig_comm
The original comm handle.
Definition: MultiApp.h:520
static InputParameters validParams()
Definition: MultiApp.C:50
A MultiApp represents one or more MOOSE applications that are running simultaneously.
Definition: MultiApp.h:112
processor_id_type processor_id() const
void setAppOutputFileBase()
Sets all the app&#39;s output file bases.
Definition: MultiApp.C:1481
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition: MooseApp.C:1801
auto min(const L &left, const R &right)
std::shared_ptr< mfem::Device > getMFEMDevice(Moose::PassKey< MultiApp >)
Get the MFEM device object.
Definition: MooseApp.h:1079
MPI_Comm & _my_comm
The MPI communicator this object is going to use.
Definition: MultiApp.h:526
const ExecFlagType EXEC_FINAL
Definition: Moose.C:46
void declareControllable(const std::string &name, std::set< ExecFlagType > execute_flags={})
Declare the given parameters as controllable.
const bool _run_in_position
Whether to run the child apps with their meshes transformed with the coordinate transforms.
Definition: MultiApp.h:620
virtual void moveApp(unsigned int global_app, Point p)
Move the global_app to Point p.
Definition: MultiApp.C:1108
void ErrorVector unsigned int
virtual Executioner * getExecutioner(unsigned int app)
Definition: MultiApp.C:725
auto index_range(const T &sizable)
Base class for user-specific data.
Definition: UserObject.h:40
const Point & position(unsigned int app) const
The physical position of a global App number.
Definition: MultiApp.C:1513
OutputWarehouse & getOutputWarehouse()
Get the OutputWarehouse objects.
Definition: MooseApp.C:2442
std::vector< std::string > _cli_args_from_file
CommandLine arguments from files.
Definition: MultiApp.h:595
const UserObject & appUserObjectBase(unsigned int app, const std::string &name)
Get a UserObject base for a specific global app.
Definition: MultiApp.C:1040
const ExecFlagType EXEC_POST_ADAPTIVITY
Definition: Moose.C:58
uint8_t dof_id_type
unsigned int globalAppToLocal(unsigned int global_app)
Map a global App number to the local number.
Definition: MultiApp.C:1451
This class contains transformation information that only exists in a context in which there are multi...
void dynamicAppRegistration(const std::string &app_name, std::string library_path, const std::string &library_name, bool lib_load_deps)
Definition: MooseApp.C:2614
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
std::vector< bool > _reset_happened
Whether or not apps have been reset at each time.
Definition: MultiApp.h:574
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.
const ExecFlagType EXEC_INITIAL
Definition: Moose.C:30
std::vector< bool > _has_bounding_box
Flag if this multi-app computed its bounding box (valid only for non-displaced meshes) ...
Definition: MultiApp.h:544