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_SolutionStateMetaData.hpp"
16 #include "Tempus_SolutionHistory.hpp"
17 #include "Tempus_StepperState.hpp"
18 
19 //Thyra
20 #include "Thyra_VectorStdOps.hpp"
21 
22 namespace Tempus {
23 
24 /** \brief StepControlStrategy class for TimeStepControl
25  *
26  * This TimeStepControlStrategy primarily tries to maintain a
27  * certain level of change in the solution ill-respective of the
28  * error involved, e.g., the solution should change between 1% and
29  * 3% (\f$\eta_{min}=0.01\f$ and \f$\eta_{max}=0.03\f$) every
30  * time step. The relative solution change is measured by
31  * \f[
32  * \eta_{n-1} = \frac{|| x_{n-1} - x_{n-2} ||}{ || x_{n-2} || + \epsilon }
33  * \f]
34  * where \f$\epsilon\f$ is a small constant to ensure that \f$\eta_{n-1}\f$
35  * remains finite. The user can select the desired relative
36  * change in the solution by choosing a range for \f$\eta_{n-1}\f$
37  * \f[
38  * \eta_{min} < \eta_{n-1} < \eta_{max}
39  * \f]
40  * If the solution change is outside this range, an amplification
41  * (\f$\rho\f$) or reduction factor (\f$\sigma\f$) is applied to
42  * the timestep to bring the solution change back into the desired
43  * range. This can be written as
44  * \f[
45  * \Delta t_n = \left\{
46  * \begin{array}{rll}
47  * \sigma \Delta t_{n-1} & \mbox{if $\eta_{n-1} > \eta_{max}$}
48  * & \mbox{where $0 < \sigma < 1$} \\
49  * \rho \Delta t_{n-1} & \mbox{else if $\eta_{n-1} < \eta_{min}$}
50  * & \mbox{where $\rho > 1$} \\
51  * \Delta t_{n-1} &
52  * \mbox{else if $\eta_{min}<\eta_{n-1}<\eta_{max}$} \\
53  * \end{array}
54  * \right.
55  * \f]
56  * In the full implementation, several other mechanisms can amplify
57  * or reduce the timestep.
58  * - Stepper fails
59  * - Maximum Absolute error, \f$e_{abs}^{max}\f$
60  * - Maximum Relative error, \f$e_{rel}^{max}\f$
61  * - Order, \f$p\f$
62  * \f[
63  * \Delta t_n = \left\{
64  * \begin{array}{rll}
65  * \sigma \Delta t_{n-1} & \mbox{if Stepper fails}
66  * & \mbox{where $0 < \sigma < 1$} \\
67  * \rho \Delta t_{n-1} & \mbox{else if $\eta_{n-1} < \eta_{min}$}
68  * & \mbox{where $\rho > 1$} \\
69  * \sigma \Delta t_{n-1} & \mbox{else if $\eta_{n-1} > \eta_{max}$}
70  * & \mbox{where $0 < \sigma < 1$} \\
71  * \sigma \Delta t_{n-1} & \mbox{else if $e_{abs} > e_{abs}^{max}$}
72  * & \mbox{where $0 < \sigma < 1$} \\
73  * \sigma \Delta t_{n-1} & \mbox{else if $e_{rel} > e_{rel}^{max}$}
74  * & \mbox{where $0 < \sigma < 1$} \\
75  * \rho \Delta t_{n-1} & \mbox{else if $p < p_{min}$}
76  * & \mbox{where $\rho > 1$} \\
77  * \sigma \Delta t_{n-1} & \mbox{else if $p > p_{max}$}
78  * & \mbox{where $0 < \sigma < 1$} \\
79  * \Delta t_{n-1} & \mbox{else} & \\
80  * \end{array}
81  * \right.
82  * \f]
83  *
84  * Note
85  * - Only one amplification or reduction is applied each timestep.
86  * - The priority is specified by the order of list.
87  * - The timestep, \f$\Delta t_n\f$, is still constrained to the
88  * maximum and minimum timestep size.
89  * \f$\Delta t_{min} < \Delta t_n < \Delta t_{max}\f$
90  * - If \f$ \eta_{min} < \eta_n < \eta_{max}\f$, the timestep
91  * is unchanged, i.e., constant timestep size.
92  * - To have constant timesteps, set \f$\eta_{min}=0\f$ and
93  * \f$\eta_{max}=10^{16}\f$. These are the defaults.
94  * - From (Denner, 2014), amplification factor, \f$\rho\f$, is
95  * required to be less than 1.91 for stability (\f$\rho < 1.91\f$).
96  * - Denner (2014) suggests that \f$\eta_{min} = 0.1*\eta_{max}\f$
97  * and the numerical tests confirm this for their problems.
98  *
99  * #### References
100  * Section 2.2.1 / Algorithm 2.4 of A. Denner, "Experiments on
101  * Temporal Variable Step BDF2 Algorithms", Masters Thesis,
102  * U Wisconsin-Madison, 2014.
103  *
104  */
105 template<class Scalar>
107  : virtual public TimeStepControlStrategy<Scalar>
108 {
109 public:
110 
111  /// Constructor
113  Teuchos::RCP<Teuchos::ParameterList> pList = Teuchos::null){
114  this->setParameterList(pList);
115  }
116 
117  /// Destructor
119 
120  /** \brief Determine the time step size.*/
121  virtual void getNextTimeStep(
122  const TimeStepControl<Scalar> tsc,
124  Status & /* integratorStatus */) override
125  {
126  using Teuchos::RCP;
127  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
128  RCP<SolutionStateMetaData<Scalar> > metaData = workingState->getMetaData();
129  const Scalar errorAbs = metaData->getErrorAbs();
130  const Scalar errorRel = metaData->getErrorRel();
131  const int iStep = metaData->getIStep();
132  int order = metaData->getOrder();
133  Scalar dt = metaData->getDt();
134  bool printChanges = solutionHistory->getVerbLevel() !=
135  Teuchos::as<int>(Teuchos::VERB_NONE);
136 
137  RCP<Teuchos::FancyOStream> out = tsc.getOStream();
138  Teuchos::OSTab ostab(out,0,"getNextTimeStep");
139 
140  auto changeDT = [] (int istep, Scalar dt_old, Scalar dt_new,
141  std::string reason)
142  {
143  std::stringstream message;
144  message << std::scientific
145  <<std::setw(6)<<std::setprecision(3)<<istep
146  << " * (dt = "<<std::setw(9)<<std::setprecision(3)<<dt_old
147  << ", new = "<<std::setw(9)<<std::setprecision(3)<<dt_new
148  << ") " << reason << std::endl;
149  return message.str();
150  };
151 
152  Scalar rho = getAmplFactor();
153  Scalar sigma = getReductFactor();
154  Scalar eta = computeEta(tsc, solutionHistory);
155  //*out << " eta = " << eta << "\n";
156 
157  // General rule: only increase/decrease dt once for any given reason.
158  if (workingState->getSolutionStatus() == Status::FAILED) {
159  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
160  "Stepper failure - Decreasing dt.");
161  dt *= sigma;
162  }
163  else { //Stepper passed
164  if (eta < getMinEta()) { // increase dt
165  if (printChanges) *out << changeDT(iStep, dt, dt*rho,
166  "Monitoring Value (eta) is too small ("
167  + std::to_string(eta) + " < " + std::to_string(getMinEta())
168  + "). Increasing dt.");
169  dt *= rho;
170  }
171  else if (eta > getMaxEta()) { // reduce dt
172  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
173  "Monitoring Value (eta) is too large ("
174  + std::to_string(eta) + " > " + std::to_string(getMaxEta())
175  + "). Decreasing dt.");
176  dt *= sigma;
177  }
178  else if (errorAbs > tsc.getMaxAbsError()) { // reduce dt
179  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
180  "Absolute error is too large ("
181  + std::to_string(errorAbs)+" > "+std::to_string(tsc.getMaxAbsError())
182  + "). Decreasing dt.");
183  dt *= sigma;
184  }
185  else if (errorRel > tsc.getMaxRelError()) { // reduce dt
186  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
187  "Relative error is too large ("
188  + std::to_string(errorRel)+" > "+std::to_string(tsc.getMaxRelError())
189  + "). Decreasing dt.");
190  dt *= sigma;
191  }
192  else if (order < tsc.getMinOrder()) { // order too low, increase dt
193  if (printChanges) *out << changeDT(iStep, dt, dt*rho,
194  "Order is too small ("
195  + std::to_string(order) + " < " + std::to_string(tsc.getMinOrder())
196  + "). Increasing dt.");
197  dt *= rho;
198  }
199  else if (order > tsc.getMaxOrder()) { // order too high, reduce dt
200  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
201  "Order is too large ("
202  + std::to_string(order) + " > " + std::to_string(tsc.getMaxOrder())
203  + "). Decreasing dt.");
204  dt *= sigma;
205  }
206  }
207 
208  if (dt < tsc.getMinTimeStep()) { // decreased below minimum dt
209  if (printChanges) *out << changeDT(iStep, dt, tsc.getMinTimeStep(),
210  "dt is too small. Resetting to minimum dt.");
211  dt = tsc.getMinTimeStep();
212  }
213  if (dt > tsc.getMaxTimeStep()) { // increased above maximum dt
214  if (printChanges) *out << changeDT(iStep, dt, tsc.getMaxTimeStep(),
215  "dt is too large. Resetting to maximum dt.");
216  dt = tsc.getMaxTimeStep();
217  }
218 
219  metaData->setOrder(order);
220  metaData->setDt(dt);
221  }
222 
223  /// \name Overridden from Teuchos::ParameterListAcceptor
224  //@{
226  const Teuchos::RCP<Teuchos::ParameterList> & pList) override
227  {
228  if (pList == Teuchos::null) {
229  // Create default parameters if null, otherwise keep current parameters.
230  if (tscsPL_ == Teuchos::null) {
231  tscsPL_ = Teuchos::parameterList("TimeStepControlStrategyBasicVS");
232  *tscsPL_= *(this->getValidParameters());
233  }
234  } else {
235  tscsPL_ = pList;
236  }
237  tscsPL_->validateParametersAndSetDefaults(*this->getValidParameters());
238 
239  TEUCHOS_TEST_FOR_EXCEPTION(getAmplFactor() <= 1.0, std::out_of_range,
240  "Error - Invalid value of Amplification Factor = " << getAmplFactor()
241  << "! \n" << "Amplification Factor must be > 1.0.\n");
242 
243  TEUCHOS_TEST_FOR_EXCEPTION(getReductFactor() >= 1.0, std::out_of_range,
244  "Error - Invalid value of Reduction Factor = " << getReductFactor()
245  << "! \n" << "Reduction Factor must be < 1.0.\n");
246 
247  TEUCHOS_TEST_FOR_EXCEPTION(getMinEta() > getMaxEta(), std::out_of_range,
248  "Error - Invalid values of 'Minimum Value Monitoring Function' = "
249  << getMinEta() << "\n and 'Maximum Value Monitoring Function' = "
250  << getMaxEta() <<"! \n Mininum Value cannot be > Maximum Value! \n");
251 
252  }
253 
254  Teuchos::RCP<const Teuchos::ParameterList>
255  getValidParameters() const override {
256  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
257 
258  // From (Denner, 2014), amplification factor can be at most 1.91 for
259  // stability.
260  pl->set<double>("Amplification Factor", 1.75, "Amplification factor");
261  pl->set<double>("Reduction Factor" , 0.5 , "Reduction factor");
262  // From (Denner, 2014), it seems a reasonable choice for eta_min is
263  // 0.1*eta_max. Numerical tests confirm this.
264  pl->set<double>("Minimum Value Monitoring Function", 0.0 , "Min value eta");
265  pl->set<double>("Maximum Value Monitoring Function", 1.0e-16, "Max value eta");
266  pl->set<std::string>("Name", "Basic VS");
267  return pl;
268  }
269 
270  Teuchos::RCP<Teuchos::ParameterList> getNonconstParameterList() override {
271  return tscsPL_;
272  }
273 
274  Teuchos::RCP<Teuchos::ParameterList> unsetParameterList() override {
275  Teuchos::RCP<Teuchos::ParameterList> temp_plist = tscsPL_;
276  tscsPL_ = Teuchos::null;
277  return(temp_plist);
278  }
279  //@}
280 
281  virtual Scalar getAmplFactor() const
282  { return tscsPL_->get<double>("Amplification Factor"); }
283  virtual Scalar getReductFactor() const
284  { return tscsPL_->get<double>("Reduction Factor");}
285  virtual Scalar getMinEta() const
286  { return tscsPL_->get<double>("Minimum Value Monitoring Function"); }
287  virtual Scalar getMaxEta() const
288  { return tscsPL_->get<double>("Maximum Value Monitoring Function"); }
289 
290  virtual void setAmplFactor(Scalar rho)
291  { tscsPL_->set<double>("Amplification Factor", rho); }
292  virtual void setReductFactor(Scalar sigma)
293  { tscsPL_->set<double>("Reduction Factor", sigma); }
294  virtual void setMinEta(Scalar minEta)
295  { tscsPL_->set<double>("Minimum Value Monitoring Function", minEta); }
296  virtual void setMaxEta(Scalar maxEta)
297  { tscsPL_->set<double>("Maximum Value Monitoring Function", maxEta); }
298 
300  const Teuchos::RCP<SolutionHistory<Scalar> > & solutionHistory)
301  {
302  using Teuchos::RCP;
303  Scalar eta;
304  const double eps = 1.0e4*std::numeric_limits<double>::epsilon();
305  RCP<Teuchos::FancyOStream> out = tsc.getOStream();
306  int numStates = solutionHistory->getNumStates();
307  //Compute eta
308  if (numStates < 3) {
309  eta = getMinEta();
310  return eta;
311  }
312  RCP<const Thyra::VectorBase<Scalar> > xOld =
313  solutionHistory->getStateTimeIndexNM2()->getX();
314  RCP<const Thyra::VectorBase<Scalar> > x =
315  solutionHistory->getStateTimeIndexNM1()->getX();
316  //IKT: uncomment the following to get some debug output
317  //#define VERBOSE_DEBUG_OUTPUT
318 #ifdef VERBOSE_DEBUG_OUTPUT
319  Teuchos::Range1D range;
320  *out << "\n*** xOld ***\n";
321  RTOpPack::ConstSubVectorView<Scalar> xOldv;
322  xOld->acquireDetachedView(range, &xOldv);
323  auto xoa = xOldv.values();
324  for (auto i = 0; i < xoa.size(); ++i) *out << xoa[i] << " ";
325  *out << "\n*** xOld ***\n";
326  *out << "\n*** x ***\n";
327  RTOpPack::ConstSubVectorView<Scalar> xv;
328  x->acquireDetachedView(range, &xv);
329  auto xa = xv.values();
330  for (auto i = 0; i < xa.size(); ++i) *out << xa[i] << " ";
331  *out << "\n*** x ***\n";
332 #endif
333  //xDiff = x - xOld
334  RCP<Thyra::VectorBase<Scalar> > xDiff = Thyra::createMember(x->space());
335  Thyra::V_VmV(xDiff.ptr(), *x, *xOld);
336  Scalar xDiffNorm = Thyra::norm(*xDiff);
337  Scalar xOldNorm = Thyra::norm(*xOld);
338  //eta = ||x^(n+1)-x^n||/(||x^n||+eps)
339  eta = xDiffNorm/(xOldNorm + eps);
340 #ifdef VERBOSE_DEBUG_OUTPUT
341  Scalar xNorm = Thyra::norm(*x);
342  *out << "IKT xDiffNorm, xNorm, xOldNorm, eta = " << xDiffNorm << ", "
343  << xNorm << ", " << xOldNorm << ", " << eta << "\n";
344 #endif
345  return eta;
346  }
347 
348 private:
349  Teuchos::RCP<Teuchos::ParameterList> tscsPL_;
350 };
351 } // namespace Tempus
352 #endif // Tempus_TimeStepControlStrategy_BasicVS_hpp
Scalar computeEta(const TimeStepControl< Scalar > tsc, const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
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...
Teuchos::RCP< SolutionHistory< Scalar > > solutionHistory(Teuchos::RCP< Teuchos::ParameterList > pList=Teuchos::null)
Nonmember constructor.
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.