LCOV - code coverage report
Current view: top level - src/multiapps - TransientMultiApp.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 287 313 91.7 %
Date: 2026-05-29 20:35:17 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       19982 : TransientMultiApp::validParams()
      30             : {
      31       19982 :   InputParameters params = MultiApp::validParams();
      32       19982 :   params += TransientInterface::validParams();
      33       39964 :   params.addClassDescription("MultiApp for performing coupled simulations with the parent and "
      34             :                              "sub-application both progressing in time.");
      35             : 
      36       59946 :   params.addParam<bool>("sub_cycling",
      37       39964 :                         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       59946 :   params.addParam<bool>("interpolate_transfers",
      44       39964 :                         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       59946 :   params.addParam<bool>("detect_steady_state",
      51       39964 :                         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       79928 :   params.addParam<bool>("output_sub_cycles", false, "If true then every sub-cycle will be output.");
      57       59946 :   params.addParam<bool>(
      58       39964 :       "print_sub_cycles", true, "Toggle the display of sub-cycles on the screen.");
      59             : 
      60       59946 :   params.addParam<unsigned int>(
      61       39964 :       "max_failures", 0, "Maximum number of solve failures tolerated while sub_cycling.");
      62             : 
      63       79928 :   params.addParamNamesToGroup("sub_cycling interpolate_transfers detect_steady_state "
      64             :                               "output_sub_cycles print_sub_cycles max_failures",
      65             :                               "Sub cycling");
      66             : 
      67       59946 :   params.addParam<bool>("tolerate_failure",
      68       39964 :                         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       59946 :   params.addParam<bool>(
      74             :       "catch_up",
      75       39964 :       false,
      76             :       "If true this will allow failed solves to attempt to 'catch up' using smaller timesteps.");
      77             : 
      78       59946 :   params.addParam<Real>("max_catch_up_steps",
      79       39964 :                         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       79928 :   params.addParamNamesToGroup("catch_up max_catch_up_steps", "Recovering failed solutions");
      85       59946 :   params.addParamNamesToGroup("tolerate_failure", "Accepting failed solutions");
      86             : 
      87       19982 :   return params;
      88           0 : }
      89             : 
      90        5398 : TransientMultiApp::TransientMultiApp(const InputParameters & parameters)
      91             :   : MultiApp(parameters),
      92       10784 :     _sub_cycling(getParam<bool>("sub_cycling")),
      93       10784 :     _interpolate_transfers(getParam<bool>("interpolate_transfers")),
      94       10784 :     _detect_steady_state(getParam<bool>("detect_steady_state")),
      95       10784 :     _output_sub_cycles(getParam<bool>("output_sub_cycles")),
      96       10784 :     _max_failures(getParam<unsigned int>("max_failures")),
      97       10784 :     _tolerate_failure(getParam<bool>("tolerate_failure")),
      98        5392 :     _failures(0),
      99       10784 :     _catch_up(getParam<bool>("catch_up")),
     100       10784 :     _max_catch_up_steps(getParam<Real>("max_catch_up_steps")),
     101       10784 :     _first(declareRecoverableData<bool>("first", true)),
     102        5392 :     _auto_advance(false),
     103       16182 :     _print_sub_cycles(getParam<bool>("print_sub_cycles"))
     104             : {
     105             :   // Transfer interpolation only makes sense for sub-cycling solves
     106        5392 :   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        5392 :   if (_sub_cycling && _catch_up)
     114           6 :     paramError("catch_up",
     115             :                "MultiApp ",
     116           3 :                name(),
     117             :                " \"sub_cycling\" and \"catch_up\" cannot both be set to true simultaneously.");
     118             : 
     119        5389 :   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        5389 :   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        5389 :   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        5389 : }
     140             : 
     141             : NumericVector<Number> &
     142        1021 : TransientMultiApp::appTransferVector(unsigned int app, std::string var_name)
     143             : {
     144        1021 :   if (std::find(_transferred_vars.begin(), _transferred_vars.end(), var_name) ==
     145        2042 :       _transferred_vars.end())
     146         872 :     _transferred_vars.push_back(var_name);
     147             : 
     148        1021 :   if (_interpolate_transfers)
     149         197 :     return appProblemBase(app).getAuxiliarySystem().system().get_vector("transfer");
     150             : 
     151         824 :   return appProblemBase(app).getAuxiliarySystem().solution();
     152             : }
     153             : 
     154             : void
     155        5314 : TransientMultiApp::initialSetup()
     156             : {
     157        5314 :   MultiApp::initialSetup();
     158             : 
     159        5314 :   if (!_has_an_app)
     160          52 :     return;
     161             : 
     162        5262 :   Moose::ScopedCommSwapper swapper(_my_comm);
     163             : 
     164        5262 :   if (_has_an_app)
     165             :   {
     166        5262 :     _transient_executioners.resize(_my_num_apps);
     167             :     // Grab Transient Executioners from each app
     168       13041 :     for (unsigned int i = 0; i < _my_num_apps; i++)
     169        7782 :       setupApp(i);
     170             :   }
     171        5259 : }
     172             : 
     173             : bool
     174       60513 : TransientMultiApp::solveStep(Real dt, Real target_time, bool auto_advance)
     175             : {
     176       60513 :   if (!_has_an_app)
     177          79 :     return true;
     178             : 
     179       60434 :   TIME_SECTION(_solve_step_timer);
     180             : 
     181       60434 :   _auto_advance = auto_advance;
     182             : 
     183       60434 :   if (_fe_problem.verboseMultiApps())
     184        1886 :     _console << COLOR_CYAN << "Solving MultiApp '" << name() << "' with target time " << target_time
     185        1886 :              << " and dt " << dt << " with auto-advance " << (auto_advance ? "on" : "off")
     186        1886 :              << COLOR_DEFAULT << std::endl;
     187             : 
     188             :   // "target_time" must always be in global time
     189       60434 :   target_time += _app.getGlobalTimeOffset();
     190             : 
     191       60434 :   Moose::ScopedCommSwapper swapper(_my_comm);
     192       60434 :   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       60434 :     ierr = MPI_Comm_rank(_communicator.get(), &rank);
     200       60434 :     mooseCheckMPIErr(ierr);
     201             : 
     202      127209 :     for (unsigned int i = 0; i < _my_num_apps; i++)
     203             :     {
     204       66849 :       FEProblemBase & problem = appProblemBase(_first_local_app + i);
     205             : 
     206       66849 :       TransientBase * ex = _transient_executioners[i];
     207             : 
     208             :       // The App might have a different local time from the rest of the problem
     209       66849 :       Real app_time_offset = _apps[i]->getGlobalTimeOffset();
     210             : 
     211             :       // Maybe this MultiApp was already solved
     212      133389 :       if ((ex->getTime() + app_time_offset + ex->timestepTol() >= target_time) ||
     213       66540 :           (ex->getTime() >= ex->endTime()))
     214         329 :         continue;
     215             : 
     216             :       // Examine global time synchronization
     217       66520 :       if (!_sub_cycling && !_reset_happened.size())
     218             :       {
     219             :         // The multi-app general offset is substracted to go into local time.
     220       64325 :         if (std::abs(target_time - _app.getGlobalTimeOffset() - ex->getTime() - dt) >
     221       64325 :             ex->timestepTol())
     222          70 :           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       66517 :       if (_sub_cycling)
     236             :       {
     237        1600 :         Real time_old = ex->getTime() + app_time_offset;
     238             : 
     239        1600 :         if (_interpolate_transfers)
     240             :         {
     241         161 :           AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
     242         161 :           System & libmesh_aux_system = aux_system.system();
     243             : 
     244         161 :           NumericVector<Number> & solution = *libmesh_aux_system.solution;
     245         161 :           NumericVector<Number> & transfer_old = libmesh_aux_system.get_vector("transfer_old");
     246             : 
     247         161 :           solution.close();
     248             : 
     249             :           // Save off the current auxiliary solution
     250         161 :           transfer_old = solution;
     251             : 
     252         161 :           transfer_old.close();
     253             : 
     254             :           // Snag all of the local dof indices for all of these variables
     255         161 :           AllLocalDofIndicesThread aldit(problem, _transferred_vars);
     256         161 :           ConstElemRange & elem_range = *problem.mesh().getActiveLocalElementRange();
     257         161 :           Threads::parallel_reduce(elem_range, aldit);
     258             : 
     259         161 :           _transferred_dofs = aldit.getDofIndices();
     260         161 :         }
     261             : 
     262             :         // Disable/enable output for sub cycling
     263        1600 :         problem.allowOutput(_output_sub_cycles);         // disables all outputs, including console
     264        1600 :         problem.allowOutput<Console>(_print_sub_cycles); // re-enables Console to print, if desired
     265             : 
     266        1600 :         ex->setTargetTime(target_time - app_time_offset);
     267             : 
     268             :         //      unsigned int failures = 0;
     269             : 
     270        1600 :         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        1600 :         if (_first && !_app.isRecovering() && !_app.isRestarting())
     280         178 :           problem.advanceState();
     281             : 
     282        1600 :         bool local_first = _first;
     283             : 
     284             :         // Now do all of the solves we need
     285        9053 :         while ((!at_steady && ex->getTime() + app_time_offset + ex->timestepTol() < target_time) ||
     286        1583 :                !ex->lastSolveConverged())
     287             :         {
     288        5887 :           if (local_first != true)
     289        5708 :             ex->incrementStepOrReject();
     290             : 
     291        5887 :           local_first = false;
     292             : 
     293        5887 :           ex->preStep();
     294        5887 :           ex->computeDT();
     295             : 
     296        5887 :           if (_interpolate_transfers)
     297             :           {
     298             :             // See what time this executioner is going to go to.
     299        1498 :             Real future_time = ex->getTime() + app_time_offset + ex->getDT();
     300             : 
     301             :             // How far along we are towards the target time:
     302        1498 :             Real step_percent = (future_time - time_old) / (target_time - time_old);
     303             : 
     304        1498 :             Real one_minus_step_percent = 1.0 - step_percent;
     305             : 
     306             :             // Do the interpolation for each variable that was transferred to
     307        1498 :             FEProblemBase & problem = appProblemBase(_first_local_app + i);
     308        1498 :             AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
     309        1498 :             System & libmesh_aux_system = aux_system.system();
     310             : 
     311        1498 :             NumericVector<Number> & solution = *libmesh_aux_system.solution;
     312        1498 :             NumericVector<Number> & transfer = libmesh_aux_system.get_vector("transfer");
     313        1498 :             NumericVector<Number> & transfer_old = libmesh_aux_system.get_vector("transfer_old");
     314             : 
     315        1498 :             solution.close(); // Just to be sure
     316        1498 :             transfer.close();
     317        1498 :             transfer_old.close();
     318             : 
     319      444818 :             for (const auto & dof : _transferred_dofs)
     320             :             {
     321      886640 :               solution.set(dof,
     322      443320 :                            (transfer_old(dof) * one_minus_step_percent) +
     323      443320 :                                (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        1498 :             solution.close();
     330             :           }
     331             : 
     332        5887 :           ex->takeStep();
     333             : 
     334        5887 :           bool converged = ex->lastSolveConverged();
     335             : 
     336        5887 :           if (!converged)
     337             :           {
     338          17 :             mooseWarning(
     339          17 :                 "While sub_cycling ", name(), _first_local_app + i, " failed to converge!\n");
     340             : 
     341          17 :             _failures++;
     342             : 
     343          17 :             if (_failures > _max_failures)
     344             :             {
     345          17 :               std::stringstream oss;
     346          17 :               oss << "While sub_cycling " << name() << _first_local_app << i << " REALLY failed!";
     347          17 :               throw MultiAppSolveFailure(oss.str());
     348          17 :             }
     349             :           }
     350        5870 :           if (_detect_steady_state)
     351         241 :             at_steady = ex->convergedToSteadyState();
     352             : 
     353        5870 :           if (converged && _detect_steady_state && at_steady)
     354             :           {
     355          23 :             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          23 :             problem.forceOutput();
     361             : 
     362             :             // Clean up the end
     363          23 :             ex->endStep(target_time - app_time_offset);
     364          23 :             ex->postStep();
     365             :           }
     366             :           else
     367             :           {
     368        5847 :             ex->endStep();
     369        5847 :             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        1583 :         if ((!at_steady && _detect_steady_state) || !_output_sub_cycles)
     378        1526 :           problem.outputStep(EXEC_FORCED);
     379             : 
     380             :       } // end of sub_cycling
     381       64917 :       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             :       // matched time steps (no subcycling)
     388             :       else
     389             :       {
     390             :         // ADL: During restart, there is already an FEProblemBase::advanceState that occurs at the
     391             :         // end of TransientMultiApp::setupApp. advanceState, along with copying the solutions
     392             :         // backwards in time/state, also *moves* (note it doesn't copy!) stateful material
     393             :         // properties backwards (through swapping). So if restarting from a full-solve steady
     394             :         // multi-app for example, then after one advance state, we will have good information in old
     395             :         // and no information in current. But then if we advance again we no longer have good data
     396             :         // in the old material properties, so don't advance here if we're restarting
     397       64917 :         if (_first && !_app.isRecovering() && !_app.isRestarting())
     398        6542 :           problem.advanceState();
     399             : 
     400       64917 :         if (auto_advance)
     401       15329 :           problem.allowOutput(true);
     402             : 
     403       64917 :         ex->takeStep(dt);
     404             : 
     405       64917 :         if (auto_advance)
     406             :         {
     407       15329 :           ex->endStep();
     408       15329 :           ex->postStep();
     409             : 
     410       15329 :           if (!ex->lastSolveConverged())
     411             :           {
     412           7 :             mooseWarning(name(), _first_local_app + i, " failed to converge!\n");
     413             : 
     414           7 :             if (_catch_up)
     415             :             {
     416           7 :               if (_fe_problem.verboseMultiApps())
     417           0 :                 _console << "Starting time step catch up!" << std::endl;
     418             : 
     419           7 :               bool caught_up = false;
     420             : 
     421           7 :               unsigned int catch_up_step = 0;
     422             : 
     423             :               // Cut the timestep in half to first try two half-step solves
     424           7 :               Real catch_up_dt = dt / 2;
     425           7 :               Real catch_up_time = 0;
     426             : 
     427          21 :               while (!caught_up && catch_up_step < _max_catch_up_steps)
     428             :               {
     429          14 :                 if (_fe_problem.verboseMultiApps())
     430           0 :                   _console << "Solving " << name() << " catch up step " << catch_up_step
     431           0 :                            << std::endl;
     432          14 :                 ex->incrementStepOrReject();
     433             : 
     434             :                 // Avoid numerical precision errors on target time
     435          14 :                 if (catch_up_time + catch_up_dt > dt)
     436           0 :                   catch_up_dt = dt - catch_up_time;
     437             : 
     438          14 :                 ex->computeDT();
     439          14 :                 ex->takeStep(catch_up_dt);
     440          14 :                 ex->endStep();
     441             : 
     442          14 :                 if (ex->lastSolveConverged())
     443             :                 {
     444          14 :                   catch_up_time += catch_up_dt;
     445          14 :                   if (std::abs(catch_up_time - dt) <
     446          14 :                       (1 + std::abs(ex->getTime())) * ex->timestepTol())
     447             :                   {
     448           7 :                     problem.outputStep(EXEC_FORCED);
     449           7 :                     caught_up = true;
     450             :                   }
     451             :                 }
     452             :                 else
     453             :                   // Keep cutting time step in half until it converges
     454           0 :                   catch_up_dt /= 2.0;
     455             : 
     456          14 :                 ex->postStep();
     457             : 
     458          14 :                 catch_up_step++;
     459             :               }
     460             : 
     461           7 :               if (!caught_up)
     462           0 :                 throw MultiAppSolveFailure(name() + " Failed to catch up!\n");
     463             :             }
     464             :           }
     465             :         }
     466             :         else // auto_advance == false
     467             :         {
     468       49588 :           if (!ex->lastSolveConverged())
     469             :           {
     470             :             // Even if we don't allow auto_advance - we can still catch up to the current time if
     471             :             // possible
     472          68 :             if (_catch_up)
     473             :             {
     474          14 :               if (_fe_problem.verboseMultiApps())
     475           0 :                 _console << "Starting Catch Up!" << std::endl;
     476             : 
     477          14 :               bool caught_up = false;
     478             : 
     479          14 :               unsigned int catch_up_step = 0;
     480             : 
     481          14 :               Real catch_up_dt = dt / 2;
     482             : 
     483             :               // Note: this loop will _break_ if target_time is satisfied
     484          28 :               while (catch_up_step < _max_catch_up_steps)
     485             :               {
     486          28 :                 if (_fe_problem.verboseMultiApps())
     487           0 :                   _console << "Solving " << name() << " catch up step " << catch_up_step
     488           0 :                            << std::endl;
     489          28 :                 ex->incrementStepOrReject();
     490             : 
     491          28 :                 ex->computeDT();
     492          28 :                 ex->takeStep(catch_up_dt); // Cut the timestep in half to try two half-step solves
     493             : 
     494             :                 // This is required because we can't call endStep() yet
     495             :                 // (which normally increments time)
     496          28 :                 Real current_time = ex->getTime() + ex->getDT();
     497             : 
     498          28 :                 if (ex->lastSolveConverged())
     499             :                 {
     500          56 :                   if (current_time + app_time_offset +
     501          28 :                           (ex->timestepTol() * std::abs(current_time)) >=
     502             :                       target_time)
     503             :                   {
     504          14 :                     caught_up = true;
     505          14 :                     break; // break here so that we don't run endStep() or postStep() since this
     506             :                            // MultiApp should NOT be auto_advanced
     507             :                   }
     508             :                 }
     509             :                 else
     510           0 :                   catch_up_dt /= 2.0;
     511             : 
     512          14 :                 ex->endStep();
     513          14 :                 ex->postStep();
     514             : 
     515          14 :                 catch_up_step++;
     516             :               }
     517             : 
     518          14 :               if (!caught_up)
     519           0 :                 throw MultiAppSolveFailure(name() + " Failed to catch up!\n");
     520             :             }
     521             :             else
     522          54 :               throw MultiAppSolveFailure(name() + " failed to converge");
     523             :           }
     524             :         }
     525             :       }
     526             : 
     527             :       // Re-enable all output (it may of been disabled by sub-cycling)
     528       66446 :       problem.allowOutput(true);
     529             :     }
     530             : 
     531       60360 :     _first = false;
     532             : 
     533       60360 :     if (_fe_problem.verboseMultiApps())
     534        1886 :       _console << "Successfully Solved MultiApp " << name() << "." << std::endl;
     535             :   }
     536          71 :   catch (MultiAppSolveFailure & e)
     537             :   {
     538          71 :     mooseWarning(e.what());
     539          71 :     _console << "Failed to Solve MultiApp " << name() << ", attempting to recover." << std::endl;
     540          71 :     return_value = false;
     541          71 :   }
     542             : 
     543       60431 :   _transferred_vars.clear();
     544             : 
     545       60431 :   return return_value;
     546       60431 : }
     547             : 
     548             : void
     549       13157 : TransientMultiApp::incrementTStep(Real target_time)
     550             : {
     551       13157 :   if (!_sub_cycling)
     552             :   {
     553       29207 :     for (unsigned int i = 0; i < _my_num_apps; i++)
     554             :     {
     555       16623 :       TransientBase * ex = _transient_executioners[i];
     556             : 
     557             :       // The App might have a different local time from the rest of the problem
     558       16623 :       Real app_time_offset = _apps[i]->getGlobalTimeOffset();
     559             : 
     560             :       // Only increment the step if we are after (target_time) the
     561             :       // start_time (added to app_time_offset) of this sub_app.
     562       16623 :       if (_apps[i]->getStartTime() + app_time_offset < target_time)
     563       16567 :         ex->incrementStepOrReject();
     564             :     }
     565             :   }
     566       13157 : }
     567             : 
     568             : void
     569        8590 : TransientMultiApp::finishStep(bool recurse_through_multiapp_levels)
     570             : {
     571        8590 :   if (!_sub_cycling)
     572             :   {
     573       16698 :     for (unsigned int i = 0; i < _my_num_apps; i++)
     574             :     {
     575        8355 :       TransientBase * ex = _transient_executioners[i];
     576        8355 :       ex->endStep();
     577        8355 :       ex->postStep();
     578        8355 :       if (recurse_through_multiapp_levels)
     579             :       {
     580        1031 :         ex->feProblem().finishMultiAppStep(EXEC_TIMESTEP_BEGIN,
     581             :                                            /*recurse_through_multiapp_levels=*/true);
     582        1031 :         ex->feProblem().finishMultiAppStep(EXEC_TIMESTEP_END,
     583             :                                            /*recurse_through_multiapp_levels=*/true);
     584             :       }
     585             :     }
     586             :   }
     587        8590 : }
     588             : 
     589             : Real
     590       17385 : TransientMultiApp::computeDT()
     591             : {
     592       17385 :   if (_sub_cycling) // Bow out of the timestep selection dance
     593         668 :     return std::numeric_limits<Real>::max();
     594             : 
     595       16717 :   Real smallest_dt = std::numeric_limits<Real>::max();
     596             : 
     597       16717 :   if (_has_an_app)
     598             :   {
     599       16675 :     Moose::ScopedCommSwapper swapper(_my_comm);
     600             : 
     601       39368 :     for (unsigned int i = 0; i < _my_num_apps; i++)
     602             :     {
     603       22693 :       TransientBase * ex = _transient_executioners[i];
     604       22693 :       ex->computeDT();
     605       22693 :       Real dt = ex->getDT();
     606             : 
     607       22693 :       smallest_dt = std::min(dt, smallest_dt);
     608             :     }
     609       16675 :   }
     610             : 
     611       16717 :   if (_tolerate_failure) // Bow out of the timestep selection dance, we do this down here because we
     612             :                          // need to call computeConstrainedDT at least once for these
     613             :                          // executioners...
     614           0 :     return std::numeric_limits<Real>::max();
     615             : 
     616       16717 :   _communicator.min(smallest_dt);
     617       16717 :   return smallest_dt;
     618             : }
     619             : 
     620             : void
     621          69 : TransientMultiApp::resetApp(
     622             :     unsigned int global_app,
     623             :     Real /*time*/) // FIXME: Note that we are passing in time but also grabbing it below
     624             : {
     625          69 :   if (hasLocalApp(global_app))
     626             :   {
     627          69 :     unsigned int local_app = globalAppToLocal(global_app);
     628             : 
     629             :     // Grab the current time the App is at so we can start the new one at the same place
     630             :     Real time =
     631          69 :         _transient_executioners[local_app]->getTime() + _apps[local_app]->getGlobalTimeOffset();
     632             : 
     633             :     // Reset the Multiapp
     634          69 :     MultiApp::resetApp(global_app, time);
     635             : 
     636          69 :     Moose::ScopedCommSwapper swapper(_my_comm);
     637             : 
     638             :     // Setup the app, disable the output so that the initial condition does not output
     639             :     // When an app is reset the initial condition was effectively already output before reset
     640          69 :     FEProblemBase & problem = appProblemBase(local_app);
     641          69 :     problem.allowOutput(false);
     642          69 :     setupApp(local_app, time);
     643          69 :     problem.allowOutput(true);
     644          69 :   }
     645          69 : }
     646             : 
     647             : void
     648        7851 : TransientMultiApp::setupApp(unsigned int i, Real /*time*/) // FIXME: Should we be passing time?
     649             : {
     650        7851 :   auto & app = _apps[i];
     651        7851 :   TransientBase * ex = dynamic_cast<TransientBase *>(app->getExecutioner());
     652        7851 :   if (!ex)
     653           0 :     mooseError("MultiApp ", name(), " is not using a Transient Executioner!");
     654             : 
     655             :   // Get the FEProblemBase for the current MultiApp
     656        7851 :   FEProblemBase & problem = appProblemBase(_first_local_app + i);
     657             : 
     658             :   // Update the file numbers for the outputs from the parent application
     659        7851 :   app->getOutputWarehouse().setFileNumbers(_app.getOutputFileNumbers());
     660             : 
     661             :   // Add these vectors before we call init on the executioner because that will try to restore these
     662             :   // vectors in a restart context
     663        7851 :   if (_interpolate_transfers)
     664             :   {
     665          24 :     AuxiliarySystem & aux_system = problem.getAuxiliarySystem();
     666          24 :     System & libmesh_aux_system = aux_system.system();
     667             : 
     668             :     // We'll store a copy of the auxiliary system's solution at the old time in here
     669          24 :     libmesh_aux_system.add_vector("transfer_old", false);
     670             : 
     671             :     // This will be where we'll transfer the value to for the "target" time
     672          24 :     libmesh_aux_system.add_vector("transfer", false);
     673             :   }
     674             : 
     675             :   // Call initialization method of Executioner (Note, this performs the output of the initial time
     676             :   // step, if desired)
     677        7851 :   ex->init();
     678             : 
     679        7848 :   ex->preExecute();
     680        7848 :   if (!_app.isRecovering())
     681             :   {
     682        7154 :     problem.timeStep()++;
     683        7154 :     problem.advanceState();
     684             :   }
     685        7848 :   _transient_executioners[i] = ex;
     686        7848 : }

Generated by: LCOV version 1.14