Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : // MOOSE includes
11 : #include "TransientMultiApp.h"
12 :
13 : #include "AllLocalDofIndicesThread.h"
14 : #include "AuxiliarySystem.h"
15 : #include "Console.h"
16 : #include "LayeredSideDiffusiveFluxAverage.h"
17 : #include "MooseMesh.h"
18 : #include "Output.h"
19 : #include "TimeStepper.h"
20 : #include "TransientBase.h"
21 : #include "NonlinearSystem.h"
22 :
23 : #include "libmesh/mesh_tools.h"
24 : #include "libmesh/numeric_vector.h"
25 :
26 : registerMooseObject("MooseApp", TransientMultiApp);
27 :
28 : InputParameters
29 53687 : TransientMultiApp::validParams()
30 : {
31 53687 : InputParameters params = MultiApp::validParams();
32 53687 : params += TransientInterface::validParams();
33 53687 : params.addClassDescription("MultiApp for performing coupled simulations with the parent and "
34 : "sub-application both progressing in time.");
35 :
36 161061 : params.addParam<bool>("sub_cycling",
37 107374 : false,
38 : "Set to true to allow this MultiApp to take smaller "
39 : "timesteps than the rest of the simulation. More "
40 : "than one timestep will be performed for each "
41 : "parent application timestep");
42 :
43 161061 : params.addParam<bool>("interpolate_transfers",
44 107374 : false,
45 : "Only valid when sub_cycling. This allows "
46 : "transferred values to be interpolated "
47 : "over the time frame the MultiApp is "
48 : "executing over when sub_cycling");
49 :
50 161061 : params.addParam<bool>("detect_steady_state",
51 107374 : false,
52 : "If true, then if/while sub-cycling ('sub_cycling = true'), a steady-state "
53 : "check will be performed for each child app, allowing them to skip to the "
54 : "end of the parent time step if steady conditions are detected.");
55 :
56 53687 : params.addParam<bool>("output_sub_cycles", false, "If true then every sub-cycle will be output.");
57 161061 : params.addParam<bool>(
58 107374 : "print_sub_cycles", true, "Toggle the display of sub-cycles on the screen.");
59 :
60 161061 : params.addParam<unsigned int>(
61 107374 : "max_failures", 0, "Maximum number of solve failures tolerated while sub_cycling.");
62 :
63 53687 : params.addParamNamesToGroup("sub_cycling interpolate_transfers detect_steady_state "
64 : "output_sub_cycles print_sub_cycles max_failures",
65 : "Sub cycling");
66 :
67 161061 : params.addParam<bool>("tolerate_failure",
68 107374 : false,
69 : "If true this MultiApp won't participate in dt "
70 : "decisions and will always be fast-forwarded to "
71 : "the current time.");
72 :
73 161061 : params.addParam<bool>(
74 : "catch_up",
75 107374 : false,
76 : "If true this will allow failed solves to attempt to 'catch up' using smaller timesteps.");
77 :
78 161061 : params.addParam<Real>("max_catch_up_steps",
79 107374 : 2,
80 : "Maximum number of steps to allow an app to take "
81 : "when trying to catch back up after a failed "
82 : "solve.");
83 :
84 53687 : params.addParamNamesToGroup("catch_up max_catch_up_steps", "Recovering failed solutions");
85 53687 : params.addParamNamesToGroup("tolerate_failure", "Accepting failed solutions");
86 :
87 53687 : return params;
88 0 : }
89 :
90 5446 : TransientMultiApp::TransientMultiApp(const InputParameters & parameters)
91 : : MultiApp(parameters),
92 5438 : _sub_cycling(getParam<bool>("sub_cycling")),
93 5438 : _interpolate_transfers(getParam<bool>("interpolate_transfers")),
94 5438 : _detect_steady_state(getParam<bool>("detect_steady_state")),
95 5438 : _output_sub_cycles(getParam<bool>("output_sub_cycles")),
96 5438 : _max_failures(getParam<unsigned int>("max_failures")),
97 5438 : _tolerate_failure(getParam<bool>("tolerate_failure")),
98 5438 : _failures(0),
99 5438 : _catch_up(getParam<bool>("catch_up")),
100 5438 : _max_catch_up_steps(getParam<Real>("max_catch_up_steps")),
101 5438 : _first(declareRecoverableData<bool>("first", true)),
102 5438 : _auto_advance(false),
103 10884 : _print_sub_cycles(getParam<bool>("print_sub_cycles"))
104 : {
105 : // Transfer interpolation only makes sense for sub-cycling solves
106 5438 : if (_interpolate_transfers && !_sub_cycling)
107 0 : paramError("interpolate_transfers",
108 : "MultiApp ",
109 0 : name(),
110 : " is set to interpolate_transfers but is not sub_cycling! That is not valid!");
111 :
112 : // Subcycling overrides catch up, we don't want to confuse users by allowing them to set both.
113 5438 : if (_sub_cycling && _catch_up)
114 4 : paramError("catch_up",
115 : "MultiApp ",
116 4 : name(),
117 : " \"sub_cycling\" and \"catch_up\" cannot both be set to true simultaneously.");
118 :
119 5434 : if (_sub_cycling && _keep_solution_during_restore)
120 0 : paramError("keep_solution_during_restore",
121 : "In MultiApp ",
122 0 : name(),
123 : " it doesn't make any sense to keep a solution during restore when doing "
124 : "sub_cycling. Consider trying \"catch_up\" steps instead");
125 :
126 5434 : if (!_catch_up && _keep_solution_during_restore)
127 0 : paramError("keep_solution_during_restore",
128 : "In MultiApp ",
129 0 : name(),
130 : " \"keep_solution_during_restore\" requires \"catch_up = true\". Either disable "
131 : "\"keep_solution_during_restart\" or set \"catch_up = true\"");
132 :
133 5434 : if (_sub_cycling && _tolerate_failure)
134 0 : paramInfo("tolerate_failure",
135 : "In MultiApp ",
136 0 : name(),
137 : " both \"sub_cycling\" and \"tolerate_failure\" are set to true. \"tolerate_failure\""
138 : " will be ignored.");
139 5434 : }
140 :
141 : NumericVector<Number> &
142 1129 : TransientMultiApp::appTransferVector(unsigned int app, std::string var_name)
143 : {
144 1129 : if (std::find(_transferred_vars.begin(), _transferred_vars.end(), var_name) ==
145 2258 : _transferred_vars.end())
146 956 : _transferred_vars.push_back(var_name);
147 :
148 1129 : if (_interpolate_transfers)
149 214 : return appProblemBase(app).getAuxiliarySystem().system().get_vector("transfer");
150 :
151 915 : return appProblemBase(app).getAuxiliarySystem().solution();
152 : }
153 :
154 : void
155 5335 : TransientMultiApp::initialSetup()
156 : {
157 5335 : MultiApp::initialSetup();
158 :
159 5335 : if (!_has_an_app)
160 54 : return;
161 :
162 5281 : Moose::ScopedCommSwapper swapper(_my_comm);
163 :
164 5281 : if (_has_an_app)
165 : {
166 5281 : _transient_executioners.resize(_my_num_apps);
167 : // Grab Transient Executioners from each app
168 13647 : for (unsigned int i = 0; i < _my_num_apps; i++)
169 8370 : setupApp(i);
170 : }
171 5277 : }
172 :
173 : bool
174 64405 : TransientMultiApp::solveStep(Real dt, Real target_time, bool auto_advance)
175 : {
176 64405 : if (!_has_an_app)
177 85 : return true;
178 :
179 64320 : TIME_SECTION(_solve_step_timer);
180 :
181 64320 : _auto_advance = auto_advance;
182 :
183 64320 : if (_fe_problem.verboseMultiApps())
184 1912 : _console << COLOR_CYAN << "Solving MultiApp '" << name() << "' with target time " << target_time
185 1912 : << " and dt " << dt << " with auto-advance " << (auto_advance ? "on" : "off")
186 1912 : << COLOR_DEFAULT << std::endl;
187 :
188 : // "target_time" must always be in global time
189 64320 : target_time += _app.getGlobalTimeOffset();
190 :
191 64320 : Moose::ScopedCommSwapper swapper(_my_comm);
192 64320 : bool return_value = true;
193 :
194 : // Make sure we swap back the communicator regardless of how this routine is exited
195 : try
196 : {
197 : int rank;
198 : int ierr;
199 64320 : ierr = MPI_Comm_rank(_communicator.get(), &rank);
200 64320 : mooseCheckMPIErr(ierr);
201 :
202 135737 : for (unsigned int i = 0; i < _my_num_apps; i++)
203 : {
204 71518 : FEProblemBase & problem = appProblemBase(_first_local_app + i);
205 :
206 71518 : TransientBase * ex = _transient_executioners[i];
207 :
208 : // The App might have a different local time from the rest of the problem
209 71518 : Real app_time_offset = _apps[i]->getGlobalTimeOffset();
210 :
211 : // Maybe this MultiApp was already solved
212 142759 : if ((ex->getTime() + app_time_offset + ex->timestepTol() >= target_time) ||
213 71241 : (ex->getTime() >= ex->endTime()))
214 299 : continue;
215 :
216 : // Examine global time synchronization
217 71219 : if (!_sub_cycling && !_reset_happened.size())
218 : {
219 : // The multi-app general offset is substracted to go into local time.
220 68830 : if (std::abs(target_time - _app.getGlobalTimeOffset() - ex->getTime() - dt) >
221 68830 : ex->timestepTol())
222 77 : mooseDoOnce(mooseWarning(
223 : "The target time (time a multiapp must reach at the end of the time step) "
224 : "is desynchronized between this app and subapp ",
225 : i,
226 : ".\n If this is desired: use the 'global_time_offset' multiapp parameter to "
227 : "declare a constant offset\n"
228 : "If the apps should (eventually) be synchronized in time, please either: \n"
229 : " - match the 'start_time' in the main app and the multiapp, in the Executioner "
230 : "block\n"
231 : " - set 'sub_cycling' to true in the multiapp parameters\n"
232 : "This message will only print once for all apps and all time steps."));
233 : }
234 :
235 71215 : if (_sub_cycling)
236 : {
237 1734 : Real time_old = ex->getTime() + app_time_offset;
238 :
239 1734 : if (_interpolate_transfers)
240 : {
241 175 : AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
242 175 : System & libmesh_aux_system = aux_system.system();
243 :
244 175 : NumericVector<Number> & solution = *libmesh_aux_system.solution;
245 175 : NumericVector<Number> & transfer_old = libmesh_aux_system.get_vector("transfer_old");
246 :
247 175 : solution.close();
248 :
249 : // Save off the current auxiliary solution
250 175 : transfer_old = solution;
251 :
252 175 : transfer_old.close();
253 :
254 : // Snag all of the local dof indices for all of these variables
255 175 : AllLocalDofIndicesThread aldit(problem, _transferred_vars);
256 175 : ConstElemRange & elem_range = *problem.mesh().getActiveLocalElementRange();
257 175 : Threads::parallel_reduce(elem_range, aldit);
258 :
259 175 : _transferred_dofs = aldit.getDofIndices();
260 175 : }
261 :
262 : // Disable/enable output for sub cycling
263 1734 : problem.allowOutput(_output_sub_cycles); // disables all outputs, including console
264 1734 : problem.allowOutput<Console>(_print_sub_cycles); // re-enables Console to print, if desired
265 :
266 1734 : ex->setTargetTime(target_time - app_time_offset);
267 :
268 : // unsigned int failures = 0;
269 :
270 1734 : bool at_steady = false;
271 :
272 : // ADL: During restart, there is already an FEProblemBase::advanceState that occurs at the
273 : // end of TransientMultiApp::setupApp. advanceState, along with copying the solutions
274 : // backwards in time/state, also *moves* (note it doesn't copy!) stateful material
275 : // properties backwards (through swapping). So if restarting from a full-solve steady
276 : // multi-app for example, then after one advance state, we will have good information in old
277 : // and no information in current. But then if we advance again we no longer have good data
278 : // in the old material properties, so don't advance here if we're restarting
279 1734 : if (_first && !_app.isRecovering() && !_app.isRestarting())
280 189 : problem.advanceState();
281 :
282 1734 : bool local_first = _first;
283 :
284 : // Now do all of the solves we need
285 9687 : while ((!at_steady && ex->getTime() + app_time_offset + ex->timestepTol() < target_time) ||
286 1715 : !ex->lastSolveConverged())
287 : {
288 6257 : if (local_first != true)
289 6067 : ex->incrementStepOrReject();
290 :
291 6257 : local_first = false;
292 :
293 6257 : ex->preStep();
294 6257 : ex->computeDT();
295 :
296 6257 : if (_interpolate_transfers)
297 : {
298 : // See what time this executioner is going to go to.
299 1624 : Real future_time = ex->getTime() + app_time_offset + ex->getDT();
300 :
301 : // How far along we are towards the target time:
302 1624 : Real step_percent = (future_time - time_old) / (target_time - time_old);
303 :
304 1624 : Real one_minus_step_percent = 1.0 - step_percent;
305 :
306 : // Do the interpolation for each variable that was transferred to
307 1624 : FEProblemBase & problem = appProblemBase(_first_local_app + i);
308 1624 : AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
309 1624 : System & libmesh_aux_system = aux_system.system();
310 :
311 1624 : NumericVector<Number> & solution = *libmesh_aux_system.solution;
312 1624 : NumericVector<Number> & transfer = libmesh_aux_system.get_vector("transfer");
313 1624 : NumericVector<Number> & transfer_old = libmesh_aux_system.get_vector("transfer_old");
314 :
315 1624 : solution.close(); // Just to be sure
316 1624 : transfer.close();
317 1624 : transfer_old.close();
318 :
319 494390 : for (const auto & dof : _transferred_dofs)
320 : {
321 985532 : solution.set(dof,
322 492766 : (transfer_old(dof) * one_minus_step_percent) +
323 492766 : (transfer(dof) * step_percent));
324 : // solution.set(dof, transfer_old(dof));
325 : // solution.set(dof, transfer(dof));
326 : // solution.set(dof, 1);
327 : }
328 :
329 1624 : solution.close();
330 : }
331 :
332 6257 : ex->takeStep();
333 :
334 6257 : bool converged = ex->lastSolveConverged();
335 :
336 6257 : if (!converged)
337 : {
338 38 : mooseWarning(
339 19 : "While sub_cycling ", name(), _first_local_app + i, " failed to converge!\n");
340 :
341 19 : _failures++;
342 :
343 19 : if (_failures > _max_failures)
344 : {
345 19 : std::stringstream oss;
346 19 : oss << "While sub_cycling " << name() << _first_local_app << i << " REALLY failed!";
347 19 : throw MultiAppSolveFailure(oss.str());
348 19 : }
349 : }
350 :
351 6238 : at_steady = ex->convergedToSteadyState();
352 :
353 6238 : if (converged && _detect_steady_state && at_steady)
354 : {
355 25 : if (_fe_problem.verboseMultiApps())
356 0 : _console << "Detected Steady State! Fast-forwarding to " << target_time << std::endl;
357 :
358 : // Indicate that the next output call (occurs in ex->endStep()) should output,
359 : // regardless of intervals etc...
360 25 : problem.forceOutput();
361 :
362 : // Clean up the end
363 25 : ex->endStep(target_time - app_time_offset);
364 25 : ex->postStep();
365 : }
366 : else
367 : {
368 6213 : ex->endStep();
369 6213 : ex->postStep();
370 : }
371 : }
372 :
373 : // If we were looking for a steady state, but didn't reach one, we still need to output one
374 : // more time, regardless of interval
375 : // Note: if we turn off the output for all time steps for sub-cycling, we still need to
376 : // have one output at the end.
377 1715 : if ((!at_steady && _detect_steady_state) || !_output_sub_cycles)
378 1653 : problem.outputStep(EXEC_FORCED);
379 :
380 : } // sub_cycling
381 69481 : else if (_tolerate_failure)
382 : {
383 0 : ex->takeStep(dt);
384 0 : ex->endStep(target_time - app_time_offset);
385 0 : ex->postStep();
386 : }
387 : else
388 : {
389 : // ADL: During restart, there is already an FEProblemBase::advanceState that occurs at the
390 : // end of TransientMultiApp::setupApp. advanceState, along with copying the solutions
391 : // backwards in time/state, also *moves* (note it doesn't copy!) stateful material
392 : // properties backwards (through swapping). So if restarting from a full-solve steady
393 : // multi-app for example, then after one advance state, we will have good information in old
394 : // and no information in current. But then if we advance again we no longer have good data
395 : // in the old material properties, so don't advance here if we're restarting
396 69481 : if (_first && !_app.isRecovering() && !_app.isRestarting())
397 6765 : problem.advanceState();
398 :
399 69481 : if (auto_advance)
400 16370 : problem.allowOutput(true);
401 :
402 69481 : ex->takeStep(dt);
403 :
404 69481 : if (auto_advance)
405 : {
406 16370 : ex->endStep();
407 16370 : ex->postStep();
408 :
409 16370 : if (!ex->lastSolveConverged())
410 : {
411 8 : mooseWarning(name(), _first_local_app + i, " failed to converge!\n");
412 :
413 8 : if (_catch_up)
414 : {
415 8 : if (_fe_problem.verboseMultiApps())
416 0 : _console << "Starting time step catch up!" << std::endl;
417 :
418 8 : bool caught_up = false;
419 :
420 8 : unsigned int catch_up_step = 0;
421 :
422 : // Cut the timestep in half to first try two half-step solves
423 8 : Real catch_up_dt = dt / 2;
424 8 : Real catch_up_time = 0;
425 :
426 24 : while (!caught_up && catch_up_step < _max_catch_up_steps)
427 : {
428 16 : if (_fe_problem.verboseMultiApps())
429 0 : _console << "Solving " << name() << " catch up step " << catch_up_step
430 0 : << std::endl;
431 16 : ex->incrementStepOrReject();
432 :
433 : // Avoid numerical precision errors on target time
434 16 : if (catch_up_time + catch_up_dt > dt)
435 0 : catch_up_dt = dt - catch_up_time;
436 :
437 16 : ex->computeDT();
438 16 : ex->takeStep(catch_up_dt);
439 16 : ex->endStep();
440 :
441 16 : if (ex->lastSolveConverged())
442 : {
443 16 : catch_up_time += catch_up_dt;
444 16 : if (std::abs(catch_up_time - dt) <
445 16 : (1 + std::abs(ex->getTime())) * ex->timestepTol())
446 : {
447 8 : problem.outputStep(EXEC_FORCED);
448 8 : caught_up = true;
449 : }
450 : }
451 : else
452 : // Keep cutting time step in half until it converges
453 0 : catch_up_dt /= 2.0;
454 :
455 16 : ex->postStep();
456 :
457 16 : catch_up_step++;
458 : }
459 :
460 8 : if (!caught_up)
461 0 : throw MultiAppSolveFailure(name() + " Failed to catch up!\n");
462 : }
463 : }
464 : }
465 : else // auto_advance == false
466 : {
467 53111 : if (!ex->lastSolveConverged())
468 : {
469 : // Even if we don't allow auto_advance - we can still catch up to the current time if
470 : // possible
471 97 : if (_catch_up)
472 : {
473 19 : if (_fe_problem.verboseMultiApps())
474 0 : _console << "Starting Catch Up!" << std::endl;
475 :
476 19 : bool caught_up = false;
477 :
478 19 : unsigned int catch_up_step = 0;
479 :
480 19 : Real catch_up_dt = dt / 2;
481 :
482 : // Note: this loop will _break_ if target_time is satisfied
483 38 : while (catch_up_step < _max_catch_up_steps)
484 : {
485 38 : if (_fe_problem.verboseMultiApps())
486 0 : _console << "Solving " << name() << " catch up step " << catch_up_step
487 0 : << std::endl;
488 38 : ex->incrementStepOrReject();
489 :
490 38 : ex->computeDT();
491 38 : ex->takeStep(catch_up_dt); // Cut the timestep in half to try two half-step solves
492 :
493 : // This is required because we can't call endStep() yet
494 : // (which normally increments time)
495 38 : Real current_time = ex->getTime() + ex->getDT();
496 :
497 38 : if (ex->lastSolveConverged())
498 : {
499 76 : if (current_time + app_time_offset +
500 38 : (ex->timestepTol() * std::abs(current_time)) >=
501 : target_time)
502 : {
503 19 : caught_up = true;
504 19 : break; // break here so that we don't run endStep() or postStep() since this
505 : // MultiApp should NOT be auto_advanced
506 : }
507 : }
508 : else
509 0 : catch_up_dt /= 2.0;
510 :
511 19 : ex->endStep();
512 19 : ex->postStep();
513 :
514 19 : catch_up_step++;
515 : }
516 :
517 19 : if (!caught_up)
518 0 : throw MultiAppSolveFailure(name() + " Failed to catch up!\n");
519 : }
520 : else
521 78 : throw MultiAppSolveFailure(name() + " failed to converge");
522 : }
523 : }
524 : }
525 :
526 : // Re-enable all output (it may of been disabled by sub-cycling)
527 71118 : problem.allowOutput(true);
528 : }
529 :
530 64219 : _first = false;
531 :
532 64219 : if (_fe_problem.verboseMultiApps())
533 1912 : _console << "Successfully Solved MultiApp " << name() << "." << std::endl;
534 : }
535 97 : catch (MultiAppSolveFailure & e)
536 : {
537 97 : mooseWarning(e.what());
538 97 : _console << "Failed to Solve MultiApp " << name() << ", attempting to recover." << std::endl;
539 97 : return_value = false;
540 97 : }
541 :
542 64316 : _transferred_vars.clear();
543 :
544 64316 : return return_value;
545 64316 : }
546 :
547 : void
548 14228 : TransientMultiApp::incrementTStep(Real target_time)
549 : {
550 14228 : if (!_sub_cycling)
551 : {
552 31840 : for (unsigned int i = 0; i < _my_num_apps; i++)
553 : {
554 18234 : TransientBase * ex = _transient_executioners[i];
555 :
556 : // The App might have a different local time from the rest of the problem
557 18234 : Real app_time_offset = _apps[i]->getGlobalTimeOffset();
558 :
559 : // Only increment the step if we are after (target_time) the
560 : // start_time (added to app_time_offset) of this sub_app.
561 18234 : if (_apps[i]->getStartTime() + app_time_offset < target_time)
562 18170 : ex->incrementStepOrReject();
563 : }
564 : }
565 14228 : }
566 :
567 : void
568 9421 : TransientMultiApp::finishStep(bool recurse_through_multiapp_levels)
569 : {
570 9421 : if (!_sub_cycling)
571 : {
572 18319 : for (unsigned int i = 0; i < _my_num_apps; i++)
573 : {
574 9167 : TransientBase * ex = _transient_executioners[i];
575 9167 : ex->endStep();
576 9167 : ex->postStep();
577 9167 : if (recurse_through_multiapp_levels)
578 : {
579 1140 : ex->feProblem().finishMultiAppStep(EXEC_TIMESTEP_BEGIN,
580 : /*recurse_through_multiapp_levels=*/true);
581 1140 : ex->feProblem().finishMultiAppStep(EXEC_TIMESTEP_END,
582 : /*recurse_through_multiapp_levels=*/true);
583 : }
584 : }
585 : }
586 9421 : }
587 :
588 : Real
589 18442 : TransientMultiApp::computeDT()
590 : {
591 18442 : if (_sub_cycling) // Bow out of the timestep selection dance
592 721 : return std::numeric_limits<Real>::max();
593 :
594 17721 : Real smallest_dt = std::numeric_limits<Real>::max();
595 :
596 17721 : if (_has_an_app)
597 : {
598 17678 : Moose::ScopedCommSwapper swapper(_my_comm);
599 :
600 42124 : for (unsigned int i = 0; i < _my_num_apps; i++)
601 : {
602 24446 : TransientBase * ex = _transient_executioners[i];
603 24446 : ex->computeDT();
604 24446 : Real dt = ex->getDT();
605 :
606 24446 : smallest_dt = std::min(dt, smallest_dt);
607 : }
608 17678 : }
609 :
610 17721 : if (_tolerate_failure) // Bow out of the timestep selection dance, we do this down here because we
611 : // need to call computeConstrainedDT at least once for these
612 : // executioners...
613 0 : return std::numeric_limits<Real>::max();
614 :
615 17721 : _communicator.min(smallest_dt);
616 17721 : return smallest_dt;
617 : }
618 :
619 : void
620 76 : TransientMultiApp::resetApp(
621 : unsigned int global_app,
622 : Real /*time*/) // FIXME: Note that we are passing in time but also grabbing it below
623 : {
624 76 : if (hasLocalApp(global_app))
625 : {
626 76 : unsigned int local_app = globalAppToLocal(global_app);
627 :
628 : // Grab the current time the App is at so we can start the new one at the same place
629 : Real time =
630 76 : _transient_executioners[local_app]->getTime() + _apps[local_app]->getGlobalTimeOffset();
631 :
632 : // Reset the Multiapp
633 76 : MultiApp::resetApp(global_app, time);
634 :
635 76 : Moose::ScopedCommSwapper swapper(_my_comm);
636 :
637 : // Setup the app, disable the output so that the initial condition does not output
638 : // When an app is reset the initial condition was effectively already output before reset
639 76 : FEProblemBase & problem = appProblemBase(local_app);
640 76 : problem.allowOutput(false);
641 76 : setupApp(local_app, time);
642 76 : problem.allowOutput(true);
643 76 : }
644 76 : }
645 :
646 : void
647 8446 : TransientMultiApp::setupApp(unsigned int i, Real /*time*/) // FIXME: Should we be passing time?
648 : {
649 8446 : auto & app = _apps[i];
650 8446 : TransientBase * ex = dynamic_cast<TransientBase *>(app->getExecutioner());
651 8446 : if (!ex)
652 0 : mooseError("MultiApp ", name(), " is not using a Transient Executioner!");
653 :
654 : // Get the FEProblemBase for the current MultiApp
655 8446 : FEProblemBase & problem = appProblemBase(_first_local_app + i);
656 :
657 : // Update the file numbers for the outputs from the parent application
658 8446 : app->getOutputWarehouse().setFileNumbers(_app.getOutputFileNumbers());
659 :
660 : // Add these vectors before we call init on the executioner because that will try to restore these
661 : // vectors in a restart context
662 8446 : if (_interpolate_transfers)
663 : {
664 26 : AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
665 26 : System & libmesh_aux_system = aux_system.system();
666 :
667 : // We'll store a copy of the auxiliary system's solution at the old time in here
668 26 : libmesh_aux_system.add_vector("transfer_old", false);
669 :
670 : // This will be where we'll transfer the value to for the "target" time
671 26 : libmesh_aux_system.add_vector("transfer", false);
672 : }
673 :
674 : // Call initialization method of Executioner (Note, this performs the output of the initial time
675 : // step, if desired)
676 8446 : ex->init();
677 :
678 8442 : ex->preExecute();
679 8442 : if (!_app.isRecovering())
680 : {
681 7793 : problem.timeStep()++;
682 7793 : problem.advanceState();
683 : }
684 8442 : _transient_executioners[i] = ex;
685 8442 : }
|