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 : #include "TransientBase.h"
11 :
12 : // MOOSE includes
13 : #include "Factory.h"
14 : #include "SubProblem.h"
15 : #include "TimeStepper.h"
16 : #include "MooseApp.h"
17 : #include "Conversion.h"
18 : #include "FEProblem.h"
19 : #include "NonlinearSystem.h"
20 : #include "Control.h"
21 : #include "TimePeriod.h"
22 : #include "MooseMesh.h"
23 : #include "TimeIntegrator.h"
24 : #include "Console.h"
25 : #include "AuxiliarySystem.h"
26 : #include "Convergence.h"
27 : #include "ConvergenceIterationTypes.h"
28 :
29 : #include "libmesh/implicit_system.h"
30 : #include "libmesh/nonlinear_implicit_system.h"
31 : #include "libmesh/transient_system.h"
32 : #include "libmesh/numeric_vector.h"
33 :
34 : // C++ Includes
35 : #include <iomanip>
36 : #include <iostream>
37 : #include <fstream>
38 : #include <sstream>
39 : #include <iomanip>
40 :
41 : InputParameters
42 179263 : TransientBase::defaultSteadyStateConvergenceParams()
43 : {
44 179263 : InputParameters params = emptyInputParameters();
45 :
46 537789 : params.addParam<Real>("steady_state_tolerance",
47 358526 : 1.0e-08,
48 : "Whenever the relative residual changes by less "
49 : "than this the solution will be considered to be "
50 : "at steady state.");
51 537789 : params.addParam<bool>("check_aux",
52 358526 : false,
53 : "Whether to check the auxiliary system for convergence to steady-state. If "
54 : "false, then the solution vector from the solver system is used.");
55 537789 : params.addParam<bool>(
56 : "normalize_solution_diff_norm_by_dt",
57 358526 : true,
58 : "Whether to divide the solution difference norm by dt. If taking 'small' "
59 : "time steps you probably want this to be true. If taking very 'large' timesteps in an "
60 : "attempt to *reach* a steady-state, you probably want this parameter to be false.");
61 :
62 537789 : params.addParamNamesToGroup("steady_state_tolerance check_aux normalize_solution_diff_norm_by_dt",
63 : "Steady State Detection");
64 :
65 179263 : return params;
66 0 : }
67 :
68 : InputParameters
69 99668 : TransientBase::validParams()
70 : {
71 99668 : InputParameters params = Executioner::validParams();
72 99668 : params += TransientBase::defaultSteadyStateConvergenceParams();
73 :
74 199336 : params.addClassDescription("Executioner for time varying simulations.");
75 :
76 99668 : std::vector<Real> sync_times(1);
77 99668 : sync_times[0] = -std::numeric_limits<Real>::max();
78 :
79 : /**
80 : * For backwards compatibility we'll allow users to set the TimeIntegration scheme inside of the
81 : * executioner block
82 : * as long as the TimeIntegrator does not have any additional parameters.
83 : */
84 : MooseEnum schemes("implicit-euler explicit-euler crank-nicolson bdf2 explicit-midpoint dirk "
85 : "explicit-tvd-rk-2 newmark-beta",
86 398672 : "implicit-euler");
87 :
88 498340 : params.addParam<Real>("start_time", 0.0, "The start time of the simulation");
89 398672 : params.addParam<Real>("end_time", 1.0e30, "The end time of the simulation");
90 398672 : params.addParam<Real>("dt", 1., "The timestep size between solves");
91 398672 : params.addParam<Real>("dtmin", 1.0e-12, "The minimum timestep size in an adaptive run");
92 398672 : params.addParam<Real>("dtmax", 1.0e30, "The maximum timestep size in an adaptive run");
93 299004 : params.addParam<bool>(
94 199336 : "reset_dt", false, "Use when restarting a calculation to force a change in dt.");
95 299004 : params.addParam<unsigned int>("num_steps",
96 199336 : std::numeric_limits<unsigned int>::max(),
97 : "The number of timesteps in a transient run");
98 398672 : params.addParam<int>("n_startup_steps", 0, "The number of timesteps during startup");
99 :
100 299004 : params.addParam<bool>(
101 199336 : "steady_state_detection", false, "Whether or not to check for steady state conditions");
102 398672 : params.addParam<ConvergenceName>(
103 : "steady_state_convergence",
104 : "Name of the Convergence object to use to assess whether the solution has reached a steady "
105 : "state. If not provided, a default Convergence will be constructed internally from the "
106 : "executioner parameters.");
107 299004 : params.addParam<Real>(
108 : "steady_state_start_time",
109 199336 : 0.0,
110 : "Minimum amount of time to run before checking for steady state conditions.");
111 :
112 398672 : params.addParam<std::vector<std::string>>("time_periods", "The names of periods");
113 398672 : params.addParam<std::vector<Real>>("time_period_starts", "The start times of time periods");
114 398672 : params.addParam<std::vector<Real>>("time_period_ends", "The end times of time periods");
115 299004 : params.addParam<bool>(
116 199336 : "abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
117 299004 : params.addParam<bool>(
118 : "error_on_dtmin",
119 199336 : true,
120 : "Throw error when timestep is less than dtmin instead of just aborting solve.");
121 398672 : params.addParam<MooseEnum>("scheme", schemes, "Time integration scheme used.");
122 299004 : params.addParam<Real>("timestep_tolerance",
123 199336 : 1.0e-12,
124 : "the tolerance setting for final timestep size and sync times");
125 :
126 299004 : params.addParam<bool>("use_multiapp_dt",
127 199336 : false,
128 : "If true then the dt for the simulation will be "
129 : "chosen by the MultiApps. If false (the "
130 : "default) then the minimum over the master dt "
131 : "and the MultiApps is used");
132 :
133 398672 : params.addParamNamesToGroup(
134 : "steady_state_detection steady_state_convergence steady_state_start_time",
135 : "Steady State Detection");
136 :
137 398672 : params.addParamNamesToGroup("start_time dtmin dtmax n_startup_steps "
138 : "abort_on_solve_fail timestep_tolerance use_multiapp_dt",
139 : "Advanced");
140 :
141 398672 : params.addParamNamesToGroup("time_periods time_period_starts time_period_ends", "Time Periods");
142 :
143 : // This Executioner supports --test-restep
144 99668 : params.set<bool>("_supports_test_restep") = true;
145 :
146 199336 : return params;
147 99668 : }
148 :
149 31191 : TransientBase::TransientBase(const InputParameters & parameters)
150 : : Executioner(parameters),
151 31191 : _problem(_fe_problem),
152 62382 : _aux(_fe_problem.getAuxiliarySystem()),
153 62382 : _time_scheme(getParam<MooseEnum>("scheme").getEnum<Moose::TimeIntegratorType>()),
154 31191 : _time_stepper(nullptr),
155 31191 : _t_step(_problem.timeStep()),
156 31191 : _time(_problem.time()),
157 31191 : _time_old(_problem.timeOld()),
158 31191 : _dt(_problem.dt()),
159 31191 : _dt_old(_problem.dtOld()),
160 62382 : _unconstrained_dt(declareRecoverableData<Real>("unconstrained_dt", -1)),
161 62382 : _at_sync_point(declareRecoverableData<bool>("at_sync_point", false)),
162 62382 : _last_solve_converged(declareRecoverableData<bool>("last_solve_converged", true)),
163 31191 : _xfem_repeat_step(false),
164 62382 : _end_time(getParam<Real>("end_time")),
165 62382 : _dtmin(getParam<Real>("dtmin")),
166 62382 : _dtmax(getParam<Real>("dtmax")),
167 62382 : _num_steps(getParam<unsigned int>("num_steps")),
168 62382 : _n_startup_steps(getParam<int>("n_startup_steps")),
169 62382 : _steady_state_detection(getParam<bool>("steady_state_detection")),
170 62382 : _steady_state_start_time(getParam<Real>("steady_state_start_time")),
171 31191 : _sync_times(_app.getOutputWarehouse().getSyncTimes()),
172 62382 : _abort(getParam<bool>("abort_on_solve_fail")),
173 62382 : _error_on_dtmin(getParam<bool>("error_on_dtmin")),
174 62382 : _time_interval(declareRecoverableData<bool>("time_interval", false)),
175 62382 : _start_time(getParam<Real>("start_time")),
176 62382 : _timestep_tolerance(getParam<Real>("timestep_tolerance")),
177 62382 : _target_time(declareRecoverableData<Real>("target_time", -std::numeric_limits<Real>::max())),
178 62382 : _use_multiapp_dt(getParam<bool>("use_multiapp_dt")),
179 62382 : _testing_restep(false)
180 : {
181 31191 : _t_step = 0;
182 31191 : _dt = 0;
183 31191 : _next_interval_output_time = 0.0;
184 :
185 : // Either a start_time has been forced on us, or we want to tell the App about what our start time
186 : // is (in case anyone else is interested.
187 31191 : if (_app.hasStartTime())
188 0 : _start_time = _app.getStartTime();
189 62382 : else if (parameters.isParamSetByUser("start_time"))
190 4023 : _app.setStartTime(_start_time);
191 :
192 31191 : _time = _time_old = _start_time;
193 31191 : _problem.transient(true);
194 :
195 31191 : setupTimeIntegrator();
196 :
197 : // Cut timesteps and end_time in half
198 31187 : if (_app.testCheckpointHalfTransient())
199 : {
200 : mooseAssert(!_app.testReStep(), "Cannot use with restep");
201 2065 : _end_time = (_start_time + _end_time) / 2.0;
202 2065 : _num_steps /= 2.0;
203 :
204 2065 : if (_num_steps == 0) // Always do one step in the first half
205 749 : _num_steps = 1;
206 : }
207 : // Retest a timestep (see options below for which timestep)
208 29122 : else if (_app.testReStep())
209 : {
210 1430 : if (_problem.shouldSolve())
211 : {
212 : // If num_steps is defined, we'll use that to determine restep timestep
213 2300 : if (!parameters.isParamSetByAddParam("num_steps"))
214 883 : _test_restep_step = _t_step + (_num_steps + 1) / 2;
215 : // If end_time is defined, we'll use the half time to determine when to restep
216 2300 : if (!parameters.isParamSetByAddParam("end_time"))
217 306 : _test_restep_time = (_start_time + _end_time) / 2;
218 : // If neither was set or we are doing pseudo-transient, pick the second timestep
219 1150 : if ((!_test_restep_step && !_test_restep_time) || _steady_state_detection)
220 30 : _test_restep_step = 2;
221 :
222 1150 : std::stringstream msg;
223 1150 : if (_test_restep_step && _test_restep_time)
224 58 : msg << "Timestep " << *_test_restep_step << " or time " << *_test_restep_time
225 58 : << " (whichever happens first)";
226 1092 : else if (_test_restep_step)
227 844 : msg << "Timestep " << *_test_restep_step;
228 248 : else if (_test_restep_time)
229 248 : msg << "Time " << *_test_restep_time;
230 1150 : mooseInfo(msg.str(), " will be forcefully retried due to --test-restep.");
231 1150 : }
232 : else
233 280 : mooseInfo(
234 : "A timestep is not being retried with --test-restep because Problem/solve=false.\n\nTo "
235 : "avoid this test being ran, you could set `restep = false` in the test specification.");
236 : }
237 :
238 93561 : if (isParamValid("steady_state_convergence"))
239 114 : _problem.setSteadyStateConvergenceName(getParam<ConvergenceName>("steady_state_convergence"));
240 : else
241 : // Note that we create a steady-state Convergence object even if steady_state_detection ==
242 : // false. This could possibly be changed in the future, but TransientMultiApp would need to be
243 : // able to signal for the Convergence object to be created in case it uses steady-state
244 : // detection for sub-stepping.
245 31149 : _problem.setNeedToAddDefaultSteadyStateConvergence();
246 31187 : }
247 :
248 : void
249 30416 : TransientBase::init()
250 : {
251 30416 : _problem.execute(EXEC_PRE_MULTIAPP_SETUP);
252 30416 : _problem.initialSetup();
253 30206 : _fixed_point_solve->initialSetup();
254 :
255 : mooseAssert(getTimeStepper(), "No time stepper was set");
256 :
257 30206 : _time_stepper->init();
258 :
259 30176 : auto & conv = _problem.getConvergence(_problem.getSteadyStateConvergenceName());
260 30176 : conv.checkIterationType(ConvergenceIterationTypes::STEADY_STATE);
261 :
262 30176 : if (_app.isRecovering()) // Recover case
263 : {
264 2164 : if (_t_step == 0)
265 0 : mooseError(
266 : "Internal error in TransientBase executioner: _t_step is equal to 0 while recovering "
267 : "in init().");
268 :
269 2164 : _dt_old = _dt;
270 : }
271 30176 : }
272 :
273 : void
274 30563 : TransientBase::preExecute()
275 : {
276 30563 : _time_stepper->preExecute();
277 :
278 30563 : if (!_app.isRecovering())
279 : {
280 28508 : _t_step = 0;
281 28508 : _dt = 0;
282 28508 : _next_interval_output_time = 0.0;
283 28508 : if (!_app.isRestarting())
284 28102 : _time = _time_old = _start_time;
285 :
286 28508 : _problem.outputStep(EXEC_INITIAL);
287 :
288 28508 : computeDT();
289 28504 : _dt = getDT();
290 28504 : if (_dt == 0)
291 4 : mooseError("Time stepper computed zero time step size on initial which is not allowed.\n"
292 : "1. If you are using an existing time stepper, double check the values in your "
293 : "input file or report an error.\n"
294 : "2. If you are developing a new time stepper, make sure that initial time step "
295 : "size in your code is computed correctly.");
296 28500 : const auto & tis = getTimeIntegrators();
297 56964 : for (auto & ti : tis)
298 28468 : ti->init();
299 28496 : }
300 30551 : }
301 :
302 : void
303 185802 : TransientBase::preStep()
304 : {
305 185802 : _time_stepper->preStep();
306 185802 : }
307 :
308 : void
309 211150 : TransientBase::postStep()
310 : {
311 211150 : _time_stepper->postStep();
312 211150 : }
313 :
314 : void
315 22107 : TransientBase::execute()
316 : {
317 22107 : preExecute();
318 :
319 : // Start time loop...
320 201183 : while (keepGoing())
321 : {
322 179360 : incrementStepOrReject();
323 179356 : preStep();
324 179356 : computeDT();
325 179235 : takeStep();
326 179088 : endStep();
327 179088 : postStep();
328 : }
329 :
330 21819 : if (lastSolveConverged())
331 : {
332 21777 : _t_step++;
333 :
334 : /*
335 : * Call the multi-app executioners endStep and
336 : * postStep methods when doing Picard or when not automatically advancing sub-applications for
337 : * some other reason. We do not perform these calls for loose-coupling/auto-advancement
338 : * problems because TransientBase::endStep and TransientBase::postStep get called from
339 : * TransientBaseMultiApp::solveStep in that case.
340 : */
341 21777 : if (!_fixed_point_solve->autoAdvance())
342 : {
343 1082 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN,
344 : /*recurse_through_multiapp_levels=*/true);
345 1082 : _problem.finishMultiAppStep(EXEC_TIMESTEP_BEGIN, /*recurse_through_multiapp_levels=*/true);
346 1082 : _problem.finishMultiAppStep(EXEC_TIMESTEP_END, /*recurse_through_multiapp_levels=*/true);
347 1082 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_END,
348 : /*recurse_through_multiapp_levels=*/true);
349 : }
350 : }
351 :
352 21819 : if (!_app.testCheckpointHalfTransient())
353 : {
354 102015 : TIME_SECTION("final", 1, "Executing Final Objects");
355 20403 : _problem.execMultiApps(EXEC_FINAL);
356 20403 : _problem.finalizeMultiApps();
357 20403 : _problem.execute(EXEC_FINAL);
358 20399 : _problem.outputStep(EXEC_FINAL);
359 20399 : }
360 :
361 : // This method is to finalize anything else we want to do on the problem side.
362 21815 : _problem.postExecute();
363 :
364 : // This method can be overridden for user defined activities in the Executioner.
365 21815 : postExecute();
366 :
367 21815 : if (_test_restep_step || _test_restep_time)
368 4 : mooseError((_test_restep_step ? "Timestep " : "Time "),
369 4 : (_test_restep_step ? *_test_restep_step : *_test_restep_time),
370 : " was never retried because the simulation did not get to this timestep.\n\nTo "
371 : "support restep testing, specify `num_steps` in the input.\nOtherwise, set "
372 : "`restep = false` in this test specification.");
373 21811 : }
374 :
375 : void
376 238880 : TransientBase::computeDT()
377 : {
378 : // We're repeating the solve of the previous timestep,
379 : // so we use the same dt
380 238880 : if (_testing_restep)
381 : {
382 : mooseAssert(!_test_restep_step && !_test_restep_time, "Should not be set");
383 1146 : return;
384 : }
385 :
386 237734 : _time_stepper->computeStep(); // This is actually when DT gets computed
387 : }
388 :
389 : void
390 203851 : TransientBase::incrementStepOrReject()
391 : {
392 203851 : if (lastSolveConverged())
393 : {
394 198600 : if (!_xfem_repeat_step)
395 : {
396 : #ifdef LIBMESH_ENABLE_AMR
397 198600 : if (_t_step != 0)
398 178008 : _problem.adaptMesh();
399 : #endif
400 :
401 198600 : _time_old = _time;
402 198600 : _t_step++;
403 :
404 198600 : bool advance_problem_state = true;
405 198600 : const auto & tis = getTimeIntegrators();
406 400839 : for (auto & ti : tis)
407 : // We do not want to advance the problem state here if a time integrator is already doing so
408 : // itself
409 202239 : if (ti->advancesProblemState())
410 : {
411 0 : advance_problem_state = false;
412 0 : break;
413 : }
414 :
415 198600 : if (advance_problem_state)
416 198600 : _problem.advanceState();
417 0 : else if (tis.size() > 1)
418 0 : mooseError("Either there must be a single time integrator which advances state or none of "
419 : "the time integrators should advance state.");
420 :
421 198600 : if (_t_step == 1)
422 20592 : return;
423 :
424 : /*
425 : * Call the multi-app executioners endStep and
426 : * postStep methods when doing Picard or when not automatically advancing sub-applications for
427 : * some other reason. We do not perform these calls for loose-coupling/auto-advancement
428 : * problems because TransientBase::endStep and TransientBase::postStep get called from
429 : * TransientBaseMultiApp::solveStep in that case.
430 : */
431 178008 : if (!_fixed_point_solve->autoAdvance())
432 : {
433 8316 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
434 8316 : _problem.finishMultiAppStep(EXEC_TIMESTEP_BEGIN);
435 8316 : _problem.finishMultiAppStep(EXEC_TIMESTEP_END);
436 8316 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_END);
437 : }
438 :
439 : /*
440 : * Ensure that we increment the sub-application time steps so that
441 : * when dt selection is made in the master application, we are using
442 : * the correct time step information
443 : */
444 178008 : _problem.incrementMultiAppTStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
445 178008 : _problem.incrementMultiAppTStep(EXEC_TIMESTEP_BEGIN);
446 178008 : _problem.incrementMultiAppTStep(EXEC_TIMESTEP_END);
447 178008 : _problem.incrementMultiAppTStep(EXEC_MULTIAPP_FIXED_POINT_END);
448 198600 : }
449 : }
450 : else
451 : {
452 5251 : _problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_BEGIN, true);
453 5251 : _problem.restoreMultiApps(EXEC_TIMESTEP_BEGIN, true);
454 5251 : _problem.restoreMultiApps(EXEC_TIMESTEP_END, true);
455 5251 : _problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_END, true);
456 5251 : _time_stepper->rejectStep();
457 5247 : _time = _time_old;
458 : }
459 : }
460 :
461 : void
462 254666 : TransientBase::takeStep(Real input_dt)
463 : {
464 254666 : if (lastSolveConverged())
465 249535 : _dt_old = _dt;
466 :
467 : // We're repeating the solve of the previous timestep,
468 : // so we use the same dt
469 254666 : if (_testing_restep)
470 : {
471 : mooseAssert(!_test_restep_step && !_test_restep_time, "Should not be set");
472 1146 : _testing_restep = false;
473 : }
474 253520 : else if (input_dt == -1.0)
475 183985 : _dt = computeConstrainedDT();
476 : else
477 69535 : _dt = input_dt;
478 :
479 254662 : _time_stepper->preSolve();
480 :
481 : // Increment time
482 254662 : _time = _time_old + _dt;
483 :
484 254662 : _problem.timestepSetup();
485 :
486 254662 : _problem.onTimestepBegin();
487 :
488 254662 : _time_stepper->step();
489 254519 : _xfem_repeat_step = _fixed_point_solve->XFEMRepeatStep();
490 :
491 254519 : _last_solve_converged = _time_stepper->converged();
492 :
493 : // We're running with --test-restep and we have just solved
494 : // the timestep we are to repeat for the first time
495 510982 : if ((_test_restep_step && *_test_restep_step == _t_step) ||
496 256463 : (_test_restep_time && _time >= *_test_restep_time))
497 : {
498 : mooseAssert(!_testing_restep, "Should not be set");
499 :
500 1146 : mooseInfo("Aborting and retrying solve for timestep ", _t_step, " due to --test-restep");
501 1146 : _last_solve_converged = false;
502 1146 : _testing_restep = true;
503 1146 : _test_restep_step.reset();
504 1146 : _test_restep_time.reset();
505 :
506 1146 : return;
507 : }
508 :
509 253373 : if (!lastSolveConverged())
510 : {
511 4245 : _console << "Aborting as solve did not converge" << std::endl;
512 4245 : return;
513 : }
514 :
515 249128 : if (!(_problem.haveXFEM() && _fixed_point_solve->XFEMRepeatStep()))
516 : {
517 249128 : if (lastSolveConverged())
518 249128 : _time_stepper->acceptStep();
519 : else
520 0 : _time_stepper->rejectStep();
521 : }
522 :
523 249128 : _time = _time_old;
524 :
525 249128 : _time_stepper->postSolve();
526 :
527 249128 : return;
528 : }
529 :
530 : void
531 211105 : TransientBase::endStep(Real input_time)
532 : {
533 211105 : if (input_time == -1.0)
534 211080 : _time = _time_old + _dt;
535 : else
536 25 : _time = input_time;
537 :
538 211105 : if (lastSolveConverged())
539 : {
540 205831 : if (_xfem_repeat_step)
541 0 : _time = _time_old;
542 : else
543 : {
544 : // TODO: add linear system support
545 205831 : const auto & tis = getTimeIntegrators();
546 415294 : for (auto & ti : tis)
547 209463 : ti->postStep();
548 :
549 : // Compute the Error Indicators and Markers
550 205831 : _problem.computeIndicators();
551 205831 : _problem.computeMarkers();
552 :
553 : // Perform the output of the current time step
554 205831 : _problem.outputStep(EXEC_TIMESTEP_END);
555 :
556 : // output
557 205831 : if (_time_interval && (_time + _timestep_tolerance >= _next_interval_output_time))
558 0 : _next_interval_output_time += _time_interval_output_interval;
559 205831 : }
560 : }
561 211105 : }
562 :
563 : Real
564 184535 : TransientBase::computeConstrainedDT()
565 : {
566 : // // If start up steps are needed
567 : // if (_t_step == 1 && _n_startup_steps > 1)
568 : // _dt = _input_dt/(double)(_n_startup_steps);
569 : // else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
570 : // _dt = _input_dt;
571 :
572 184535 : Real dt_cur = _dt;
573 184535 : std::ostringstream diag;
574 :
575 : // After startup steps, compute new dt
576 184535 : if (_t_step > _n_startup_steps)
577 184431 : dt_cur = getDT();
578 :
579 : else
580 : {
581 : diag << "Timestep < n_startup_steps, using old dt: " << std::setw(9) << std::setprecision(6)
582 104 : << std::setfill('0') << std::showpoint << std::left << _dt << " tstep: " << _t_step
583 104 : << " n_startup_steps: " << _n_startup_steps << std::endl;
584 : }
585 184535 : _unconstrained_dt = dt_cur;
586 :
587 184535 : if (_verbose)
588 5804 : _console << diag.str();
589 :
590 184535 : diag.str("");
591 184535 : diag.clear();
592 :
593 : // Allow the time stepper to limit the time step
594 184535 : _at_sync_point = _time_stepper->constrainStep(dt_cur);
595 :
596 : // Don't let time go beyond next time interval output if specified
597 184531 : if ((_time_interval) && (_time + dt_cur + _timestep_tolerance >= _next_interval_output_time))
598 : {
599 0 : dt_cur = _next_interval_output_time - _time;
600 0 : _at_sync_point = true;
601 :
602 : diag << "Limiting dt for time interval output at time: " << std::setw(9) << std::setprecision(6)
603 0 : << std::setfill('0') << std::showpoint << std::left << _next_interval_output_time
604 0 : << " dt: " << std::setw(9) << std::setprecision(6) << std::setfill('0') << std::showpoint
605 0 : << std::left << dt_cur << std::endl;
606 : }
607 :
608 : // If a target time is set and the current dt would exceed it, limit dt to match the target
609 190977 : if (_target_time > -std::numeric_limits<Real>::max() + _timestep_tolerance &&
610 6446 : _time + dt_cur + _timestep_tolerance >= _target_time)
611 : {
612 1717 : dt_cur = _target_time - _time;
613 1717 : _at_sync_point = true;
614 :
615 : diag << "Limiting dt for target time: " << std::setw(9) << std::setprecision(6)
616 1717 : << std::setfill('0') << std::showpoint << std::left << _next_interval_output_time
617 1717 : << " dt: " << std::setw(9) << std::setprecision(6) << std::setfill('0') << std::showpoint
618 1717 : << std::left << dt_cur << std::endl;
619 : }
620 :
621 : // Constrain by what the multi apps are doing
622 184531 : constrainDTFromMultiApp(dt_cur, diag, EXEC_MULTIAPP_FIXED_POINT_BEGIN);
623 184531 : constrainDTFromMultiApp(dt_cur, diag, EXEC_TIMESTEP_BEGIN);
624 184531 : constrainDTFromMultiApp(dt_cur, diag, EXEC_TIMESTEP_END);
625 184531 : constrainDTFromMultiApp(dt_cur, diag, EXEC_MULTIAPP_FIXED_POINT_END);
626 :
627 184531 : if (_verbose)
628 5804 : _console << diag.str();
629 :
630 184531 : return dt_cur;
631 184531 : }
632 :
633 : void
634 738124 : TransientBase::constrainDTFromMultiApp(Real & dt_cur,
635 : std::ostringstream & diag,
636 : const ExecFlagType & execute_on) const
637 : {
638 738124 : Real multi_app_dt = _problem.computeMultiAppsDT(execute_on);
639 738124 : if (_use_multiapp_dt || multi_app_dt < dt_cur)
640 : {
641 1949 : dt_cur = multi_app_dt;
642 1949 : _at_sync_point = false;
643 1949 : diag << "Limiting dt for MultiApps on " << execute_on.name() << ": " << std::setw(9)
644 1949 : << std::setprecision(6) << std::setfill('0') << std::showpoint << std::left << dt_cur
645 1949 : << std::endl;
646 : }
647 738124 : }
648 :
649 : Real
650 239320 : TransientBase::getDT()
651 : {
652 239320 : return _time_stepper->getCurrentDT();
653 : }
654 :
655 : bool
656 201183 : TransientBase::keepGoing()
657 : {
658 201183 : bool keep_going = !_problem.isSolveTerminationRequested();
659 :
660 : // Check for stop condition based upon steady-state check flag:
661 201183 : if (lastSolveConverged())
662 : {
663 195916 : if (!_xfem_repeat_step)
664 : {
665 195916 : if (_steady_state_detection == true && _time > _steady_state_start_time)
666 : {
667 : // Check solution difference relative norm against steady-state tolerance
668 13814 : if (convergedToSteadyState())
669 : {
670 375 : _console << "Steady-State Solution Achieved at time: " << _time << std::endl;
671 : // Output last solve if not output previously by forcing it
672 375 : keep_going = false;
673 : }
674 : }
675 :
676 : // Check for stop condition based upon number of simulation steps and/or solution end time:
677 195912 : if (static_cast<unsigned int>(_t_step) >= _num_steps)
678 17223 : keep_going = false;
679 :
680 195912 : if ((_time >= _end_time) || (fabs(_time - _end_time) <= _timestep_tolerance))
681 4322 : keep_going = false;
682 : }
683 : }
684 5267 : else if (_abort)
685 : {
686 20 : _console << "Aborting as solve did not converge and input selected to abort" << std::endl;
687 20 : keep_going = false;
688 : }
689 5247 : else if (!_error_on_dtmin && _dt <= _dtmin)
690 : {
691 22 : _console << "Aborting as timestep already at or below dtmin" << std::endl;
692 22 : keep_going = false;
693 : }
694 :
695 201179 : return keep_going;
696 : }
697 :
698 : void
699 0 : TransientBase::estimateTimeError()
700 : {
701 0 : }
702 :
703 : bool
704 1505367 : TransientBase::lastSolveConverged() const
705 : {
706 1505367 : return _last_solve_converged;
707 : }
708 :
709 : void
710 29187 : TransientBase::postExecute()
711 : {
712 29187 : _time_stepper->postExecute();
713 29187 : }
714 :
715 : void
716 1748 : TransientBase::setTargetTime(Real target_time)
717 : {
718 1748 : _target_time = target_time;
719 1748 : }
720 :
721 : Real
722 13270 : TransientBase::computeSolutionChangeNorm(bool check_aux, bool normalize_by_dt) const
723 : {
724 13270 : return relativeSolutionDifferenceNorm(check_aux) / (normalize_by_dt ? _dt : Real(1));
725 : }
726 :
727 : void
728 31191 : TransientBase::setupTimeIntegrator()
729 : {
730 93573 : if (_pars.isParamSetByUser("scheme") && _problem.hasTimeIntegrator())
731 4 : mooseError("You cannot specify time_scheme in the Executioner and independently add a "
732 : "TimeIntegrator to the system at the same time");
733 :
734 31187 : if (!_problem.hasTimeIntegrator())
735 : {
736 : // backwards compatibility
737 30068 : std::string ti_str;
738 : using namespace Moose;
739 :
740 30068 : switch (_time_scheme)
741 : {
742 29736 : case TI_IMPLICIT_EULER:
743 29736 : ti_str = "ImplicitEuler";
744 29736 : break;
745 78 : case TI_EXPLICIT_EULER:
746 78 : ti_str = "ExplicitEuler";
747 78 : break;
748 49 : case TI_CRANK_NICOLSON:
749 49 : ti_str = "CrankNicolson";
750 49 : break;
751 166 : case TI_BDF2:
752 166 : ti_str = "BDF2";
753 166 : break;
754 0 : case TI_EXPLICIT_MIDPOINT:
755 0 : ti_str = "ExplicitMidpoint";
756 0 : break;
757 0 : case TI_LSTABLE_DIRK2:
758 0 : ti_str = "LStableDirk2";
759 0 : break;
760 0 : case TI_EXPLICIT_TVD_RK_2:
761 0 : ti_str = "ExplicitTVDRK2";
762 0 : break;
763 39 : case TI_NEWMARK_BETA:
764 39 : ti_str = "NewmarkBeta";
765 39 : break;
766 0 : default:
767 0 : mooseError("Unknown scheme: ", _time_scheme);
768 : break;
769 : }
770 :
771 60136 : InputParameters params = _app.getFactory().getValidParams(ti_str);
772 30068 : _problem.addTimeIntegrator(ti_str, ti_str, params);
773 30068 : }
774 31187 : }
775 :
776 : std::string
777 25807 : TransientBase::getTimeStepperName() const
778 : {
779 25807 : if (_time_stepper)
780 : {
781 25807 : TimeStepper & ts = *_time_stepper;
782 25807 : return demangle(typeid(ts).name());
783 : }
784 : else
785 0 : return std::string();
786 : }
787 :
788 : std::vector<std::string>
789 25701 : TransientBase::getTimeIntegratorNames() const
790 : {
791 25701 : const auto & tis = getTimeIntegrators();
792 25701 : if (tis.empty())
793 0 : mooseError("Time integrator has not been built yet so we can't retrieve its name");
794 :
795 25701 : std::vector<std::string> ret;
796 51486 : for (const auto & ti : tis)
797 : {
798 103140 : const auto & sys = ti->getCheckedPointerParam<SystemBase *>("_sys")->system();
799 51570 : const auto & uvars = ti->getParam<std::vector<VariableName>>("variables");
800 :
801 25785 : std::vector<VariableName> vars;
802 25901 : for (const auto & var : uvars)
803 116 : if (sys.has_variable(var))
804 116 : vars.push_back(var);
805 :
806 25785 : if (!uvars.empty() && vars.empty())
807 0 : continue;
808 :
809 25785 : if (tis.size() > 1)
810 : {
811 400 : const std::string sys_prefix = _problem.numSolverSystems() > 1 ? sys.name() : "";
812 168 : const std::string var_prefix = MooseUtils::join(vars, ", ");
813 168 : const bool both = !sys_prefix.empty() && !var_prefix.empty();
814 168 : ret.push_back("[" + sys_prefix + (both ? " (" : "") + var_prefix + (both ? ")" : "") + "]:");
815 168 : }
816 :
817 25785 : ret.push_back(ti->type());
818 25785 : }
819 51402 : return ret;
820 25701 : }
821 :
822 : void
823 31079 : TransientBase::setTimeStepper(TimeStepper & ts)
824 : {
825 : mooseAssert(!_time_stepper, "Already set");
826 31079 : _time_stepper = &ts;
827 31079 : }
828 :
829 : bool
830 14076 : TransientBase::convergedToSteadyState() const
831 : {
832 14076 : auto & convergence = _problem.getConvergence(_problem.getSteadyStateConvergenceName());
833 14076 : const auto status = convergence.checkConvergence(_t_step);
834 :
835 14076 : if (status == Convergence::MooseConvergenceStatus::DIVERGED)
836 4 : mooseError(
837 4 : "The steady-state Convergence object (", convergence.name(), ") reported divergence.");
838 14072 : else if (status == Convergence::MooseConvergenceStatus::CONVERGED)
839 400 : return true;
840 : else // status == Convergence::MooseConvergenceStatus::ITERATING
841 13672 : return false;
842 : }
843 :
844 : void
845 77 : TransientBase::parentOutputPositionChanged()
846 : {
847 77 : _fe_problem.parentOutputPositionChanged();
848 77 : }
|