Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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
virtual Scalar getMaxRelError() const
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.
virtual Scalar getMaxAbsError() const
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 getMaxTimeStep() const
virtual Scalar getMinTimeStep() const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList() override
StepControlStrategy class for TimeStepControl.