Tempus  Version of the Day
Time Integration
Tempus_TimeStepControlStrategyBasicVS.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ****************************************************************************
3 // Tempus: Copyright (2017) Sandia Corporation
4 //
5 // Distributed under BSD 3-clause license (See accompanying file Copyright.txt)
6 // ****************************************************************************
7 // @HEADER
8 
9 #ifndef Tempus_TimeStepControlStrategy_BasicVS_hpp
10 #define Tempus_TimeStepControlStrategy_BasicVS_hpp
11 
12 #include "Tempus_TimeStepControl.hpp"
14 #include "Tempus_SolutionState.hpp"
15 #include "Tempus_SolutionHistory.hpp"
16 #include "Tempus_StepperState.hpp"
17 
18 //Thyra
19 #include "Thyra_VectorStdOps.hpp"
20 
21 namespace Tempus {
22 
23 /** \brief StepControlStrategy class for TimeStepControl
24  *
25  * This TimeStepControlStrategy primarily tries to maintain a
26  * certain level of change in the solution ill-respective of the
27  * error involved, e.g., the solution should change between 1% and
28  * 3% (\f$\eta_{min}=0.01\f$ and \f$\eta_{max}=0.03\f$) every
29  * time step. The relative solution change is measured by
30  * \f[
31  * \eta_{n-1} = \frac{|| x_{n-1} - x_{n-2} ||}{ || x_{n-2} || + \epsilon }
32  * \f]
33  * where \f$\epsilon\f$ is a small constant to ensure that \f$\eta_{n-1}\f$
34  * remains finite. The user can select the desired relative
35  * change in the solution by choosing a range for \f$\eta_{n-1}\f$
36  * \f[
37  * \eta_{min} < \eta_{n-1} < \eta_{max}
38  * \f]
39  * If the solution change is outside this range, an amplification
40  * (\f$\rho\f$) or reduction factor (\f$\sigma\f$) is applied to
41  * the timestep to bring the solution change back into the desired
42  * range. This can be written as
43  * \f[
44  * \Delta t_n = \left\{
45  * \begin{array}{rll}
46  * \sigma \Delta t_{n-1} & \mbox{if $\eta_{n-1} > \eta_{max}$}
47  * & \mbox{where $0 < \sigma < 1$} \\
48  * \rho \Delta t_{n-1} & \mbox{else if $\eta_{n-1} < \eta_{min}$}
49  * & \mbox{where $\rho > 1$} \\
50  * \Delta t_{n-1} &
51  * \mbox{else if $\eta_{min}<\eta_{n-1}<\eta_{max}$} \\
52  * \end{array}
53  * \right.
54  * \f]
55  * In the full implementation, several other mechanisms can amplify
56  * or reduce the timestep.
57  * - Stepper fails
58  * - Maximum Absolute error, \f$e_{abs}^{max}\f$
59  * - Maximum Relative error, \f$e_{rel}^{max}\f$
60  * - Order, \f$p\f$
61  * \f[
62  * \Delta t_n = \left\{
63  * \begin{array}{rll}
64  * \sigma \Delta t_{n-1} & \mbox{if Stepper fails}
65  * & \mbox{where $0 < \sigma < 1$} \\
66  * \rho \Delta t_{n-1} & \mbox{else if $\eta_{n-1} < \eta_{min}$}
67  * & \mbox{where $\rho > 1$} \\
68  * \sigma \Delta t_{n-1} & \mbox{else if $\eta_{n-1} > \eta_{max}$}
69  * & \mbox{where $0 < \sigma < 1$} \\
70  * \sigma \Delta t_{n-1} & \mbox{else if $e_{abs} > e_{abs}^{max}$}
71  * & \mbox{where $0 < \sigma < 1$} \\
72  * \sigma \Delta t_{n-1} & \mbox{else if $e_{rel} > e_{rel}^{max}$}
73  * & \mbox{where $0 < \sigma < 1$} \\
74  * \rho \Delta t_{n-1} & \mbox{else if $p < p_{min}$}
75  * & \mbox{where $\rho > 1$} \\
76  * \sigma \Delta t_{n-1} & \mbox{else if $p > p_{max}$}
77  * & \mbox{where $0 < \sigma < 1$} \\
78  * \Delta t_{n-1} & \mbox{else} & \\
79  * \end{array}
80  * \right.
81  * \f]
82  *
83  * Note
84  * - Only one amplification or reduction is applied each timestep.
85  * - The priority is specified by the order of list.
86  * - The timestep, \f$\Delta t_n\f$, is still constrained to the
87  * maximum and minimum timestep size.
88  * \f$\Delta t_{min} < \Delta t_n < \Delta t_{max}\f$
89  * - If \f$ \eta_{min} < \eta_n < \eta_{max}\f$, the timestep
90  * is unchanged, i.e., constant timestep size.
91  * - To have constant timesteps, set \f$\eta_{min}=0\f$ and
92  * \f$\eta_{max}=10^{16}\f$. These are the defaults.
93  * - From (Denner, 2014), amplification factor, \f$\rho\f$, is
94  * required to be less than 1.91 for stability (\f$\rho < 1.91\f$).
95  * - Denner (2014) suggests that \f$\eta_{min} = 0.1*\eta_{max}\f$
96  * and the numerical tests confirm this for their problems.
97  *
98  * #### References
99  * Section 2.2.1 / Algorithm 2.4 of A. Denner, "Experiments on
100  * Temporal Variable Step BDF2 Algorithms", Masters Thesis,
101  * U Wisconsin-Madison, 2014.
102  *
103  */
104 template<class Scalar>
106  : virtual public TimeStepControlStrategy<Scalar>
107 {
108 public:
109 
110  /// Constructor
112  Teuchos::RCP<Teuchos::ParameterList> pList = Teuchos::null){
113  this->setParameterList(pList);
114  }
115 
116  /// Destructor
118 
119  /** \brief Determine the time step size.*/
120  virtual void getNextTimeStep(
121  const TimeStepControl<Scalar> tsc,
122  Teuchos::RCP<SolutionHistory<Scalar> > solutionHistory,
123  Status & /* integratorStatus */) override
124  {
125  using Teuchos::RCP;
126  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
127  const Scalar errorAbs = workingState->getErrorAbs();
128  const Scalar errorRel = workingState->getErrorRel();
129  const int iStep = workingState->getIndex();
130  int order = workingState->getOrder();
131  Scalar dt = workingState->getTimeStep();
132  bool printDtChanges = tsc.getPrintDtChanges();
133 
134  RCP<Teuchos::FancyOStream> out = tsc.getOStream();
135  Teuchos::OSTab ostab(out,0,"getNextTimeStep");
136 
137  auto changeDT = [] (int istep, Scalar dt_old, Scalar dt_new,
138  std::string reason)
139  {
140  std::stringstream message;
141  message << std::scientific
142  <<std::setw(6)<<std::setprecision(3)<<istep
143  << " * (dt = "<<std::setw(9)<<std::setprecision(3)<<dt_old
144  << ", new = "<<std::setw(9)<<std::setprecision(3)<<dt_new
145  << ") " << reason << std::endl;
146  return message.str();
147  };
148 
149  Scalar rho = getAmplFactor();
150  Scalar sigma = getReductFactor();
151  Scalar eta = solutionHistory->getCurrentState()->getDxNormL2Rel();
152  if (iStep == 1) eta = getMinEta(); // For first step use initial dt.
153 
154  // General rule: only increase/decrease dt once for any given reason.
155  if (workingState->getSolutionStatus() == Status::FAILED) {
156  if (printDtChanges) *out << changeDT(iStep, dt, dt*sigma,
157  "Stepper failure - Decreasing dt.");
158  dt *= sigma;
159  }
160  else { //Stepper passed
161  if (eta < getMinEta()) { // increase dt
162  if (printDtChanges) *out << changeDT(iStep, dt, dt*rho,
163  "Change too small ("
164  + std::to_string(eta) + " < " + std::to_string(getMinEta())
165  + "). Increasing dt.");
166  dt *= rho;
167  }
168  else if (eta > getMaxEta()) { // reduce dt
169  if (printDtChanges) *out << changeDT(iStep, dt, dt*sigma,
170  "Change too large ("
171  + std::to_string(eta) + " > " + std::to_string(getMaxEta())
172  + "). Decreasing dt.");
173  dt *= sigma;
174  }
175  else if (errorAbs > tsc.getMaxAbsError()) { // reduce dt
176  if (printDtChanges) *out << changeDT(iStep, dt, dt*sigma,
177  "Absolute error is too large ("
178  + std::to_string(errorAbs)+" > "+std::to_string(tsc.getMaxAbsError())
179  + "). Decreasing dt.");
180  dt *= sigma;
181  }
182  else if (errorRel > tsc.getMaxRelError()) { // reduce dt
183  if (printDtChanges) *out << changeDT(iStep, dt, dt*sigma,
184  "Relative error is too large ("
185  + std::to_string(errorRel)+" > "+std::to_string(tsc.getMaxRelError())
186  + "). Decreasing dt.");
187  dt *= sigma;
188  }
189  else if (order < tsc.getMinOrder()) { // order too low, increase dt
190  if (printDtChanges) *out << changeDT(iStep, dt, dt*rho,
191  "Order is too small ("
192  + std::to_string(order) + " < " + std::to_string(tsc.getMinOrder())
193  + "). Increasing dt.");
194  dt *= rho;
195  }
196  else if (order > tsc.getMaxOrder()) { // order too high, reduce dt
197  if (printDtChanges) *out << changeDT(iStep, dt, dt*sigma,
198  "Order is too large ("
199  + std::to_string(order) + " > " + std::to_string(tsc.getMaxOrder())
200  + "). Decreasing dt.");
201  dt *= sigma;
202  }
203  }
204 
205  if (dt < tsc.getMinTimeStep()) { // decreased below minimum dt
206  if (printDtChanges) *out << changeDT(iStep, dt, tsc.getMinTimeStep(),
207  "dt is too small. Resetting to minimum dt.");
208  dt = tsc.getMinTimeStep();
209  }
210  if (dt > tsc.getMaxTimeStep()) { // increased above maximum dt
211  if (printDtChanges) *out << changeDT(iStep, dt, tsc.getMaxTimeStep(),
212  "dt is too large. Resetting to maximum dt.");
213  dt = tsc.getMaxTimeStep();
214  }
215 
216  workingState->setOrder(order);
217  workingState->setTimeStep(dt);
218  workingState->setComputeNorms(true);
219  }
220 
221  /// \name Overridden from Teuchos::ParameterListAcceptor
222  //@{
224  const Teuchos::RCP<Teuchos::ParameterList> & pList) override
225  {
226  if (pList == Teuchos::null) {
227  // Create default parameters if null, otherwise keep current parameters.
228  if (tscsPL_ == Teuchos::null) {
229  tscsPL_ = Teuchos::parameterList("TimeStepControlStrategyBasicVS");
230  *tscsPL_= *(this->getValidParameters());
231  }
232  } else {
233  tscsPL_ = pList;
234  }
235  tscsPL_->validateParametersAndSetDefaults(*this->getValidParameters());
236 
237  TEUCHOS_TEST_FOR_EXCEPTION(getAmplFactor() <= 1.0, std::out_of_range,
238  "Error - Invalid value of Amplification Factor = " << getAmplFactor()
239  << "! \n" << "Amplification Factor must be > 1.0.\n");
240 
241  TEUCHOS_TEST_FOR_EXCEPTION(getReductFactor() >= 1.0, std::out_of_range,
242  "Error - Invalid value of Reduction Factor = " << getReductFactor()
243  << "! \n" << "Reduction Factor must be < 1.0.\n");
244 
245  TEUCHOS_TEST_FOR_EXCEPTION(getMinEta() > getMaxEta(), std::out_of_range,
246  "Error - Invalid values of 'Minimum Value Monitoring Function' = "
247  << getMinEta() << "\n and 'Maximum Value Monitoring Function' = "
248  << getMaxEta() <<"! \n Mininum Value cannot be > Maximum Value! \n");
249 
250  }
251 
252  Teuchos::RCP<const Teuchos::ParameterList>
253  getValidParameters() const override {
254  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
255 
256  // From (Denner, 2014), amplification factor can be at most 1.91 for
257  // stability.
258  pl->set<double>("Amplification Factor", 1.75, "Amplification factor");
259  pl->set<double>("Reduction Factor" , 0.5 , "Reduction factor");
260  // From (Denner, 2014), it seems a reasonable choice for eta_min is
261  // 0.1*eta_max. Numerical tests confirm this.
262  pl->set<double>("Minimum Value Monitoring Function", 0.0 , "Min value eta");
263  pl->set<double>("Maximum Value Monitoring Function", 1.0e-16, "Max value eta");
264  pl->set<std::string>("Name", "Basic VS");
265  return pl;
266  }
267 
268  Teuchos::RCP<Teuchos::ParameterList> getNonconstParameterList() override {
269  return tscsPL_;
270  }
271 
272  Teuchos::RCP<Teuchos::ParameterList> unsetParameterList() override {
273  Teuchos::RCP<Teuchos::ParameterList> temp_plist = tscsPL_;
274  tscsPL_ = Teuchos::null;
275  return(temp_plist);
276  }
277  //@}
278 
279  virtual Scalar getAmplFactor() const
280  { return tscsPL_->get<double>("Amplification Factor"); }
281  virtual Scalar getReductFactor() const
282  { return tscsPL_->get<double>("Reduction Factor");}
283  virtual Scalar getMinEta() const
284  { return tscsPL_->get<double>("Minimum Value Monitoring Function"); }
285  virtual Scalar getMaxEta() const
286  { return tscsPL_->get<double>("Maximum Value Monitoring Function"); }
287 
288  virtual void setAmplFactor(Scalar rho)
289  { tscsPL_->set<double>("Amplification Factor", rho); }
290  virtual void setReductFactor(Scalar sigma)
291  { tscsPL_->set<double>("Reduction Factor", sigma); }
292  virtual void setMinEta(Scalar minEta)
293  { tscsPL_->set<double>("Minimum Value Monitoring Function", minEta); }
294  virtual void setMaxEta(Scalar maxEta)
295  { tscsPL_->set<double>("Maximum Value Monitoring Function", maxEta); }
296 
297 private:
298 
299  Teuchos::RCP<Teuchos::ParameterList> tscsPL_;
300 
301 };
302 
303 
304 } // namespace Tempus
305 #endif // Tempus_TimeStepControlStrategy_BasicVS_hpp
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const override
virtual void getNextTimeStep(const TimeStepControl< Scalar > tsc, Teuchos::RCP< SolutionHistory< Scalar > > solutionHistory, Status &) override
Determine the time step size.
StepControlStrategy class for TimeStepControl.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &pList) override
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList() override
TimeStepControlStrategyBasicVS(Teuchos::RCP< Teuchos::ParameterList > pList=Teuchos::null)
Constructor.
Status
Status for the Integrator, the Stepper and the SolutionState.
TimeStepControl manages the time step size. There several mechanicisms that effect the time step size...
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
virtual Scalar getMinTimeStep() const
virtual Scalar getMaxTimeStep() const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList() override
StepControlStrategy class for TimeStepControl.