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 
12 #include "Tempus_RKButcherTableauBuilder.hpp"
14 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
15 #include "Thyra_VectorStdOps.hpp"
16 
17 
18 namespace Tempus {
19 
20 template<class Scalar>
22 {
23  this->setTableau();
24  this->setParameterList(Teuchos::null);
25  this->modelWarning();
26 }
27 
28 template<class Scalar>
30  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
31  Teuchos::RCP<Teuchos::ParameterList> pList)
32 {
33  this->setTableau(pList);
34  this->setParameterList(pList);
35 
36  if (appModel == Teuchos::null) {
37  this->modelWarning();
38  }
39  else {
40  this->setModel(appModel);
41  this->initialize();
42  }
43 }
44 
45 template<class Scalar>
47  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
48  std::string stepperType)
49 {
50  this->setTableau(stepperType);
51 
52  if (appModel == Teuchos::null) {
53  this->modelWarning();
54  }
55  else {
56  this->setModel(appModel);
57  this->initialize();
58  }
59 }
60 
61 template<class Scalar>
63  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
64  std::string stepperType,
65  Teuchos::RCP<Teuchos::ParameterList> pList)
66 {
67  this->setTableau(stepperType);
68  this->setParameterList(pList);
69 
70  if (appModel == Teuchos::null) {
71  this->modelWarning();
72  }
73  else {
74  this->setModel(appModel);
75  this->initialize();
76  }
77 }
78 
79 template<class Scalar>
81  const Teuchos::RCP<SolutionHistory<Scalar> >& sh) const
82 {
83 
84  Scalar dt = Scalar(1.0e+99);
85  if (!this->stepperPL_->template get<bool>("Use Embedded")) return dt;
86 
87  Teuchos::RCP<SolutionState<Scalar> > currentState=sh->getCurrentState();
88  Teuchos::RCP<SolutionStateMetaData<Scalar> > metaData = currentState->getMetaData();
89  const int order = metaData->getOrder();
90  const Scalar time = metaData->getTime();
91  const Scalar errorAbs = metaData->getTolRel();
92  const Scalar errorRel = metaData->getTolAbs();
93 
94  Teuchos::RCP<Thyra::VectorBase<Scalar> > stageX, scratchX;
95  stageX = Thyra::createMember(this->appModel_->get_f_space());
96  scratchX = Thyra::createMember(this->appModel_->get_f_space());
97  Thyra::assign(stageX.ptr(), *(currentState->getX()));
98 
99  std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar> > > stageXDot(2);
100  for (int i=0; i<2; ++i) {
101  stageXDot[i] = Thyra::createMember(this->appModel_->get_f_space());
102  assign(stageXDot[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
103  }
104 
105  // A: one function evaluation at F(t_0, X_0)
106  typedef Thyra::ModelEvaluatorBase MEB;
107  MEB::InArgs<Scalar> inArgs = this->appModel_->getNominalValues();
108  MEB::OutArgs<Scalar> outArgs = this->appModel_->createOutArgs();
109  inArgs.set_x(stageX);
110  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time);
111  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
112  outArgs.set_f(stageXDot[0]); // K1
113  this->appModel_->evalModel(inArgs, outArgs);
114 
115  auto err_func = [] (Teuchos::RCP<Thyra::VectorBase<Scalar> > U,
116  const Scalar rtol, const Scalar atol,
117  Teuchos::RCP<Thyra::VectorBase<Scalar> > absU)
118  {
119  // compute err = Norm_{WRMS} with w = Atol + Rtol * | U |
120  Thyra::assign(absU.ptr(), *U);
121  Thyra::abs(*U, absU.ptr()); // absU = | X0 |
122  Thyra::Vt_S(absU.ptr(), rtol); // absU *= Rtol
123  Thyra::Vp_S(absU.ptr(), atol); // absU += Atol
124  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *U, *absU, absU.ptr());
125  Scalar err = Thyra::norm_inf(*absU);
126  return err;
127  };
128 
129  Scalar d0 = err_func(stageX, errorRel, errorAbs, scratchX);
130  Scalar d1 = err_func(stageXDot[0], errorRel, errorAbs, scratchX);
131 
132  // b) first guess for the step size
133  dt = Teuchos::as<Scalar>(0.01)*(d0/d1);
134 
135  // c) perform one explicit Euler step (X_1)
136  Thyra::Vp_StV(stageX.ptr(), dt, *(stageXDot[0]));
137 
138  // compute F(t_0 + dt, X_1)
139  inArgs.set_x(stageX);
140  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time + dt);
141  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
142  outArgs.set_f(stageXDot[1]); // K2
143  this->appModel_->evalModel(inArgs, outArgs);
144 
145  // d) compute estimate of the second derivative of the solution
146  // d2 = || f(t_0 + dt, X_1) - f(t_0, X_0) || / dt
147  Teuchos::RCP<Thyra::VectorBase<Scalar> > errX;
148  errX = Thyra::createMember(this->appModel_->get_f_space());
149  assign(errX.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
150  Thyra::V_VmV(errX.ptr(), *(stageXDot[1]), *(stageXDot[0]));
151  Scalar d2 = err_func(errX, errorRel, errorAbs, scratchX) / dt;
152 
153  // e) compute step size h_1 (from m = 0 order Taylor series)
154  Scalar max_d1_d2 = std::max(d1, d2);
155  Scalar h1 = std::pow((0.01/max_d1_d2),(1.0/(order+1)));
156 
157  // f) propse starting step size
158  dt = std::min(100*dt, h1);
159  return dt;
160 }
161 
162 template<class Scalar>
163 void StepperExplicitRK<Scalar>::setTableau(std::string stepperType)
164 {
165  if (stepperType == "") {
166  this->setTableau();
167  } else {
168  Teuchos::RCP<const RKButcherTableau<Scalar> > ERK_ButcherTableau =
169  createRKBT<Scalar>(stepperType, this->stepperPL_);
170  this->setTableau(ERK_ButcherTableau);
171  }
172 }
173 
174 template<class Scalar>
176  Teuchos::RCP<Teuchos::ParameterList> pList)
177 {
178  if (pList == Teuchos::null) {
179  // Create default parameters if null, otherwise keep current parameters.
180  if (this->stepperPL_ == Teuchos::null)
181  this->stepperPL_ = this->getDefaultParameters();
182  } else {
183  this->stepperPL_ = pList;
184  }
185 
186  std::string stepperType =
187  this->stepperPL_->template get<std::string>("Stepper Type",
188  "RK Explicit 4 Stage");
189  Teuchos::RCP<const RKButcherTableau<Scalar> > ERK_ButcherTableau =
190  createRKBT<Scalar>(stepperType, this->stepperPL_);
191  this->setTableau(ERK_ButcherTableau);
192 }
193 
194 template<class Scalar>
196  Teuchos::RCP<const RKButcherTableau<Scalar> > ERK_ButcherTableau)
197 {
198  ERK_ButcherTableau_ = ERK_ButcherTableau;
199 
200  TEUCHOS_TEST_FOR_EXCEPTION(ERK_ButcherTableau_->isImplicit() == true,
201  std::logic_error,
202  "Error - StepperExplicitRK received an implicit Butcher Tableau!\n" <<
203  " Tableau = " << ERK_ButcherTableau_->description() << "\n");
204 
205 }
206 
207 template<class Scalar>
209  Teuchos::RCP<StepperObserver<Scalar> > obs)
210 {
211  if (obs == Teuchos::null) {
212  // Create default observer, otherwise keep current observer.
213  if (this->stepperObserver_ == Teuchos::null) {
214  stepperExplicitRKObserver_ =
215  Teuchos::rcp(new StepperExplicitRKObserver<Scalar>());
216  this->stepperObserver_ =
217  Teuchos::rcp_dynamic_cast<StepperObserver<Scalar> >
218  (stepperExplicitRKObserver_);
219  }
220  } else {
221  this->stepperObserver_ = obs;
222  stepperExplicitRKObserver_ =
223  Teuchos::rcp_dynamic_cast<StepperExplicitRKObserver<Scalar> >
224  (this->stepperObserver_);
225  }
226 }
227 
228 
229 template<class Scalar>
231 {
232  TEUCHOS_TEST_FOR_EXCEPTION( ERK_ButcherTableau_ == Teuchos::null,
233  std::logic_error,
234  "Error - Need to set the Butcher Tableau, setTableau(), before calling "
235  "StepperExplicitRK::initialize()\n");
236 
237  TEUCHOS_TEST_FOR_EXCEPTION( this->appModel_==Teuchos::null, std::logic_error,
238  "Error - Need to set the model, setModel(), before calling "
239  "StepperExplicitRK::initialize()\n");
240 
241  this->setTableau(this->stepperPL_);
242  this->setParameterList(this->stepperPL_);
243  this->setObserver();
244 
245  // Initialize the stage vectors
246  int numStages = ERK_ButcherTableau_->numStages();
247  stageX_ = Thyra::createMember(this->appModel_->get_f_space());
248  stageXDot_.resize(numStages);
249  for (int i=0; i<numStages; ++i) {
250  stageXDot_[i] = Thyra::createMember(this->appModel_->get_f_space());
251  assign(stageXDot_[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
252  }
253 
254  if ( ERK_ButcherTableau_->isEmbedded() and
255  this->stepperPL_->template get<bool>("Use Embedded") ){
256  ee_ = Thyra::createMember(this->appModel_->get_f_space());
257  abs_u0 = Thyra::createMember(this->appModel_->get_f_space());
258  abs_u = Thyra::createMember(this->appModel_->get_f_space());
259  sc = Thyra::createMember(this->appModel_->get_f_space());
260  }
261 }
262 
263 
264 template<class Scalar>
266  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
267 {
268  using Teuchos::RCP;
269 
270  RCP<SolutionState<Scalar> > initialState = solutionHistory->getCurrentState();
271 
272  // Check if we need Stepper storage for xDot
273  if (initialState->getXDot() == Teuchos::null)
274  this->setStepperXDot(stageXDot_.back());
275 
277 }
278 
279 
280 template<class Scalar>
282  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
283 {
284  using Teuchos::RCP;
285 
286  TEMPUS_FUNC_TIME_MONITOR("Tempus::StepperExplicitRK::takeStep()");
287  {
288  TEUCHOS_TEST_FOR_EXCEPTION(solutionHistory->getNumStates() < 2,
289  std::logic_error,
290  "Error - StepperExplicitRK<Scalar>::takeStep(...)\n"
291  "Need at least two SolutionStates for ExplicitRK.\n"
292  " Number of States = " << solutionHistory->getNumStates() << "\n"
293  "Try setting in \"Solution History\" \"Storage Type\" = \"Undo\"\n"
294  " or \"Storage Type\" = \"Static\" and \"Storage Limit\" = \"2\"\n");
295 
296  this->stepperObserver_->observeBeginTakeStep(solutionHistory, *this);
297  RCP<SolutionState<Scalar> > currentState=solutionHistory->getCurrentState();
298  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
299  const Scalar dt = workingState->getTimeStep();
300  const Scalar time = currentState->getTime();
301 
302  const int numStages = ERK_ButcherTableau_->numStages();
303  Teuchos::SerialDenseMatrix<int,Scalar> A = ERK_ButcherTableau_->A();
304  Teuchos::SerialDenseVector<int,Scalar> b = ERK_ButcherTableau_->b();
305  Teuchos::SerialDenseVector<int,Scalar> c = ERK_ButcherTableau_->c();
306 
307  // Compute stage solutions
308  for (int i=0; i < numStages; ++i) {
309  if (!Teuchos::is_null(stepperExplicitRKObserver_))
310  stepperExplicitRKObserver_->observeBeginStage(solutionHistory, *this);
311 
312  if ( i == 0 && this->getUseFSAL() &&
313  workingState->getNConsecutiveFailures() == 0 ) {
314 
315  RCP<Thyra::VectorBase<Scalar> > tmp = stageXDot_[0];
316  stageXDot_[0] = stageXDot_.back();
317  stageXDot_.back() = tmp;
318 
319  } else {
320 
321  Thyra::assign(stageX_.ptr(), *(currentState->getX()));
322  for (int j=0; j < i; ++j) {
323  if (A(i,j) != Teuchos::ScalarTraits<Scalar>::zero()) {
324  Thyra::Vp_StV(stageX_.ptr(), dt*A(i,j), *stageXDot_[j]);
325  }
326  }
327  const Scalar ts = time + c(i)*dt;
328 
329  if (!Teuchos::is_null(stepperExplicitRKObserver_))
330  stepperExplicitRKObserver_->observeBeforeExplicit(solutionHistory,
331  *this);
332  // Evaluate xDot = f(x,t).
333  this->evaluateExplicitODE(stageXDot_[i], stageX_, ts);
334  }
335 
336  if (!Teuchos::is_null(stepperExplicitRKObserver_))
337  stepperExplicitRKObserver_->observeEndStage(solutionHistory, *this);
338  }
339 
340  // Sum for solution: x_n = x_n-1 + Sum{ b(i) * dt*f(i) }
341  Thyra::assign((workingState->getX()).ptr(), *(currentState->getX()));
342  for (int i=0; i < numStages; ++i) {
343  if (b(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
344  Thyra::Vp_StV((workingState->getX()).ptr(), dt*b(i), *(stageXDot_[i]));
345  }
346  }
347 
348 
349  // At this point, the stepper has passed.
350  // But when using adaptive time stepping, the embedded method
351  // can change the step status
352  workingState->setSolutionStatus(Status::PASSED);
353 
354  if (ERK_ButcherTableau_->isEmbedded() and this->getEmbedded()) {
355 
356  RCP<SolutionStateMetaData<Scalar> > metaData=workingState->getMetaData();
357  const Scalar tolAbs = metaData->getTolRel();
358  const Scalar tolRel = metaData->getTolAbs();
359 
360  // just compute the error weight vector
361  // (all that is needed is the error, and not the embedded solution)
362  Teuchos::SerialDenseVector<int,Scalar> errWght = b ;
363  errWght -= ERK_ButcherTableau_->bstar();
364 
365  //compute local truncation error estimate: | u^{n+1} - \hat{u}^{n+1} |
366  // Sum for solution: ee_n = Sum{ (b(i) - bstar(i)) * dt*f(i) }
367  assign(ee_.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
368  for (int i=0; i < numStages; ++i) {
369  if (errWght(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
370  Thyra::Vp_StV(ee_.ptr(), dt*errWght(i), *(stageXDot_[i]));
371  }
372  }
373 
374  // compute: Atol + max(|u^n|, |u^{n+1}| ) * Rtol
375  Thyra::abs( *(currentState->getX()), abs_u0.ptr());
376  Thyra::abs( *(workingState->getX()), abs_u.ptr());
377  Thyra::pair_wise_max_update(tolRel, *abs_u0, abs_u.ptr());
378  Thyra::add_scalar(tolAbs, abs_u.ptr());
379 
380  //compute: || ee / sc ||
381  assign(sc.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
382  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *ee_, *abs_u, sc.ptr());
383  Scalar err = std::abs(Thyra::norm_inf(*sc));
384  metaData->setErrorRel(err);
385 
386  // test if step should be rejected
387  if (std::isinf(err) || std::isnan(err) || err > Teuchos::as<Scalar>(1.0))
388  workingState->setSolutionStatus(Status::FAILED);
389  }
390 
391  workingState->setOrder(this->getOrder());
392  this->stepperObserver_->observeEndTakeStep(solutionHistory, *this);
393  }
394  return;
395 }
396 
397 
398 /** \brief Provide a StepperState to the SolutionState.
399  * This Stepper does not have any special state data,
400  * so just provide the base class StepperState with the
401  * Stepper description. This can be checked to ensure
402  * that the input StepperState can be used by this Stepper.
403  */
404 template<class Scalar>
405 Teuchos::RCP<Tempus::StepperState<Scalar> > StepperExplicitRK<Scalar>::
407 {
408  Teuchos::RCP<Tempus::StepperState<Scalar> > stepperState =
409  rcp(new StepperState<Scalar>(description()));
410  return stepperState;
411 }
412 
413 
414 template<class Scalar>
416 {
417  return(ERK_ButcherTableau_->description());
418 }
419 
420 
421 template<class Scalar>
423  Teuchos::FancyOStream &out,
424  const Teuchos::EVerbosityLevel /* verbLevel */) const
425 {
426  out << description() << "::describe:" << std::endl
427  << "appModel_ = " << this->appModel_->description() << std::endl;
428 }
429 
430 
431 template <class Scalar>
433  const Teuchos::RCP<Teuchos::ParameterList> & pList)
434 {
435  if (pList == Teuchos::null) {
436  // Create default parameters if null, otherwise keep current parameters.
437  if (this->stepperPL_ == Teuchos::null)
438  this->stepperPL_ = this->getDefaultParameters();
439  } else {
440  this->stepperPL_ = pList;
441  }
442  // Can not validate because of optional Parameters.
443  this->stepperPL_->validateParametersAndSetDefaults(*this->getValidParameters(),0);
444 }
445 
446 
447 template<class Scalar>
448 Teuchos::RCP<const Teuchos::ParameterList>
450 {
451  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
452  if (ERK_ButcherTableau_ == Teuchos::null) {
453  auto ERK_ButcherTableau =
454  createRKBT<Scalar>("RK Explicit 4 Stage", Teuchos::null);
455  pl->setParameters(*(ERK_ButcherTableau->getValidParameters()));
456  } else {
457  pl->setParameters(*(ERK_ButcherTableau_->getValidParameters()));
458  }
459 
460  this->getValidParametersBasic(pl);
461  pl->set<std::string>("Initial Condition Consistency", "Consistent");
462  pl->set<bool>("Use Embedded", false,
463  "'Whether to use Embedded Stepper (if available) or not\n"
464  " 'true' - Stepper will compute embedded solution and is adaptive.\n"
465  " 'false' - Stepper is not embedded(adaptive).\n");
466  return pl;
467 }
468 
469 
470 template<class Scalar>
471 Teuchos::RCP<Teuchos::ParameterList>
473 {
474  using Teuchos::RCP;
475  using Teuchos::ParameterList;
476  using Teuchos::rcp_const_cast;
477 
478  RCP<ParameterList> pl =
479  rcp_const_cast<ParameterList>(this->getValidParameters());
480 
481  return pl;
482 }
483 
484 
485 template <class Scalar>
486 Teuchos::RCP<Teuchos::ParameterList>
488 {
489  return(this->stepperPL_);
490 }
491 
492 
493 template <class Scalar>
494 Teuchos::RCP<Teuchos::ParameterList>
496 {
497  Teuchos::RCP<Teuchos::ParameterList> temp_plist = this->stepperPL_;
498  this->stepperPL_ = Teuchos::null;
499  return(temp_plist);
500 }
501 
502 
503 } // namespace Tempus
504 #endif // Tempus_StepperExplicitRK_impl_hpp
Teuchos::RCP< Teuchos::ParameterList > getDefaultParameters() const
virtual Scalar getInitTimeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory) const
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
virtual std::string description() const
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList()
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions and make them consistent.
StepperExplicitRKObserver class for StepperExplicitRK.
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...
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList()
virtual void takeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Take the specified timestep, dt, and return true if successful.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &pl)
virtual void initialize()
Initialize during construction and after changing input parameters.
virtual void setTableau(std::string stepperType)
virtual Teuchos::RCP< Tempus::StepperState< Scalar > > getDefaultStepperState()
Get a default (initial) StepperState.