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