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 :
27 : #include "libmesh/implicit_system.h"
28 : #include "libmesh/nonlinear_implicit_system.h"
29 : #include "libmesh/transient_system.h"
30 : #include "libmesh/numeric_vector.h"
31 :
32 : // C++ Includes
33 : #include <iomanip>
34 : #include <iostream>
35 : #include <fstream>
36 : #include <sstream>
37 : #include <iomanip>
38 :
39 : InputParameters
40 85434 : TransientBase::validParams()
41 : {
42 85434 : InputParameters params = Executioner::validParams();
43 85434 : params.addClassDescription("Executioner for time varying simulations.");
44 :
45 85434 : std::vector<Real> sync_times(1);
46 85434 : sync_times[0] = -std::numeric_limits<Real>::max();
47 :
48 : /**
49 : * For backwards compatibility we'll allow users to set the TimeIntegration scheme inside of the
50 : * executioner block
51 : * as long as the TimeIntegrator does not have any additional parameters.
52 : */
53 : MooseEnum schemes("implicit-euler explicit-euler crank-nicolson bdf2 explicit-midpoint dirk "
54 : "explicit-tvd-rk-2 newmark-beta",
55 85434 : "implicit-euler");
56 :
57 85434 : params.addParam<Real>("start_time", 0.0, "The start time of the simulation");
58 85434 : params.addParam<Real>("end_time", 1.0e30, "The end time of the simulation");
59 85434 : params.addParam<Real>("dt", 1., "The timestep size between solves");
60 85434 : params.addParam<Real>("dtmin", 1.0e-12, "The minimum timestep size in an adaptive run");
61 85434 : params.addParam<Real>("dtmax", 1.0e30, "The maximum timestep size in an adaptive run");
62 256302 : params.addParam<bool>(
63 170868 : "reset_dt", false, "Use when restarting a calculation to force a change in dt.");
64 256302 : params.addParam<unsigned int>("num_steps",
65 170868 : std::numeric_limits<unsigned int>::max(),
66 : "The number of timesteps in a transient run");
67 85434 : params.addParam<int>("n_startup_steps", 0, "The number of timesteps during startup");
68 :
69 256302 : params.addDeprecatedParam<bool>("trans_ss_check",
70 170868 : false,
71 : "Whether or not to check for steady state conditions",
72 : "Use steady_state_detection instead");
73 256302 : params.addDeprecatedParam<Real>("ss_check_tol",
74 170868 : 1.0e-08,
75 : "Whenever the relative residual changes by less "
76 : "than this the solution will be considered to be "
77 : "at steady state.",
78 : "Use steady_state_tolerance instead");
79 256302 : params.addDeprecatedParam<Real>(
80 : "ss_tmin",
81 170868 : 0.0,
82 : "Minimum amount of time to run before checking for steady state conditions.",
83 : "Use steady_state_start_time instead");
84 :
85 256302 : params.addParam<bool>(
86 170868 : "steady_state_detection", false, "Whether or not to check for steady state conditions");
87 256302 : params.addParam<Real>("steady_state_tolerance",
88 170868 : 1.0e-08,
89 : "Whenever the relative residual changes by less "
90 : "than this the solution will be considered to be "
91 : "at steady state.");
92 256302 : params.addParam<Real>(
93 : "steady_state_start_time",
94 170868 : 0.0,
95 : "Minimum amount of time to run before checking for steady state conditions.");
96 256302 : params.addParam<bool>(
97 : "normalize_solution_diff_norm_by_dt",
98 170868 : true,
99 : "Whether to divide the solution difference norm by dt. If taking 'small' "
100 : "time steps you probably want this to be true. If taking very 'large' timesteps in an "
101 : "attempt to *reach* a steady-state, you probably want this parameter to be false.");
102 :
103 85434 : params.addParam<std::vector<std::string>>("time_periods", "The names of periods");
104 85434 : params.addParam<std::vector<Real>>("time_period_starts", "The start times of time periods");
105 85434 : params.addParam<std::vector<Real>>("time_period_ends", "The end times of time periods");
106 256302 : params.addParam<bool>(
107 170868 : "abort_on_solve_fail", false, "abort if solve not converged rather than cut timestep");
108 256302 : params.addParam<bool>(
109 : "error_on_dtmin",
110 170868 : true,
111 : "Throw error when timestep is less than dtmin instead of just aborting solve.");
112 85434 : params.addParam<MooseEnum>("scheme", schemes, "Time integration scheme used.");
113 256302 : params.addParam<Real>("timestep_tolerance",
114 170868 : 1.0e-12,
115 : "the tolerance setting for final timestep size and sync times");
116 :
117 256302 : params.addParam<bool>("use_multiapp_dt",
118 170868 : false,
119 : "If true then the dt for the simulation will be "
120 : "chosen by the MultiApps. If false (the "
121 : "default) then the minimum over the master dt "
122 : "and the MultiApps is used");
123 :
124 256302 : params.addParam<bool>("check_aux",
125 170868 : false,
126 : "Whether to check the auxiliary system for convergence to steady-state. If "
127 : "false, then the nonlinear system is used.");
128 :
129 85434 : params.addParamNamesToGroup(
130 : "steady_state_detection steady_state_tolerance steady_state_start_time check_aux",
131 : "Steady State Detection");
132 :
133 85434 : params.addParamNamesToGroup("start_time dtmin dtmax n_startup_steps trans_ss_check ss_check_tol "
134 : "ss_tmin abort_on_solve_fail timestep_tolerance use_multiapp_dt",
135 : "Advanced");
136 :
137 85434 : params.addParamNamesToGroup("time_periods time_period_starts time_period_ends", "Time Periods");
138 :
139 170868 : return params;
140 85434 : }
141 :
142 28403 : TransientBase::TransientBase(const InputParameters & parameters)
143 : : Executioner(parameters),
144 28403 : _problem(_fe_problem),
145 56806 : _aux(_fe_problem.getAuxiliarySystem()),
146 28403 : _check_aux(getParam<bool>("check_aux")),
147 28403 : _time_scheme(getParam<MooseEnum>("scheme").getEnum<Moose::TimeIntegratorType>()),
148 28403 : _time_stepper(nullptr),
149 28403 : _t_step(_problem.timeStep()),
150 28403 : _time(_problem.time()),
151 28403 : _time_old(_problem.timeOld()),
152 28403 : _dt(_problem.dt()),
153 28403 : _dt_old(_problem.dtOld()),
154 28403 : _unconstrained_dt(declareRecoverableData<Real>("unconstrained_dt", -1)),
155 28403 : _at_sync_point(declareRecoverableData<bool>("at_sync_point", false)),
156 28403 : _last_solve_converged(declareRecoverableData<bool>("last_solve_converged", true)),
157 28403 : _xfem_repeat_step(false),
158 28403 : _end_time(getParam<Real>("end_time")),
159 28403 : _dtmin(getParam<Real>("dtmin")),
160 28403 : _dtmax(getParam<Real>("dtmax")),
161 28403 : _num_steps(getParam<unsigned int>("num_steps")),
162 28403 : _n_startup_steps(getParam<int>("n_startup_steps")),
163 28403 : _steady_state_detection(getParam<bool>("steady_state_detection")),
164 28403 : _steady_state_tolerance(getParam<Real>("steady_state_tolerance")),
165 28403 : _steady_state_start_time(getParam<Real>("steady_state_start_time")),
166 28403 : _sync_times(_app.getOutputWarehouse().getSyncTimes()),
167 28403 : _abort(getParam<bool>("abort_on_solve_fail")),
168 28403 : _error_on_dtmin(getParam<bool>("error_on_dtmin")),
169 28403 : _time_interval(declareRecoverableData<bool>("time_interval", false)),
170 28403 : _start_time(getParam<Real>("start_time")),
171 28403 : _timestep_tolerance(getParam<Real>("timestep_tolerance")),
172 28403 : _target_time(declareRecoverableData<Real>("target_time", -std::numeric_limits<Real>::max())),
173 28403 : _use_multiapp_dt(getParam<bool>("use_multiapp_dt")),
174 28403 : _solution_change_norm(declareRecoverableData<Real>("solution_change_norm", 0.0)),
175 56806 : _normalize_solution_diff_norm_by_dt(getParam<bool>("normalize_solution_diff_norm_by_dt"))
176 : {
177 : // Handle deprecated parameters
178 28403 : if (!parameters.isParamSetByAddParam("trans_ss_check"))
179 0 : _steady_state_detection = getParam<bool>("trans_ss_check");
180 :
181 28403 : if (!parameters.isParamSetByAddParam("ss_check_tol"))
182 0 : _steady_state_tolerance = getParam<Real>("ss_check_tol");
183 :
184 28403 : if (!parameters.isParamSetByAddParam("ss_tmin"))
185 0 : _steady_state_start_time = getParam<Real>("ss_tmin");
186 :
187 28403 : _t_step = 0;
188 28403 : _dt = 0;
189 28403 : _next_interval_output_time = 0.0;
190 :
191 : // Either a start_time has been forced on us, or we want to tell the App about what our start time
192 : // is (in case anyone else is interested.
193 28403 : if (_app.hasStartTime())
194 0 : _start_time = _app.getStartTime();
195 28403 : else if (parameters.isParamSetByUser("start_time"))
196 3663 : _app.setStartTime(_start_time);
197 :
198 28403 : _time = _time_old = _start_time;
199 28403 : _problem.transient(true);
200 :
201 28403 : setupTimeIntegrator();
202 :
203 28399 : if (_app.testCheckpointHalfTransient()) // Cut timesteps and end_time in half...
204 : {
205 2042 : _end_time = (_start_time + _end_time) / 2.0;
206 2042 : _num_steps /= 2.0;
207 :
208 2042 : if (_num_steps == 0) // Always do one step in the first half
209 748 : _num_steps = 1;
210 : }
211 28399 : }
212 :
213 : void
214 27628 : TransientBase::init()
215 : {
216 27628 : _problem.execute(EXEC_PRE_MULTIAPP_SETUP);
217 27628 : _problem.initialSetup();
218 :
219 : mooseAssert(getTimeStepper(), "No time stepper was set");
220 :
221 27443 : _time_stepper->init();
222 :
223 27420 : if (_app.isRecovering()) // Recover case
224 : {
225 2141 : if (_t_step == 0)
226 0 : mooseError(
227 : "Internal error in TransientBase executioner: _t_step is equal to 0 while recovering "
228 : "in init().");
229 :
230 2141 : _dt_old = _dt;
231 : }
232 27420 : }
233 :
234 : void
235 27723 : TransientBase::preExecute()
236 : {
237 27723 : _time_stepper->preExecute();
238 :
239 27723 : if (!_app.isRecovering())
240 : {
241 25691 : _t_step = 0;
242 25691 : _dt = 0;
243 25691 : _next_interval_output_time = 0.0;
244 25691 : if (!_app.isRestarting())
245 25331 : _time = _time_old = _start_time;
246 :
247 25691 : _problem.outputStep(EXEC_INITIAL);
248 :
249 25691 : computeDT();
250 25687 : _dt = getDT();
251 25687 : if (_dt == 0)
252 4 : mooseError("Time stepper computed zero time step size on initial which is not allowed.\n"
253 : "1. If you are using an existing time stepper, double check the values in your "
254 : "input file or report an error.\n"
255 : "2. If you are developing a new time stepper, make sure that initial time step "
256 : "size in your code is computed correctly.");
257 25683 : const auto & tis = getTimeIntegrators();
258 51440 : for (auto & ti : tis)
259 25761 : ti->init();
260 25679 : }
261 27711 : }
262 :
263 : void
264 168255 : TransientBase::preStep()
265 : {
266 168255 : _time_stepper->preStep();
267 168255 : }
268 :
269 : void
270 191188 : TransientBase::postStep()
271 : {
272 191188 : _time_stepper->postStep();
273 191188 : }
274 :
275 : void
276 19943 : TransientBase::execute()
277 : {
278 19943 : preExecute();
279 :
280 : // Start time loop...
281 182263 : while (keepGoing())
282 : {
283 162603 : incrementStepOrReject();
284 162599 : preStep();
285 162599 : computeDT();
286 162478 : takeStep();
287 162332 : endStep();
288 162332 : postStep();
289 : }
290 :
291 19660 : if (lastSolveConverged())
292 : {
293 19619 : _t_step++;
294 :
295 : /*
296 : * Call the multi-app executioners endStep and
297 : * postStep methods when doing Picard or when not automatically advancing sub-applications for
298 : * some other reason. We do not perform these calls for loose-coupling/auto-advancement
299 : * problems because TransientBase::endStep and TransientBase::postStep get called from
300 : * TransientBaseMultiApp::solveStep in that case.
301 : */
302 19619 : if (!_fixed_point_solve->autoAdvance())
303 : {
304 1006 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN,
305 : /*recurse_through_multiapp_levels=*/true);
306 1006 : _problem.finishMultiAppStep(EXEC_TIMESTEP_BEGIN, /*recurse_through_multiapp_levels=*/true);
307 1006 : _problem.finishMultiAppStep(EXEC_TIMESTEP_END, /*recurse_through_multiapp_levels=*/true);
308 1006 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_END,
309 : /*recurse_through_multiapp_levels=*/true);
310 : }
311 : }
312 :
313 19660 : if (!_app.testCheckpointHalfTransient())
314 : {
315 18271 : TIME_SECTION("final", 1, "Executing Final Objects");
316 18271 : _problem.execMultiApps(EXEC_FINAL);
317 18271 : _problem.finalizeMultiApps();
318 18271 : _problem.execute(EXEC_FINAL);
319 18267 : _problem.outputStep(EXEC_FINAL);
320 18267 : }
321 :
322 : // This method is to finalize anything else we want to do on the problem side.
323 19656 : _problem.postExecute();
324 :
325 : // This method can be overridden for user defined activities in the Executioner.
326 19656 : postExecute();
327 19656 : }
328 :
329 : void
330 216619 : TransientBase::computeDT()
331 : {
332 216619 : _time_stepper->computeStep(); // This is actually when DT gets computed
333 216494 : }
334 :
335 : void
336 184903 : TransientBase::incrementStepOrReject()
337 : {
338 184903 : if (lastSolveConverged())
339 : {
340 180749 : if (!_xfem_repeat_step)
341 : {
342 : #ifdef LIBMESH_ENABLE_AMR
343 180749 : if (_t_step != 0)
344 162287 : _problem.adaptMesh();
345 : #endif
346 :
347 180749 : _time_old = _time;
348 180749 : _t_step++;
349 :
350 180749 : bool advance_problem_state = true;
351 180749 : const auto & tis = getTimeIntegrators();
352 365446 : for (auto & ti : tis)
353 : // We do not want to advance the problem state here if a time integrator is already doing so
354 : // itself
355 184697 : if (ti->advancesProblemState())
356 : {
357 0 : advance_problem_state = false;
358 0 : break;
359 : }
360 :
361 180749 : if (advance_problem_state)
362 180749 : _problem.advanceState();
363 0 : else if (tis.size() > 1)
364 0 : mooseError("Either there must be a single time integrator which advances state or none of "
365 : "the time integrators should advance state.");
366 :
367 180749 : if (_t_step == 1)
368 18462 : return;
369 :
370 : /*
371 : * Call the multi-app executioners endStep and
372 : * postStep methods when doing Picard or when not automatically advancing sub-applications for
373 : * some other reason. We do not perform these calls for loose-coupling/auto-advancement
374 : * problems because TransientBase::endStep and TransientBase::postStep get called from
375 : * TransientBaseMultiApp::solveStep in that case.
376 : */
377 162287 : if (!_fixed_point_solve->autoAdvance())
378 : {
379 7669 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
380 7669 : _problem.finishMultiAppStep(EXEC_TIMESTEP_BEGIN);
381 7669 : _problem.finishMultiAppStep(EXEC_TIMESTEP_END);
382 7669 : _problem.finishMultiAppStep(EXEC_MULTIAPP_FIXED_POINT_END);
383 : }
384 :
385 : /*
386 : * Ensure that we increment the sub-application time steps so that
387 : * when dt selection is made in the master application, we are using
388 : * the correct time step information
389 : */
390 162287 : _problem.incrementMultiAppTStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
391 162287 : _problem.incrementMultiAppTStep(EXEC_TIMESTEP_BEGIN);
392 162287 : _problem.incrementMultiAppTStep(EXEC_TIMESTEP_END);
393 162287 : _problem.incrementMultiAppTStep(EXEC_MULTIAPP_FIXED_POINT_END);
394 180749 : }
395 : }
396 : else
397 : {
398 4154 : _problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_BEGIN, true);
399 4154 : _problem.restoreMultiApps(EXEC_TIMESTEP_BEGIN, true);
400 4154 : _problem.restoreMultiApps(EXEC_TIMESTEP_END, true);
401 4154 : _problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_END, true);
402 4154 : _time_stepper->rejectStep();
403 4150 : _time = _time_old;
404 : }
405 : }
406 :
407 : void
408 231980 : TransientBase::takeStep(Real input_dt)
409 : {
410 231980 : _dt_old = _dt;
411 :
412 231980 : if (input_dt == -1.0)
413 168134 : _dt = computeConstrainedDT();
414 : else
415 63846 : _dt = input_dt;
416 :
417 231976 : _time_stepper->preSolve();
418 :
419 : // Increment time
420 231976 : _time = _time_old + _dt;
421 :
422 231976 : _problem.timestepSetup();
423 :
424 231976 : _problem.onTimestepBegin();
425 :
426 231976 : _time_stepper->step();
427 231834 : _xfem_repeat_step = _fixed_point_solve->XFEMRepeatStep();
428 :
429 231834 : _last_solve_converged = _time_stepper->converged();
430 :
431 231834 : if (!lastSolveConverged())
432 : {
433 4292 : _console << "Aborting as solve did not converge" << std::endl;
434 4292 : return;
435 : }
436 :
437 227542 : if (!(_problem.haveXFEM() && _fixed_point_solve->XFEMRepeatStep()))
438 : {
439 227542 : if (lastSolveConverged())
440 227542 : _time_stepper->acceptStep();
441 : else
442 0 : _time_stepper->rejectStep();
443 : }
444 :
445 227542 : _time = _time_old;
446 :
447 227542 : _time_stepper->postSolve();
448 :
449 227542 : _solution_change_norm =
450 227542 : relativeSolutionDifferenceNorm() / (_normalize_solution_diff_norm_by_dt ? _dt : Real(1));
451 :
452 227542 : return;
453 : }
454 :
455 : void
456 191148 : TransientBase::endStep(Real input_time)
457 : {
458 191148 : if (input_time == -1.0)
459 191126 : _time = _time_old + _dt;
460 : else
461 22 : _time = input_time;
462 :
463 191148 : if (lastSolveConverged())
464 : {
465 186971 : if (_xfem_repeat_step)
466 0 : _time = _time_old;
467 : else
468 : {
469 : // TODO: add linear system support
470 186971 : const auto & tis = getTimeIntegrators();
471 377890 : for (auto & ti : tis)
472 190919 : ti->postStep();
473 :
474 : // Compute the Error Indicators and Markers
475 186971 : _problem.computeIndicators();
476 186971 : _problem.computeMarkers();
477 :
478 : // Perform the output of the current time step
479 186971 : _problem.outputStep(EXEC_TIMESTEP_END);
480 :
481 : // output
482 186971 : if (_time_interval && (_time + _timestep_tolerance >= _next_interval_output_time))
483 0 : _next_interval_output_time += _time_interval_output_interval;
484 186971 : }
485 : }
486 191148 : }
487 :
488 : Real
489 168134 : TransientBase::computeConstrainedDT()
490 : {
491 : // // If start up steps are needed
492 : // if (_t_step == 1 && _n_startup_steps > 1)
493 : // _dt = _input_dt/(double)(_n_startup_steps);
494 : // else if (_t_step == 1+_n_startup_steps && _n_startup_steps > 1)
495 : // _dt = _input_dt;
496 :
497 168134 : Real dt_cur = _dt;
498 168134 : std::ostringstream diag;
499 :
500 : // After startup steps, compute new dt
501 168134 : if (_t_step > _n_startup_steps)
502 168038 : dt_cur = getDT();
503 :
504 : else
505 : {
506 : diag << "Timestep < n_startup_steps, using old dt: " << std::setw(9) << std::setprecision(6)
507 96 : << std::setfill('0') << std::showpoint << std::left << _dt << " tstep: " << _t_step
508 96 : << " n_startup_steps: " << _n_startup_steps << std::endl;
509 : }
510 168134 : _unconstrained_dt = dt_cur;
511 :
512 168134 : if (_verbose)
513 5258 : _console << diag.str();
514 :
515 168134 : diag.str("");
516 168134 : diag.clear();
517 :
518 : // Allow the time stepper to limit the time step
519 168134 : _at_sync_point = _time_stepper->constrainStep(dt_cur);
520 :
521 : // Don't let time go beyond next time interval output if specified
522 168130 : if ((_time_interval) && (_time + dt_cur + _timestep_tolerance >= _next_interval_output_time))
523 : {
524 0 : dt_cur = _next_interval_output_time - _time;
525 0 : _at_sync_point = true;
526 :
527 : diag << "Limiting dt for time interval output at time: " << std::setw(9) << std::setprecision(6)
528 0 : << std::setfill('0') << std::showpoint << std::left << _next_interval_output_time
529 0 : << " dt: " << std::setw(9) << std::setprecision(6) << std::setfill('0') << std::showpoint
530 0 : << std::left << dt_cur << std::endl;
531 : }
532 :
533 : // If a target time is set and the current dt would exceed it, limit dt to match the target
534 173786 : if (_target_time > -std::numeric_limits<Real>::max() + _timestep_tolerance &&
535 5656 : _time + dt_cur + _timestep_tolerance >= _target_time)
536 : {
537 1542 : dt_cur = _target_time - _time;
538 1542 : _at_sync_point = true;
539 :
540 : diag << "Limiting dt for target time: " << std::setw(9) << std::setprecision(6)
541 1542 : << std::setfill('0') << std::showpoint << std::left << _next_interval_output_time
542 1542 : << " dt: " << std::setw(9) << std::setprecision(6) << std::setfill('0') << std::showpoint
543 1542 : << std::left << dt_cur << std::endl;
544 : }
545 :
546 : // Constrain by what the multi apps are doing
547 168130 : constrainDTFromMultiApp(dt_cur, diag, EXEC_MULTIAPP_FIXED_POINT_BEGIN);
548 168130 : constrainDTFromMultiApp(dt_cur, diag, EXEC_TIMESTEP_BEGIN);
549 168130 : constrainDTFromMultiApp(dt_cur, diag, EXEC_TIMESTEP_END);
550 168130 : constrainDTFromMultiApp(dt_cur, diag, EXEC_MULTIAPP_FIXED_POINT_END);
551 :
552 168130 : if (_verbose)
553 5258 : _console << diag.str();
554 :
555 168130 : return dt_cur;
556 168130 : }
557 :
558 : void
559 672520 : TransientBase::constrainDTFromMultiApp(Real & dt_cur,
560 : std::ostringstream & diag,
561 : const ExecFlagType & execute_on) const
562 : {
563 672520 : Real multi_app_dt = _problem.computeMultiAppsDT(execute_on);
564 672520 : if (_use_multiapp_dt || multi_app_dt < dt_cur)
565 : {
566 1896 : dt_cur = multi_app_dt;
567 1896 : _at_sync_point = false;
568 1896 : diag << "Limiting dt for MultiApps on " << execute_on.name() << ": " << std::setw(9)
569 1896 : << std::setprecision(6) << std::setfill('0') << std::showpoint << std::left << dt_cur
570 1896 : << std::endl;
571 : }
572 672520 : }
573 :
574 : Real
575 217955 : TransientBase::getDT()
576 : {
577 217955 : return _time_stepper->getCurrentDT();
578 : }
579 :
580 : bool
581 182263 : TransientBase::keepGoing()
582 : {
583 182263 : bool keep_going = !_problem.isSolveTerminationRequested();
584 :
585 : // Check for stop condition based upon steady-state check flag:
586 182263 : if (lastSolveConverged())
587 : {
588 178094 : if (!_xfem_repeat_step)
589 : {
590 178094 : if (_steady_state_detection == true && _time > _steady_state_start_time)
591 : {
592 : // Check solution difference relative norm against steady-state tolerance
593 12074 : if (convergedToSteadyState())
594 : {
595 305 : _console << "Steady-State Solution Achieved at time: " << _time << std::endl;
596 : // Output last solve if not output previously by forcing it
597 305 : keep_going = false;
598 : }
599 : else // keep going
600 : {
601 : // Print steady-state relative error norm
602 11769 : _console << "Steady-State Relative Differential Norm: " << _solution_change_norm
603 11769 : << std::endl;
604 : }
605 : }
606 :
607 : // Check for stop condition based upon number of simulation steps and/or solution end time:
608 178094 : if (static_cast<unsigned int>(_t_step) >= _num_steps)
609 15597 : keep_going = false;
610 :
611 178094 : if ((_time >= _end_time) || (fabs(_time - _end_time) <= _timestep_tolerance))
612 3858 : keep_going = false;
613 : }
614 : }
615 4169 : else if (_abort)
616 : {
617 20 : _console << "Aborting as solve did not converge and input selected to abort" << std::endl;
618 20 : keep_going = false;
619 : }
620 4149 : else if (!_error_on_dtmin && _dt <= _dtmin)
621 : {
622 21 : _console << "Aborting as timestep already at or below dtmin" << std::endl;
623 21 : keep_going = false;
624 : }
625 :
626 182263 : return keep_going;
627 : }
628 :
629 : void
630 0 : TransientBase::estimateTimeError()
631 : {
632 0 : }
633 :
634 : bool
635 1128196 : TransientBase::lastSolveConverged() const
636 : {
637 1128196 : return _last_solve_converged;
638 : }
639 :
640 : void
641 26393 : TransientBase::postExecute()
642 : {
643 26393 : _time_stepper->postExecute();
644 26393 : }
645 :
646 : void
647 1572 : TransientBase::setTargetTime(Real target_time)
648 : {
649 1572 : _target_time = target_time;
650 1572 : }
651 :
652 : Real
653 5637 : TransientBase::getSolutionChangeNorm()
654 : {
655 5637 : return _solution_change_norm;
656 : }
657 :
658 : void
659 28403 : TransientBase::setupTimeIntegrator()
660 : {
661 28403 : if (_pars.isParamSetByUser("scheme") && _problem.hasTimeIntegrator())
662 4 : mooseError("You cannot specify time_scheme in the Executioner and independently add a "
663 : "TimeIntegrator to the system at the same time");
664 :
665 28399 : if (!_problem.hasTimeIntegrator())
666 : {
667 : // backwards compatibility
668 27331 : std::string ti_str;
669 : using namespace Moose;
670 :
671 27331 : switch (_time_scheme)
672 : {
673 27017 : case TI_IMPLICIT_EULER:
674 27017 : ti_str = "ImplicitEuler";
675 27017 : break;
676 72 : case TI_EXPLICIT_EULER:
677 72 : ti_str = "ExplicitEuler";
678 72 : break;
679 45 : case TI_CRANK_NICOLSON:
680 45 : ti_str = "CrankNicolson";
681 45 : break;
682 161 : case TI_BDF2:
683 161 : ti_str = "BDF2";
684 161 : break;
685 0 : case TI_EXPLICIT_MIDPOINT:
686 0 : ti_str = "ExplicitMidpoint";
687 0 : break;
688 0 : case TI_LSTABLE_DIRK2:
689 0 : ti_str = "LStableDirk2";
690 0 : break;
691 0 : case TI_EXPLICIT_TVD_RK_2:
692 0 : ti_str = "ExplicitTVDRK2";
693 0 : break;
694 36 : case TI_NEWMARK_BETA:
695 36 : ti_str = "NewmarkBeta";
696 36 : break;
697 0 : default:
698 0 : mooseError("Unknown scheme: ", _time_scheme);
699 : break;
700 : }
701 :
702 54662 : InputParameters params = _app.getFactory().getValidParams(ti_str);
703 27331 : _problem.addTimeIntegrator(ti_str, ti_str, params);
704 27331 : }
705 28399 : }
706 :
707 : std::string
708 23388 : TransientBase::getTimeStepperName() const
709 : {
710 23388 : if (_time_stepper)
711 : {
712 23388 : TimeStepper & ts = *_time_stepper;
713 23388 : return demangle(typeid(ts).name());
714 : }
715 : else
716 0 : return std::string();
717 : }
718 :
719 : std::vector<std::string>
720 23388 : TransientBase::getTimeIntegratorNames() const
721 : {
722 23388 : const auto & tis = getTimeIntegrators();
723 23388 : if (tis.empty())
724 0 : mooseError("Time integrator has not been built yet so we can't retrieve its name");
725 :
726 23388 : std::vector<std::string> ret;
727 46857 : for (const auto & ti : tis)
728 : {
729 23469 : const auto & sys = ti->getCheckedPointerParam<SystemBase *>("_sys")->system();
730 23469 : const auto & uvars = ti->getParam<std::vector<VariableName>>("variables");
731 :
732 23469 : std::vector<VariableName> vars;
733 23583 : for (const auto & var : uvars)
734 114 : if (sys.has_variable(var))
735 114 : vars.push_back(var);
736 :
737 23469 : if (!uvars.empty() && vars.empty())
738 0 : continue;
739 :
740 23469 : if (tis.size() > 1)
741 : {
742 162 : const std::string sys_prefix = _problem.numSolverSystems() > 1 ? sys.name() : "";
743 162 : const std::string var_prefix = MooseUtils::join(vars, ", ");
744 162 : const bool both = !sys_prefix.empty() && !var_prefix.empty();
745 162 : ret.push_back("[" + sys_prefix + (both ? " (" : "") + var_prefix + (both ? ")" : "") + "]:");
746 162 : }
747 :
748 23469 : ret.push_back(ti->type());
749 23469 : }
750 46776 : return ret;
751 23388 : }
752 :
753 : void
754 28291 : TransientBase::setTimeStepper(TimeStepper & ts)
755 : {
756 : mooseAssert(!_time_stepper, "Already set");
757 28291 : _time_stepper = &ts;
758 28291 : }
759 :
760 : bool
761 12074 : TransientBase::convergedToSteadyState() const
762 : {
763 : bool converged;
764 :
765 12074 : if (_check_aux)
766 : {
767 : // Get the relative change in the norm of each auxvariable
768 507 : std::vector<Number> aux_soln_change_norms;
769 507 : _aux.variableWiseRelativeSolutionDifferenceNorm(aux_soln_change_norms);
770 :
771 507 : converged = true;
772 531 : for (auto & norm_diff : aux_soln_change_norms)
773 : {
774 : // Normalize by timestep
775 519 : norm_diff /= (_normalize_solution_diff_norm_by_dt ? _dt : Real(1));
776 519 : if (norm_diff >= _steady_state_tolerance)
777 : {
778 495 : converged = false;
779 : // No point in checking the rest of the auxvariables
780 495 : break;
781 : }
782 : }
783 :
784 : // This line is useful since _solution_change_norm will be printed
785 507 : _solution_change_norm =
786 507 : *std::max_element(aux_soln_change_norms.begin(), aux_soln_change_norms.end());
787 507 : }
788 :
789 : // If not using _check_aux, use relative change in norm from nonlinear system
790 11567 : else if (_solution_change_norm < _steady_state_tolerance)
791 293 : converged = true;
792 : else
793 11274 : converged = false;
794 :
795 12074 : return converged;
796 : }
797 :
798 : void
799 72 : TransientBase::parentOutputPositionChanged()
800 : {
801 72 : _fe_problem.parentOutputPositionChanged();
802 72 : }
|