www.mooseframework.org
IterationAdaptiveDT.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "IterationAdaptiveDT.h"
12 #include "Function.h"
13 #include "PiecewiseBase.h"
14 #include "Transient.h"
15 #include "NonlinearSystem.h"
16 
18 
19 template <>
22 {
24  params.addClassDescription("Adjust the timestep based on the number of iterations");
25  params.addParam<int>("optimal_iterations",
26  "The target number of nonlinear iterations for adaptive timestepping");
27  params.addParam<int>("iteration_window",
28  "Attempt to grow/shrink timestep if the iteration count "
29  "is below/above 'optimal_iterations plus/minus "
30  "iteration_window' (default = optimal_iterations/5).");
31  params.addParam<unsigned>("linear_iteration_ratio",
32  "The ratio of linear to nonlinear iterations "
33  "to determine target linear iterations and "
34  "window for adaptive timestepping (default = "
35  "25)");
36  params.addDeprecatedParam<PostprocessorName>("postprocessor_dtlim",
37  "If specified, the postprocessor value "
38  "is used as an upper limit for the "
39  "current time step length",
40  "Use 'timestep_limiting_postprocessor' instead");
41  params.addParam<PostprocessorName>("timestep_limiting_postprocessor",
42  "If specified, the postprocessor value "
43  "is used as an upper limit for the "
44  "current time step length");
45  params.addParam<FunctionName>("timestep_limiting_function",
46  "A 'PiecewiseBase' type function used to control the timestep by "
47  "limiting the change in the function over a timestep");
48  params.addParam<Real>(
49  "max_function_change",
50  "The absolute value of the maximum change in timestep_limiting_function over a timestep");
51  params.addParam<bool>("force_step_every_function_point",
52  false,
53  "Forces the timestepper to take "
54  "a step that is consistent with "
55  "points defined in the function");
56  params.addRequiredParam<Real>("dt", "The default timestep size between solves");
57  params.addParam<std::vector<Real>>("time_t", "The values of t");
58  params.addParam<std::vector<Real>>("time_dt", "The values of dt");
59  params.addParam<Real>("growth_factor",
60  2.0,
61  "Factor to apply to timestep if easy convergence (if "
62  "'optimal_iterations' is specified) or if recovering "
63  "from failed solve");
64  params.addParam<Real>("cutback_factor",
65  0.5,
66  "Factor to apply to timestep if difficult "
67  "convergence (if 'optimal_iterations' is specified) "
68  "or if solution failed");
69 
70  params.addParam<bool>("reject_large_step",
71  false,
72  "If 'true', time steps that are too large compared to the "
73  "ideal time step will be rejected and repeated");
74  params.addRangeCheckedParam<Real>("reject_large_step_threshold",
75  0.1,
76  "reject_large_step_threshold > 0 "
77  "& reject_large_step_threshold < 1",
78  "Ratio between the the ideal time step size and the "
79  "current time step size below which a time step will "
80  "be rejected if 'reject_large_step' is 'true'");
81 
82  params.declareControllable("growth_factor cutback_factor");
83 
84  return params;
85 }
86 
88  : TimeStepper(parameters),
90  _dt_old(declareRestartableData<Real>("dt_old", 0.0)),
91  _input_dt(getParam<Real>("dt")),
92  _tfunc_last_step(declareRestartableData<bool>("tfunc_last_step", false)),
93  _sync_last_step(declareRestartableData<bool>("sync_last_step", false)),
94  _linear_iteration_ratio(isParamValid("linear_iteration_ratio")
95  ? getParam<unsigned>("linear_iteration_ratio")
96  : 25), // Default to 25
97  _adaptive_timestepping(false),
98  _pps_value(isParamValid("timestep_limiting_postprocessor")
99  ? &getPostprocessorValue("timestep_limiting_postprocessor")
100  : isParamValid("postprocessor_dtlim")
101  ? &getPostprocessorValue("postprocessor_dtlim")
102  : nullptr),
103  _timestep_limiting_function(nullptr),
104  _piecewise_timestep_limiting_function(nullptr),
105  _times(0),
106  _max_function_change(-1),
107  _force_step_every_function_point(getParam<bool>("force_step_every_function_point")),
108  _tfunc_times(getParam<std::vector<Real>>("time_t").begin(),
109  getParam<std::vector<Real>>("time_t").end()),
110  _time_ipol(getParam<std::vector<Real>>("time_t"), getParam<std::vector<Real>>("time_dt")),
111  _use_time_ipol(_time_ipol.getSampleSize() > 0),
112  _growth_factor(getParam<Real>("growth_factor")),
113  _cutback_factor(getParam<Real>("cutback_factor")),
114  _nl_its(declareRestartableData<unsigned int>("nl_its", 0)),
115  _l_its(declareRestartableData<unsigned int>("l_its", 0)),
116  _cutback_occurred(declareRestartableData<bool>("cutback_occurred", false)),
117  _at_function_point(false),
118  _reject_large_step(getParam<bool>("reject_large_step")),
119  _large_step_rejection_threshold(getParam<Real>("reject_large_step_threshold"))
120 {
121  if (isParamValid("optimal_iterations"))
122  {
123  _adaptive_timestepping = true;
124  _optimal_iterations = getParam<int>("optimal_iterations");
125 
126  if (isParamValid("iteration_window"))
127  _iteration_window = getParam<int>("iteration_window");
128  else
130  }
131  else
132  {
133  if (isParamValid("iteration_window"))
134  mooseError("'optimal_iterations' must be used for 'iteration_window' to be used");
135  if (isParamValid("linear_iteration_ratio"))
136  mooseError("'optimal_iterations' must be used for 'linear_iteration_ratio' to be used");
137  }
138 
139  if (isParamValid("timestep_limiting_function"))
141  isParamValid("max_function_change") ? getParam<Real>("max_function_change") : -1;
142  else
143  {
144  if (isParamValid("max_function_change"))
145  mooseError("'timestep_limiting_function' must be used for 'max_function_change' to be used");
147  mooseError("'timestep_limiting_function' must be used for 'force_step_every_function_point' "
148  "to be used");
149  }
150 }
151 
152 void
154 {
155  if (isParamValid("timestep_limiting_function"))
156  {
158  &_fe_problem.getFunction(getParam<FunctionName>("timestep_limiting_function"),
159  isParamValid("_tid") ? getParam<THREAD_ID>("_tid") : 0);
162 
164  {
165  unsigned int time_size = _piecewise_timestep_limiting_function->functionSize();
166  _times.resize(time_size);
167 
168  for (unsigned int i = 0; i < time_size; ++i)
170  }
171  else
172  mooseError("timestep_limiting_function must be a PiecewiseBase function");
173  }
174 }
175 
176 void
178 {
180 
181  // Delete all tfunc times that are at or before the begin time
182  while (!_tfunc_times.empty() && _time + _timestep_tolerance >= *_tfunc_times.begin())
183  _tfunc_times.erase(_tfunc_times.begin());
184 }
185 
186 Real
188 {
189  return _input_dt;
190 }
191 
192 Real
194 {
195  Real dt = _dt_old;
196 
197  if (_cutback_occurred)
198  {
199  _cutback_occurred = false;
201  {
202  // Don't allow it to grow this step, but shrink if needed
203  bool allowToGrow = false;
204  computeAdaptiveDT(dt, allowToGrow);
205  }
206  }
207  else if (_tfunc_last_step)
208  {
209  _tfunc_last_step = false;
210  _sync_last_step = false;
212 
213  if (_verbose)
214  {
215  _console << "Setting dt to value specified by dt function: " << std::setw(9) << dt << '\n';
216  }
217  }
218  else if (_sync_last_step)
219  {
220  _sync_last_step = false;
221  dt = _dt_old;
222 
223  if (_verbose)
224  {
225  _console << "Setting dt to value used before sync: " << std::setw(9) << dt << '\n';
226  }
227  }
228  else if (_adaptive_timestepping)
229  computeAdaptiveDT(dt);
230  else if (_use_time_ipol)
231  dt = computeInterpolationDT();
232  else
233  {
234  dt *= _growth_factor;
235  if (dt > _dt_old * _growth_factor)
236  dt = _dt_old * _growth_factor;
237  }
238 
239  return dt;
240 }
241 
242 bool
244 {
245  bool at_sync_point = TimeStepper::constrainStep(dt);
246 
247  // Limit the timestep to postprocessor value
249 
250  // Limit the timestep to limit change in the function
251  limitDTByFunction(dt);
252 
253  // Adjust to the next tfunc time if needed
254  if (!_tfunc_times.empty() && _time + dt + _timestep_tolerance >= *_tfunc_times.begin())
255  {
256  dt = *_tfunc_times.begin() - _time;
257 
258  if (_verbose)
259  {
260  _console << "Limiting dt to sync with dt function time: " << std::setw(9)
261  << *_tfunc_times.begin() << " dt: " << std::setw(9) << dt << '\n';
262  }
263  }
264 
265  return at_sync_point;
266 }
267 
268 Real
270 {
271  _cutback_occurred = true;
272 
273  // Can't cut back any more
274  if (_dt <= _dt_min)
275  mooseError("Solve failed and timestep already at dtmin, cannot continue!");
276 
277  if (_verbose)
278  {
279  _console << "\nSolve failed with dt: " << std::setw(9) << _dt
280  << "\nRetrying with reduced dt: " << std::setw(9) << _dt * _cutback_factor << '\n';
281  }
282  else
283  _console << "\nSolve failed, cutting timestep.\n";
284 
285  return _dt * _cutback_factor;
286 }
287 
288 bool
290 {
291  if (!_reject_large_step)
292  return TimeStepper::converged();
293 
294  // the solver has not converged
295  if (!TimeStepper::converged())
296  return false;
297 
298  // we are already at dt_min or at the start of the simulation
299  // in which case we can move on to the next step
300  if (_dt == _dt_min || _t_step < 2)
301  return true;
302 
303  // we get what the next time step should be
304  Real dt_test = _dt;
306 
307  // we cannot constrain the time step any further
308  if (dt_test == 0)
309  return true;
310 
311  // if the time step is much smaller than the current time step
312  // we need to repeat the current iteration with a smaller time step
313  if (dt_test < _dt * _large_step_rejection_threshold)
314  return false;
315 
316  // otherwise we move one
317  return true;
318 }
319 
320 void
322 {
323  if (_pps_value && _t_step > 1)
324  {
325  if (limitedDT > *_pps_value)
326  {
327  limitedDT = std::max(_dt_min, *_pps_value);
328 
329  if (_verbose)
330  _console << "Limiting dt to postprocessor value. dt = " << limitedDT << '\n';
331  }
332  }
333 }
334 
335 void
337 {
338  Real orig_dt = limitedDT;
339 
341  {
342  Point dummyPoint;
343  Real oldValue = _timestep_limiting_function->value(_time_old, dummyPoint);
344  Real newValue = _timestep_limiting_function->value(_time_old + limitedDT, dummyPoint);
345  Real change = std::abs(newValue - oldValue);
346 
347  if (_max_function_change > 0.0 && change > _max_function_change)
348  {
349  do
350  {
351  limitedDT /= 2.0;
352  newValue = _timestep_limiting_function->value(_time_old + limitedDT, dummyPoint);
353  change = std::abs(newValue - oldValue);
354  } while (change > _max_function_change);
355  }
356  }
357 
358  _at_function_point = false;
360  {
361  for (unsigned int i = 0; i + 1 < _times.size(); ++i)
362  {
363  if (_time >= _times[i] && _time < _times[i + 1])
364  {
365  if (limitedDT > _times[i + 1] - _time - _timestep_tolerance)
366  {
367  limitedDT = _times[i + 1] - _time;
368  _at_function_point = true;
369  }
370  break;
371  }
372  }
373  }
374 
375  if (_verbose && limitedDT != orig_dt)
376  {
377  if (_at_function_point)
378  _console << "Limiting dt to match function point. dt = ";
379  else
380  _console << "Limiting dt to limit change in function. dt = ";
381 
382  _console << limitedDT << '\n';
383  }
384 }
385 
386 void
387 IterationAdaptiveDT::computeAdaptiveDT(Real & dt, bool allowToGrow, bool allowToShrink)
388 {
389  const unsigned int growth_nl_its(
391  const unsigned int shrink_nl_its(_optimal_iterations + _iteration_window);
392  const unsigned int growth_l_its(_optimal_iterations > _iteration_window
395  : 0);
396  const unsigned int shrink_l_its(_linear_iteration_ratio *
398 
399  if (allowToGrow && (_nl_its < growth_nl_its && _l_its < growth_l_its))
400  {
401  // Grow the timestep
402  dt *= _growth_factor;
403 
404  if (_verbose)
405  {
406  _console << "Growing dt: nl its = " << _nl_its << " < " << growth_nl_its
407  << " && lin its = " << _l_its << " < " << growth_l_its << " old dt: " << std::setw(9)
408  << _dt_old << " new dt: " << std::setw(9) << dt << '\n';
409  }
410  }
411  else if (allowToShrink && (_nl_its > shrink_nl_its || _l_its > shrink_l_its))
412  {
413  // Shrink the timestep
414  dt *= _cutback_factor;
415 
416  if (_verbose)
417  {
418  _console << "Shrinking dt: nl its = " << _nl_its << " > " << shrink_nl_its
419  << " || lin its = " << _l_its << " > " << shrink_l_its << " old dt: " << std::setw(9)
420  << _dt_old << " new dt: " << std::setw(9) << dt << '\n';
421  }
422  }
423 }
424 
425 Real
427 {
428  Real dt = _time_ipol.sample(_time_old);
429 
430  if (dt > _dt_old * _growth_factor)
431  {
432  dt = _dt_old * _growth_factor;
433 
434  if (_verbose)
435  {
436  _console << "Growing dt to recover from cutback. "
437  << " old dt: " << std::setw(9) << _dt_old << " new dt: " << std::setw(9) << dt
438  << '\n';
439  }
440  }
441 
442  return dt;
443 }
444 
445 void
447 {
449 }
450 
451 void
453 {
455 
456  while (!_tfunc_times.empty() && _time + _timestep_tolerance >= *_tfunc_times.begin())
457  {
458  if (std::abs(_time - *_tfunc_times.begin()) <= _timestep_tolerance)
459  _tfunc_last_step = true;
460 
461  _tfunc_times.erase(_tfunc_times.begin());
462  }
463 
466 
469  {
471  _sync_last_step = true;
472 
473  if (_verbose)
474  {
475  _console << "Sync point hit in current step, using previous dt for old dt: " << std::setw(9)
476  << _dt_old << '\n';
477  }
478  }
479  else
480  _dt_old = _dt;
481 }
Real & _timestep_tolerance
Definition: TimeStepper.h:133
unsigned int nLinearIterations() const
Return the number of linear iterations.
virtual Real value(Real t, const Point &p)
Override this to evaluate the scalar function at point (t,x,y,z), by default this returns zero...
Definition: Function.C:38
bool atSyncPoint()
Is the current step at a sync point (sync times, time interval, target time, etc)?
Definition: Transient.h:184
Function base which provides a piecewise approximation to a provided (x,y) point data set...
Definition: PiecewiseBase.h:26
virtual Real & dtOld() const
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
NonlinearSystemBase & getNonlinearSystemBase()
const Real & _cutback_factor
cut the timestep by by this factor
unsigned int & _nl_its
Number of nonlinear iterations in previous solve.
T sample(const T &x) const
This function will take an independent variable input and will return the dependent variable based on...
Real & _time_old
Definition: TimeStepper.h:125
virtual Real computeDT() override
Called to compute _current_dt for a normal step.
Adjust the timestep based on the number of iterations.
Base class for time stepping.
Definition: TimeStepper.h:26
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Real _input_dt
The dt from the input file.
virtual Real computeInitialDT() override
Called to compute _current_dt for the first timestep.
Transient & _executioner
Reference to transient executioner.
Definition: TimeStepper.h:121
IterationAdaptiveDT(const InputParameters &parameters)
virtual bool constrainStep(Real &dt)
Called after computeStep() is called.
Definition: TimeStepper.C:90
bool _reject_large_step
Indicates whether we need to reject a time step much larger than its ideal size.
void limitDTByFunction(Real &limitedDT)
virtual Real domain(const int i)
Definition: PiecewiseBase.C:70
void mooseError(Args &&... args) const
Definition: MooseObject.h:147
virtual bool constrainStep(Real &dt) override
Called after computeStep() is called.
virtual bool converged() const
If the time step converged.
Definition: TimeStepper.C:176
const Real & _growth_factor
grow the timestep by this factor
int _optimal_iterations
Adapt the timestep to maintain this non-linear iteration count...
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
virtual Real functionSize()
Definition: PiecewiseBase.C:64
virtual Real computeFailedDT() override
Called to compute _current_dt after a solve has failed.
FEProblemBase & _fe_problem
Definition: TimeStepper.h:119
Real unconstrainedDT()
Get the unconstrained dt.
Definition: Transient.h:190
const bool _use_time_ipol
true if we want to use piecewise-defined time stepping
unsigned int & _l_its
Number of linear iterations in previous solve.
virtual void preExecute() override
virtual Function & getFunction(const std::string &name, THREAD_ID tid=0)
Function * _timestep_limiting_function
virtual void acceptStep()
This gets called when time step is accepted.
Definition: TimeStepper.C:160
LinearInterpolation _time_ipol
PiecewiseBase linear definition of time stepping.
const PostprocessorValue * _pps_value
if specified, the postprocessor value is an upper limit for the time step length
virtual void rejectStep() override
This gets called when time step is rejected.
std::set< Real > _tfunc_times
bool _adaptive_timestepping
adaptive timestepping is active if the optimal_iterations input parameter is specified ...
void limitDTToPostprocessorValue(Real &limitedDT) const
PiecewiseBase * _piecewise_timestep_limiting_function
virtual bool converged() const override
If the time step converged.
virtual void init() override
Initialize the time stepper.
void computeAdaptiveDT(Real &dt, bool allowToGrow=true, bool allowToShrink=true)
unsigned int nNonlinearIterations() const
Return the number of non-linear iterations.
const int _linear_iteration_ratio
use _optimal_iterations and _iteration_window multiplied with this factor for linear iterations ...
InputParameters validParams< TimeStepper >()
Definition: TimeStepper.C:17
bool _force_step_every_function_point
insert sync points at the time nodes of the _piecewise_timestep_limiting_function ...
std::vector< Real > _times
time point defined in the piecewise function
registerMooseObject("MooseApp", IterationAdaptiveDT)
int _iteration_window
...plus/minus this value.
virtual void preExecute()
Definition: TimeStepper.C:61
virtual void rejectStep()
This gets called when time step is rejected.
Definition: TimeStepper.C:170
Real & _dt_min
Definition: TimeStepper.h:128
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
int & _t_step
Definition: TimeStepper.h:126
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
double _large_step_rejection_threshold
Threshold used to detect whether we need to reject a step.
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseObject.h:89
bool & _verbose
should detailed diagnostic output be printed
Definition: TimeStepper.h:136
Real & _dt
Definition: TimeStepper.h:127
void declareControllable(const std::string &name, std::set< ExecFlagType > execute_flags={})
Declare the given parameters as controllable.
InputParameters validParams< IterationAdaptiveDT >()
Real & _time
Values from executioner.
Definition: TimeStepper.h:124
Interface class for classes which interact with Postprocessors.
virtual void acceptStep() override
This gets called when time step is accepted.