LCOV - code coverage report
Current view: top level - src/multiapps - TransientMultiApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 286 312 91.7 %
Date: 2025-08-08 20:01:16 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : // 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 : }

Generated by: LCOV version 1.14