Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Tempus_StepperExplicitRK_impl.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_StepperExplicitRK_impl_hpp
10 #define Tempus_StepperExplicitRK_impl_hpp
11 
13 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
14 #include "Thyra_VectorStdOps.hpp"
15 
16 
17 namespace Tempus {
18 
19 
20 template<class Scalar>
22 {
23  this->setUseFSAL( this->getUseFSALDefault());
24  this->setICConsistency( this->getICConsistencyDefault());
25  this->setICConsistencyCheck( this->getICConsistencyCheckDefault());
26  this->setUseEmbedded( this->getUseEmbeddedDefault());
27 
28  this->stepperObserver_ =
29  Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
30 }
31 
32 
33 template<class Scalar>
35  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
36  const Teuchos::RCP<StepperRKObserverComposite<Scalar> >& obs,
37  bool useFSAL,
38  std::string ICConsistency,
39  bool ICConsistencyCheck,
40  bool useEmbedded)
41 {
42  this->setUseFSAL( useFSAL);
43  this->setICConsistency( ICConsistency);
44  this->setICConsistencyCheck( ICConsistencyCheck);
45  this->setUseEmbedded( useEmbedded);
46 
47  this->stepperObserver_ =
48  Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
49  this->setObserver(obs);
50 
51  if (appModel != Teuchos::null) {
52  this->setModel(appModel);
53  this->initialize();
54  }
55 }
56 
57 
58 template<class Scalar>
60  const Teuchos::RCP<SolutionHistory<Scalar> >& sh) const
61 {
62 
63  Scalar dt = Scalar(1.0e+99);
64  if (!this->getUseEmbedded()) return dt;
65 
66  Teuchos::RCP<SolutionState<Scalar> > currentState=sh->getCurrentState();
67  Teuchos::RCP<SolutionStateMetaData<Scalar> > metaData = currentState->getMetaData();
68  const int order = metaData->getOrder();
69  const Scalar time = metaData->getTime();
70  const Scalar errorAbs = metaData->getTolRel();
71  const Scalar errorRel = metaData->getTolAbs();
72 
73  Teuchos::RCP<Thyra::VectorBase<Scalar> > stageX, scratchX;
74  stageX = Thyra::createMember(this->appModel_->get_f_space());
75  scratchX = Thyra::createMember(this->appModel_->get_f_space());
76  Thyra::assign(stageX.ptr(), *(currentState->getX()));
77 
78  std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar> > > stageXDot(2);
79  for (int i=0; i<2; ++i) {
80  stageXDot[i] = Thyra::createMember(this->appModel_->get_f_space());
81  assign(stageXDot[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
82  }
83 
84  // A: one function evaluation at F(t_0, X_0)
85  typedef Thyra::ModelEvaluatorBase MEB;
86  MEB::InArgs<Scalar> inArgs = this->appModel_->getNominalValues();
87  MEB::OutArgs<Scalar> outArgs = this->appModel_->createOutArgs();
88  inArgs.set_x(stageX);
89  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time);
90  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
91  outArgs.set_f(stageXDot[0]); // K1
92  this->appModel_->evalModel(inArgs, outArgs);
93 
94  auto err_func = [] (Teuchos::RCP<Thyra::VectorBase<Scalar> > U,
95  const Scalar rtol, const Scalar atol,
96  Teuchos::RCP<Thyra::VectorBase<Scalar> > absU)
97  {
98  // compute err = Norm_{WRMS} with w = Atol + Rtol * | U |
99  Thyra::assign(absU.ptr(), *U);
100  Thyra::abs(*U, absU.ptr()); // absU = | X0 |
101  Thyra::Vt_S(absU.ptr(), rtol); // absU *= Rtol
102  Thyra::Vp_S(absU.ptr(), atol); // absU += Atol
103  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *U, *absU, absU.ptr());
104  Scalar err = Thyra::norm_inf(*absU);
105  return err;
106  };
107 
108  Scalar d0 = err_func(stageX, errorRel, errorAbs, scratchX);
109  Scalar d1 = err_func(stageXDot[0], errorRel, errorAbs, scratchX);
110 
111  // b) first guess for the step size
112  dt = Teuchos::as<Scalar>(0.01)*(d0/d1);
113 
114  // c) perform one explicit Euler step (X_1)
115  Thyra::Vp_StV(stageX.ptr(), dt, *(stageXDot[0]));
116 
117  // compute F(t_0 + dt, X_1)
118  inArgs.set_x(stageX);
119  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time + dt);
120  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
121  outArgs.set_f(stageXDot[1]); // K2
122  this->appModel_->evalModel(inArgs, outArgs);
123 
124  // d) compute estimate of the second derivative of the solution
125  // d2 = || f(t_0 + dt, X_1) - f(t_0, X_0) || / dt
126  Teuchos::RCP<Thyra::VectorBase<Scalar> > errX;
127  errX = Thyra::createMember(this->appModel_->get_f_space());
128  assign(errX.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
129  Thyra::V_VmV(errX.ptr(), *(stageXDot[1]), *(stageXDot[0]));
130  Scalar d2 = err_func(errX, errorRel, errorAbs, scratchX) / dt;
131 
132  // e) compute step size h_1 (from m = 0 order Taylor series)
133  Scalar max_d1_d2 = std::max(d1, d2);
134  Scalar h1 = std::pow((0.01/max_d1_d2),(1.0/(order+1)));
135 
136  // f) propose starting step size
137  dt = std::min(100*dt, h1);
138  return dt;
139 }
140 
141 
142 template<class Scalar>
144  Teuchos::RCP<Teuchos::ParameterList> pl) const
145 {
146  getValidParametersBasic(pl, this->getStepperType());
147  pl->set<bool>("Use Embedded", false,
148  "'Whether to use Embedded Stepper (if available) or not\n"
149  " 'true' - Stepper will compute embedded solution and is adaptive.\n"
150  " 'false' - Stepper is not embedded(adaptive).\n");
151  pl->set<std::string>("Description", this->getDescription());
152 }
153 
154 
155 template<class Scalar>
157  Teuchos::RCP<StepperObserver<Scalar> > obs)
158 {
159 
160  if (this->stepperObserver_ == Teuchos::null)
161  this->stepperObserver_ =
162  Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
163 
164  if (( obs == Teuchos::null ) and (this->stepperObserver_->getSize() >0 ) )
165  return;
166 
167  if (( obs == Teuchos::null ) and (this->stepperObserver_->getSize() == 0) )
168  obs = Teuchos::rcp(new StepperRKObserver<Scalar>());
169 
170  // Check that this casts to prevent a runtime error if it doesn't
171  if (Teuchos::rcp_dynamic_cast<StepperRKObserver<Scalar> > (obs) != Teuchos::null) {
172  this->stepperObserver_->addObserver(
173  Teuchos::rcp_dynamic_cast<StepperRKObserver<Scalar> > (obs, true) );
174  } else {
175  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
176  Teuchos::OSTab ostab(out,0,"setObserver");
177  *out << "Tempus::StepperExplicit_RK::setObserver: Warning: An observer has been provided that";
178  *out << " does not support Tempus::StepperRKObserver. This observer WILL NOT be added.";
179  *out << " In the future, this will result in a runtime error!" << std::endl;
180  }
181 
182 }
183 
184 
185 template<class Scalar>
187 {
188  TEUCHOS_TEST_FOR_EXCEPTION( tableau_ == Teuchos::null, std::logic_error,
189  "Error - Need to set the tableau, before calling "
190  "StepperExplicitRK::initialize()\n");
191 
192  TEUCHOS_TEST_FOR_EXCEPTION( this->appModel_==Teuchos::null, std::logic_error,
193  "Error - Need to set the model, setModel(), before calling "
194  "StepperExplicitRK::initialize()\n");
195 
196  this->setObserver();
197 
198  TEUCHOS_TEST_FOR_EXCEPTION( this->stepperObserver_->getSize() < 1
199  , std::logic_error,
200  "Error - Composite Observer is empty!\n");
201 
202  // Initialize the stage vectors
203  int numStages = tableau_->numStages();
204  stageX_ = Thyra::createMember(this->appModel_->get_f_space());
205  stageXDot_.resize(numStages);
206  for (int i=0; i<numStages; ++i) {
207  stageXDot_[i] = Thyra::createMember(this->appModel_->get_f_space());
208  assign(stageXDot_[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
209  }
210 
211  if ( tableau_->isEmbedded() and this->getUseEmbedded() ){
212  ee_ = Thyra::createMember(this->appModel_->get_f_space());
213  abs_u0 = Thyra::createMember(this->appModel_->get_f_space());
214  abs_u = Thyra::createMember(this->appModel_->get_f_space());
215  sc = Thyra::createMember(this->appModel_->get_f_space());
216  }
217 }
218 
219 
220 template<class Scalar>
222  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
223 {
224  using Teuchos::RCP;
225 
226  RCP<SolutionState<Scalar> > initialState = solutionHistory->getCurrentState();
227 
228  // Check if we need Stepper storage for xDot
229  if (initialState->getXDot() == Teuchos::null)
230  this->setStepperXDot(stageXDot_.back());
231 
233 }
234 
235 
236 template<class Scalar>
238  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
239 {
240  using Teuchos::RCP;
241 
242  TEMPUS_FUNC_TIME_MONITOR("Tempus::StepperExplicitRK::takeStep()");
243  {
244  TEUCHOS_TEST_FOR_EXCEPTION(solutionHistory->getNumStates() < 2,
245  std::logic_error,
246  "Error - StepperExplicitRK<Scalar>::takeStep(...)\n"
247  "Need at least two SolutionStates for ExplicitRK.\n"
248  " Number of States = " << solutionHistory->getNumStates() << "\n"
249  "Try setting in \"Solution History\" \"Storage Type\" = \"Undo\"\n"
250  " or \"Storage Type\" = \"Static\" and \"Storage Limit\" = \"2\"\n");
251 
252  this->stepperObserver_->observeBeginTakeStep(solutionHistory, *this);
253  RCP<SolutionState<Scalar> > currentState=solutionHistory->getCurrentState();
254  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
255  const Scalar dt = workingState->getTimeStep();
256  const Scalar time = currentState->getTime();
257 
258  const int numStages = tableau_->numStages();
259  Teuchos::SerialDenseMatrix<int,Scalar> A = tableau_->A();
260  Teuchos::SerialDenseVector<int,Scalar> b = tableau_->b();
261  Teuchos::SerialDenseVector<int,Scalar> c = tableau_->c();
262 
263  // Compute stage solutions
264  for (int i=0; i < numStages; ++i) {
265  this->stepperObserver_->observeBeginStage(solutionHistory, *this);
266 
267  // ???: is it a good idea to leave this (no-op) here?
268  this->stepperObserver_
269  ->observeBeforeImplicitExplicitly(solutionHistory, *this);
270 
271  // ???: is it a good idea to leave this (no-op) here?
272  this->stepperObserver_->observeBeforeSolve(solutionHistory, *this);
273 
274  if ( i == 0 && this->getUseFSAL() &&
275  workingState->getNConsecutiveFailures() == 0 ) {
276 
277  RCP<Thyra::VectorBase<Scalar> > tmp = stageXDot_[0];
278  stageXDot_[0] = stageXDot_.back();
279  stageXDot_.back() = tmp;
280 
281  } else {
282 
283  Thyra::assign(stageX_.ptr(), *(currentState->getX()));
284  for (int j=0; j < i; ++j) {
285  if (A(i,j) != Teuchos::ScalarTraits<Scalar>::zero()) {
286  Thyra::Vp_StV(stageX_.ptr(), dt*A(i,j), *stageXDot_[j]);
287  }
288  }
289  const Scalar ts = time + c(i)*dt;
290 
291  // ???: is it a good idea to leave this (no-op) here?
292  this->stepperObserver_->observeAfterSolve(solutionHistory, *this);
293 
294  this->stepperObserver_->observeBeforeExplicit(solutionHistory, *this);
295  auto p = Teuchos::rcp(new ExplicitODEParameters<Scalar>(dt));
296 
297  // Evaluate xDot = f(x,t).
298  this->evaluateExplicitODE(stageXDot_[i], stageX_, ts, p);
299  }
300 
301  this->stepperObserver_->observeEndStage(solutionHistory, *this);
302  }
303 
304  // Sum for solution: x_n = x_n-1 + Sum{ b(i) * dt*f(i) }
305  Thyra::assign((workingState->getX()).ptr(), *(currentState->getX()));
306  for (int i=0; i < numStages; ++i) {
307  if (b(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
308  Thyra::Vp_StV((workingState->getX()).ptr(), dt*b(i), *(stageXDot_[i]));
309  }
310  }
311 
312 
313  // At this point, the stepper has passed.
314  // But when using adaptive time stepping, the embedded method
315  // can change the step status
316  workingState->setSolutionStatus(Status::PASSED);
317 
318  if (tableau_->isEmbedded() and this->getUseEmbedded()) {
319 
320  RCP<SolutionStateMetaData<Scalar> > metaData=workingState->getMetaData();
321  const Scalar tolAbs = metaData->getTolRel();
322  const Scalar tolRel = metaData->getTolAbs();
323 
324  // just compute the error weight vector
325  // (all that is needed is the error, and not the embedded solution)
326  Teuchos::SerialDenseVector<int,Scalar> errWght = b ;
327  errWght -= tableau_->bstar();
328 
329  //compute local truncation error estimate: | u^{n+1} - \hat{u}^{n+1} |
330  // Sum for solution: ee_n = Sum{ (b(i) - bstar(i)) * dt*f(i) }
331  assign(ee_.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
332  for (int i=0; i < numStages; ++i) {
333  if (errWght(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
334  Thyra::Vp_StV(ee_.ptr(), dt*errWght(i), *(stageXDot_[i]));
335  }
336  }
337 
338  // compute: Atol + max(|u^n|, |u^{n+1}| ) * Rtol
339  Thyra::abs( *(currentState->getX()), abs_u0.ptr());
340  Thyra::abs( *(workingState->getX()), abs_u.ptr());
341  Thyra::pair_wise_max_update(tolRel, *abs_u0, abs_u.ptr());
342  Thyra::add_scalar(tolAbs, abs_u.ptr());
343 
344  //compute: || ee / sc ||
345  assign(sc.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
346  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *ee_, *abs_u, sc.ptr());
347  Scalar err = std::abs(Thyra::norm_inf(*sc));
348  metaData->setErrorRel(err);
349 
350  // test if step should be rejected
351  if (std::isinf(err) || std::isnan(err) || err > Teuchos::as<Scalar>(1.0))
352  workingState->setSolutionStatus(Status::FAILED);
353  }
354 
355  workingState->setOrder(this->getOrder());
356  this->stepperObserver_->observeEndTakeStep(solutionHistory, *this);
357  }
358  return;
359 }
360 
361 
362 /** \brief Provide a StepperState to the SolutionState.
363  * This Stepper does not have any special state data,
364  * so just provide the base class StepperState with the
365  * Stepper description. This can be checked to ensure
366  * that the input StepperState can be used by this Stepper.
367  */
368 template<class Scalar>
369 Teuchos::RCP<Tempus::StepperState<Scalar> > StepperExplicitRK<Scalar>::
371 {
372  Teuchos::RCP<Tempus::StepperState<Scalar> > stepperState =
373  rcp(new StepperState<Scalar>(this->getStepperType()));
374  return stepperState;
375 }
376 
377 
378 template<class Scalar>
380  Teuchos::FancyOStream &out,
381  const Teuchos::EVerbosityLevel /* verbLevel */) const
382 {
383  out << this->getStepperType() << "::describe:" << std::endl
384  << "appModel_ = " << this->appModel_->description() << std::endl;
385 }
386 
387 
388 template<class Scalar>
389 Teuchos::RCP<const Teuchos::ParameterList>
391 {
392  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
393  this->getValidParametersBasicERK(pl);
394  return pl;
395 }
396 
397 
398 } // namespace Tempus
399 #endif // Tempus_StepperExplicitRK_impl_hpp
virtual void setupDefault()
Default setup for constructor.
virtual Scalar getInitTimeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory) const
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
virtual void setup(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &appModel, const Teuchos::RCP< StepperRKObserverComposite< Scalar > > &obs, bool useFSAL, std::string ICConsistency, bool ICConsistencyCheck, bool useEmbedded)
Setup for constructor.
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions and make them consistent.
StepperState is a simple class to hold state information about the stepper.
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
virtual void setObserver(Teuchos::RCP< StepperObserver< Scalar > > obs=Teuchos::null)
Set Observer.
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions, make them consistent, and set needed memory.
StepperObserver class for Stepper class.
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...
void getValidParametersBasicERK(Teuchos::RCP< Teuchos::ParameterList > pl) const
virtual void takeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Take the specified timestep, dt, and return true if successful.
virtual void initialize()
Initialize during construction and after changing input parameters.
StepperRKObserver class for StepperRK.
virtual Teuchos::RCP< Tempus::StepperState< Scalar > > getDefaultStepperState()
Get a default (initial) StepperState.
void getValidParametersBasic(Teuchos::RCP< Teuchos::ParameterList > pl, std::string stepperType)
Provide basic parameters to Steppers.