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 by 1% 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\f$
34  * remains finite. The user can select the desired relative
35  * change in the solution by choosing a range for \f$\eta_n\f$
36  * \f[
37  * \eta_{min} < \eta_n < \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,
123  Status & /* integratorStatus */) override
124  {
125  using Teuchos::RCP;
126  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
127  RCP<SolutionStateMetaData<Scalar> > metaData = workingState->getMetaData();
128  const Scalar errorAbs = metaData->getErrorAbs();
129  const Scalar errorRel = metaData->getErrorRel();
130  const int iStep = metaData->getIStep();
131  int order = metaData->getOrder();
132  Scalar dt = metaData->getDt();
133  bool printChanges = solutionHistory->getVerbLevel() !=
134  Teuchos::as<int>(Teuchos::VERB_NONE);
135 
136  RCP<Teuchos::FancyOStream> out = tsc.getOStream();
137  Teuchos::OSTab ostab(out,0,"getNextTimeStep");
138 
139  auto changeDT = [] (int istep, Scalar dt_old, Scalar dt_new,
140  std::string reason)
141  {
142  std::stringstream message;
143  message << std::scientific
144  <<std::setw(6)<<std::setprecision(3)<<istep
145  << " * (dt = "<<std::setw(9)<<std::setprecision(3)<<dt_old
146  << ", new = "<<std::setw(9)<<std::setprecision(3)<<dt_new
147  << ") " << reason << std::endl;
148  return message.str();
149  };
150 
151  Scalar rho = getAmplFactor();
152  Scalar sigma = getReductFactor();
153  Scalar eta = computeEta(tsc, solutionHistory);
154 
155  // General rule: only increase/decrease dt once for any given reason.
156  if (workingState->getSolutionStatus() == Status::FAILED) {
157  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
158  "Stepper failure - Decreasing dt.");
159  dt *= sigma;
160  }
161  else { //Stepper passed
162  if (eta < getMinEta()) { // increase dt
163  if (printChanges) *out << changeDT(iStep, dt, dt*rho,
164  "Monitoring Value (eta) is too small ("
165  + std::to_string(eta) + " < " + std::to_string(getMinEta())
166  + "). Increasing dt.");
167  dt *= rho;
168  }
169  else if (eta > getMaxEta()) { // reduce dt
170  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
171  "Monitoring Value (eta) is too large ("
172  + std::to_string(eta) + " > " + std::to_string(getMaxEta())
173  + "). Decreasing dt.");
174  dt *= sigma;
175  }
176  else if (errorAbs > tsc.getMaxAbsError()) { // reduce dt
177  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
178  "Absolute error is too large ("
179  + std::to_string(errorAbs)+" > "+std::to_string(tsc.getMaxAbsError())
180  + "). Decreasing dt.");
181  dt *= sigma;
182  }
183  else if (errorRel > tsc.getMaxRelError()) { // reduce dt
184  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
185  "Relative error is too large ("
186  + std::to_string(errorRel)+" > "+std::to_string(tsc.getMaxRelError())
187  + "). Decreasing dt.");
188  dt *= sigma;
189  }
190  else if (order < tsc.getMinOrder()) { // order too low, increase dt
191  if (printChanges) *out << changeDT(iStep, dt, dt*rho,
192  "Order is too small ("
193  + std::to_string(order) + " < " + std::to_string(tsc.getMinOrder())
194  + "). Increasing dt.");
195  dt *= rho;
196  }
197  else if (order > tsc.getMaxOrder()) { // order too high, reduce dt
198  if (printChanges) *out << changeDT(iStep, dt, dt*sigma,
199  "Order is too large ("
200  + std::to_string(order) + " > " + std::to_string(tsc.getMaxOrder())
201  + "). Decreasing dt.");
202  dt *= sigma;
203  }
204  }
205 
206  if (dt < tsc.getMinTimeStep()) { // decreased below minimum dt
207  if (printChanges) *out << changeDT(iStep, dt, tsc.getMinTimeStep(),
208  "dt is too small. Resetting to minimum dt.");
209  dt = tsc.getMinTimeStep();
210  }
211  if (dt > tsc.getMaxTimeStep()) { // increased above maximum dt
212  if (printChanges) *out << changeDT(iStep, dt, tsc.getMaxTimeStep(),
213  "dt is too large. Resetting to maximum dt.");
214  dt = tsc.getMaxTimeStep();
215  }
216 
217  metaData->setOrder(order);
218  metaData->setDt(dt);
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 
289  const Teuchos::RCP<SolutionHistory<Scalar> > & solutionHistory)
290  {
291  using Teuchos::RCP;
292  Scalar eta;
293  const double eps = 1.0e4*std::numeric_limits<double>::epsilon();
294  RCP<Teuchos::FancyOStream> out = tsc.getOStream();
295  int numStates = solutionHistory->getNumStates();
296  //Compute eta
297  if (numStates < 3) {
298  eta = getMinEta();
299  return eta;
300  }
301  RCP<const Thyra::VectorBase<Scalar> > xOld = (*solutionHistory)[numStates-3]->getX();
302  RCP<const Thyra::VectorBase<Scalar> > x = (*solutionHistory)[numStates-1]->getX();
303  //IKT: uncomment the following to get some debug output
304  //#define VERBOSE_DEBUG_OUTPUT
305 #ifdef VERBOSE_DEBUG_OUTPUT
306  Teuchos::Range1D range;
307  *out << "\n*** xOld ***\n";
308  RTOpPack::ConstSubVectorView<Scalar> xOldv;
309  xOld->acquireDetachedView(range, &xOldv);
310  auto xoa = xOldv.values();
311  for (auto i = 0; i < xoa.size(); ++i) *out << xoa[i] << " ";
312  *out << "\n*** xOld ***\n";
313  *out << "\n*** x ***\n";
314  RTOpPack::ConstSubVectorView<Scalar> xv;
315  x->acquireDetachedView(range, &xv);
316  auto xa = xv.values();
317  for (auto i = 0; i < xa.size(); ++i) *out << xa[i] << " ";
318  *out << "\n*** x ***\n";
319 #endif
320  //xDiff = x - xOld
321  RCP<Thyra::VectorBase<Scalar> > xDiff = Thyra::createMember(x->space());
322  Thyra::V_VmV(xDiff.ptr(), *x, *xOld);
323  Scalar xDiffNorm = Thyra::norm(*xDiff);
324  Scalar xOldNorm = Thyra::norm(*xOld);
325  //eta = ||x^(n+1)-x^n||/(||x^n||+eps)
326  eta = xDiffNorm/(xOldNorm + eps);
327 #ifdef VERBOSE_DEBUG_OUTPUT
328  *out << "IKT xDiffNorm, xOldNorm, eta = " << xDiffNorm << ", " << xOldNorm
329  << ", " << eta << "\n";
330 #endif
331  return eta;
332  }
333 
334 private:
335  Teuchos::RCP<Teuchos::ParameterList> tscsPL_;
336 };
337 } // namespace Tempus
338 #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.