Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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 "Thyra_VectorStdOps.hpp"
13 
15 
16 
17 namespace Tempus {
18 
19 
20 template<class Scalar>
22 {
23  this->setUseEmbedded(false);
24  this->setStageNumber(-1);
25  this->setAppAction(Teuchos::null);
26 }
27 
28 
29 template<class Scalar>
31  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
32  bool useFSAL,
33  std::string ICConsistency,
34  bool ICConsistencyCheck,
35  bool useEmbedded,
36  const Teuchos::RCP<StepperRKAppAction<Scalar> >& stepperRKAppAction)
37 {
38  this->setUseFSAL( useFSAL);
39  this->setICConsistency( ICConsistency);
40  this->setICConsistencyCheck( ICConsistencyCheck);
41  this->setUseEmbedded( useEmbedded);
42  this->setStageNumber(-1);
43 
44  this->setAppAction(stepperRKAppAction);
45 
46  if (appModel != Teuchos::null) {
47  this->setModel(appModel);
48  this->initialize();
49  }
50 }
51 
52 
53 template<class Scalar>
55  const Teuchos::RCP<SolutionHistory<Scalar> >& sh) const
56 {
57 
58  Scalar dt = Scalar(1.0e+99);
59  if (!this->getUseEmbedded()) return dt;
60 
61  Teuchos::RCP<SolutionState<Scalar> > currentState=sh->getCurrentState();
62  const int order = currentState->getOrder();
63  const Scalar time = currentState->getTime();
64  const Scalar errorRel = currentState->getTolRel();
65  const Scalar errorAbs = currentState->getTolAbs();
66 
67  Teuchos::RCP<Thyra::VectorBase<Scalar> > stageX, scratchX;
68  stageX = Thyra::createMember(this->appModel_->get_f_space());
69  scratchX = Thyra::createMember(this->appModel_->get_f_space());
70  Thyra::assign(stageX.ptr(), *(currentState->getX()));
71 
72  std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar> > > stageXDot(2);
73  for (int i=0; i<2; ++i) {
74  stageXDot[i] = Thyra::createMember(this->appModel_->get_f_space());
75  assign(stageXDot[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
76  }
77 
78  // A: one function evaluation at F(t_0, X_0)
79  typedef Thyra::ModelEvaluatorBase MEB;
80  MEB::InArgs<Scalar> inArgs = this->appModel_->getNominalValues();
81  MEB::OutArgs<Scalar> outArgs = this->appModel_->createOutArgs();
82  inArgs.set_x(stageX);
83  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time);
84  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
85  outArgs.set_f(stageXDot[0]); // K1
86  this->appModel_->evalModel(inArgs, outArgs);
87 
88  auto err_func = [] (Teuchos::RCP<Thyra::VectorBase<Scalar> > U,
89  const Scalar rtol, const Scalar atol,
91  {
92  // compute err = Norm_{WRMS} with w = Atol + Rtol * | U |
93  Thyra::assign(absU.ptr(), *U);
94  Thyra::abs(*U, absU.ptr()); // absU = | X0 |
95  Thyra::Vt_S(absU.ptr(), rtol); // absU *= Rtol
96  Thyra::Vp_S(absU.ptr(), atol); // absU += Atol
97  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *U, *absU, absU.ptr());
98  Scalar err = Thyra::norm_inf(*absU);
99  return err;
100  };
101 
102  Scalar d0 = err_func(stageX, errorRel, errorAbs, scratchX);
103  Scalar d1 = err_func(stageXDot[0], errorRel, errorAbs, scratchX);
104 
105  // b) first guess for the step size
106  dt = Teuchos::as<Scalar>(0.01)*(d0/d1);
107 
108  // c) perform one explicit Euler step (X_1)
109  Thyra::Vp_StV(stageX.ptr(), dt, *(stageXDot[0]));
110 
111  // compute F(t_0 + dt, X_1)
112  inArgs.set_x(stageX);
113  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time + dt);
114  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(Teuchos::null);
115  outArgs.set_f(stageXDot[1]); // K2
116  this->appModel_->evalModel(inArgs, outArgs);
117 
118  // d) compute estimate of the second derivative of the solution
119  // d2 = || f(t_0 + dt, X_1) - f(t_0, X_0) || / dt
121  errX = Thyra::createMember(this->appModel_->get_f_space());
122  assign(errX.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
123  Thyra::V_VmV(errX.ptr(), *(stageXDot[1]), *(stageXDot[0]));
124  Scalar d2 = err_func(errX, errorRel, errorAbs, scratchX) / dt;
125 
126  // e) compute step size h_1 (from m = 0 order Taylor series)
127  Scalar max_d1_d2 = std::max(d1, d2);
128  Scalar h1 = std::pow((0.01/max_d1_d2),(1.0/(order+1)));
129 
130  // f) propose starting step size
131  dt = std::min(100*dt, h1);
132  return dt;
133 }
134 
135 
136 template<class Scalar>
139 {
140  return this->getValidParametersBasicERK();
141 }
142 
143 
144 template<class Scalar>
147 {
148  auto pl = this->getValidParametersBasic();
149  pl->template set<bool>("Use Embedded", this->getUseEmbedded(),
150  "'Whether to use Embedded Stepper (if available) or not\n"
151  " 'true' - Stepper will compute embedded solution and is adaptive.\n"
152  " 'false' - Stepper is not embedded(adaptive).\n");
153  pl->template set<std::string>("Description", this->getDescription());
154 
155  return pl;
156 }
157 
158 
159 template<class Scalar>
161 {
162  TEUCHOS_TEST_FOR_EXCEPTION( this->tableau_ == Teuchos::null, std::logic_error,
163  "Error - Need to set the tableau, before calling "
164  "StepperExplicitRK::initialize()\n");
165 
166  TEUCHOS_TEST_FOR_EXCEPTION( this->appModel_==Teuchos::null, std::logic_error,
167  "Error - Need to set the model, setModel(), before calling "
168  "StepperExplicitRK::initialize()\n");
169 
170  // Initialize the stage vectors
171  int numStages = this->tableau_->numStages();
172  stageXDot_.resize(numStages);
173  for (int i=0; i<numStages; ++i) {
174  stageXDot_[i] = Thyra::createMember(this->appModel_->get_f_space());
175  assign(stageXDot_[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
176  }
177 
178  if ( this->tableau_->isEmbedded() && this->getUseEmbedded() ){
179  this->ee_ = Thyra::createMember(this->appModel_->get_f_space());
180  this->abs_u0 = Thyra::createMember(this->appModel_->get_f_space());
181  this->abs_u = Thyra::createMember(this->appModel_->get_f_space());
182  this->sc = Thyra::createMember(this->appModel_->get_f_space());
183  }
184 
186 }
187 
188 
189 template<class Scalar>
191  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
192 {
193  if (this->getUseFSAL())
194  this->setStepperXDot(stageXDot_.back());
195  else
196  this->setStepperXDot(stageXDot_[0]);
197 
199 
200  auto xDot = solutionHistory->getCurrentState()->getXDot();
201  if (xDot != Teuchos::null && this->getUseFSAL())
202  Thyra::assign(this->getStepperXDot().ptr(), *(xDot));
203 }
204 
205 
206 template<class Scalar>
208  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
209 {
210  this->checkInitialized();
211 
212  using Teuchos::RCP;
213 
214  TEMPUS_FUNC_TIME_MONITOR("Tempus::StepperExplicitRK::takeStep()");
215  {
216  TEUCHOS_TEST_FOR_EXCEPTION(solutionHistory->getNumStates() < 2,
217  std::logic_error,
218  "Error - StepperExplicitRK<Scalar>::takeStep(...)\n"
219  "Need at least two SolutionStates for ExplicitRK.\n"
220  " Number of States = " << solutionHistory->getNumStates() << "\n"
221  "Try setting in \"Solution History\" \"Storage Type\" = \"Undo\"\n"
222  " or \"Storage Type\" = \"Static\" and \"Storage Limit\" = \"2\"\n");
223 
224  RCP<SolutionState<Scalar> > currentState=solutionHistory->getCurrentState();
225  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
226  const Scalar dt = workingState->getTimeStep();
227  const Scalar time = currentState->getTime();
228 
229  const int numStages = this->tableau_->numStages();
230  Teuchos::SerialDenseMatrix<int,Scalar> A = this->tableau_->A();
231  Teuchos::SerialDenseVector<int,Scalar> b = this->tableau_->b();
232  Teuchos::SerialDenseVector<int,Scalar> c = this->tableau_->c();
233 
234  Thyra::assign(workingState->getX().ptr(), *(currentState->getX()));
235 
236  RCP<StepperExplicitRK<Scalar> > thisStepper = Teuchos::rcpFromRef(*this);
237  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
239 
240  // Compute stage solutions
241  for (int i=0; i < numStages; ++i) {
242  this->setStageNumber(i);
243  Thyra::assign(workingState->getX().ptr(), *(currentState->getX()));
244  for (int j=0; j < i; ++j) {
245  if (A(i,j) != Teuchos::ScalarTraits<Scalar>::zero()) {
246  Thyra::Vp_StV(workingState->getX().ptr(), dt*A(i,j), *stageXDot_[j]);
247  }
248  }
249  this->setStepperXDot(stageXDot_[i]);
250 
251  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
253  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
255  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
257  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
259 
260  if ( i == 0 && this->getUseFSAL() &&
261  workingState->getNConsecutiveFailures() == 0 ) {
262  RCP<Thyra::VectorBase<Scalar> > tmp = stageXDot_[0];
263  stageXDot_[0] = stageXDot_.back();
264  stageXDot_.back() = tmp;
265  this->setStepperXDot(stageXDot_[0]);
266 
267  } else {
268  const Scalar ts = time + c(i)*dt;
270 
271  // Evaluate xDot = f(x,t).
272  this->evaluateExplicitODE(stageXDot_[i], workingState->getX(), ts, p);
273  }
274 
275  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
277  }
278  // reset the stage number
279  this->setStageNumber(-1);
280 
281  // Sum for solution: x_n = x_n-1 + Sum{ b(i) * dt*f(i) }
282  Thyra::assign((workingState->getX()).ptr(), *(currentState->getX()));
283  for (int i=0; i < numStages; ++i) {
284  if (b(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
285  Thyra::Vp_StV((workingState->getX()).ptr(), dt*b(i), *(stageXDot_[i]));
286  }
287  }
288 
289  if (this->getUseFSAL()) {
290  if (numStages == 1) {
291  const Scalar ts = time + dt;
293  // Evaluate xDot = f(x,t).
294  this->evaluateExplicitODE(stageXDot_[0], workingState->getX(), ts, p);
295  }
296  if (workingState->getXDot() != Teuchos::null)
297  Thyra::assign((workingState->getXDot()).ptr(), *(stageXDot_.back()));
298  }
299 
300 
301  // At this point, the stepper has passed.
302  // But when using adaptive time stepping, the embedded method
303  // can change the step status
304  workingState->setSolutionStatus(Status::PASSED);
305 
306  if (this->tableau_->isEmbedded() && this->getUseEmbedded()) {
307 
308  const Scalar tolRel = workingState->getTolRel();
309  const Scalar tolAbs = workingState->getTolAbs();
310 
311  // just compute the error weight vector
312  // (all that is needed is the error, and not the embedded solution)
314  errWght -= this->tableau_->bstar();
315 
316  //compute local truncation error estimate: | u^{n+1} - \hat{u}^{n+1} |
317  // Sum for solution: ee_n = Sum{ (b(i) - bstar(i)) * dt*f(i) }
318  assign(this->ee_.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
319  for (int i=0; i < numStages; ++i) {
320  if (errWght(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
321  Thyra::Vp_StV(this->ee_.ptr(), dt*errWght(i), *(stageXDot_[i]));
322  }
323  }
324 
325  // compute: Atol + max(|u^n|, |u^{n+1}| ) * Rtol
326  Thyra::abs( *(currentState->getX()), this->abs_u0.ptr());
327  Thyra::abs( *(workingState->getX()), this->abs_u.ptr());
328  Thyra::pair_wise_max_update(tolRel, *this->abs_u0, this->abs_u.ptr());
329  Thyra::add_scalar(tolAbs, this->abs_u.ptr());
330 
331  //compute: || ee / sc ||
332  assign(this->sc.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
333  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *this->ee_, *this->abs_u,this->sc.ptr());
334 
335  const auto space_dim = this->ee_->space()->dim();
336  Scalar err = std::abs(Thyra::norm(*this->sc)) / space_dim ;
337  workingState->setErrorRel(err);
338 
339  // test if step should be rejected
340  if (std::isinf(err) || std::isnan(err) || err > Teuchos::as<Scalar>(1.0))
341  workingState->setSolutionStatus(Status::FAILED);
342  }
343 
344  workingState->setOrder(this->getOrder());
345  workingState->computeNorms(currentState);
346  this->stepperRKAppAction_->execute(solutionHistory, thisStepper,
348  }
349  return;
350 }
351 
352 
359 template<class Scalar>
362 {
364  rcp(new StepperState<Scalar>(this->getStepperType()));
365  return stepperState;
366 }
367 
368 
369 template<class Scalar>
372  const Teuchos::EVerbosityLevel verbLevel) const
373 {
374  out << std::endl;
375  Stepper<Scalar>::describe(out, verbLevel);
376  StepperExplicit<Scalar>::describe(out, verbLevel);
377 
378  out << "--- StepperExplicitRK ---\n";
379  if (this->tableau_ != Teuchos::null) this->tableau_->describe(out, verbLevel);
380  out << " tableau_ = " << this->tableau_ << std::endl;
381  out << " stepperRKAppAction_= " << this->stepperRKAppAction_ << std::endl;
382  out << " stageXDot_.size() = " << stageXDot_.size() << std::endl;
383  const int numStages = stageXDot_.size();
384  for (int i=0; i<numStages; ++i)
385  out << " stageXDot_["<<i<<"] = " << stageXDot_[i] << std::endl;
386  out << " useEmbedded_ = "
387  << Teuchos::toString(this->useEmbedded_) << std::endl;
388  out << " ee_ = " << this->ee_ << std::endl;
389  out << " abs_u0 = " << this->abs_u0 << std::endl;
390  out << " abs_u = " << this->abs_u << std::endl;
391  out << " sc = " << this->sc << std::endl;
392  out << "-------------------------" << std::endl;
393 }
394 
395 
396 template<class Scalar>
398 {
399  bool isValidSetup = true;
400 
401  if ( !Stepper<Scalar>::isValidSetup(out) ) isValidSetup = false;
402  if ( !StepperExplicit<Scalar>::isValidSetup(out) ) isValidSetup = false;
403 
404  if (this->tableau_ == Teuchos::null) {
405  isValidSetup = false;
406  out << "The tableau is not set!\n";
407  }
408 
409  if (this->stepperRKAppAction_ == Teuchos::null) {
410  isValidSetup = false;
411  out << "The AppAction is not set!\n";
412  }
413 
414  return isValidSetup;
415 }
416 
417 
418 } // namespace Tempus
419 #endif // Tempus_StepperExplicitRK_impl_hpp
virtual void setupDefault()
Default setup for constructor.
virtual Scalar getInitTimeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory) const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
virtual void initialize()
Initialize after construction and changing input parameters.
virtual bool isValidSetup(Teuchos::FancyOStream &out) const
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions and make them consistent.
Thyra Base interface for time steppers.
StepperState is a simple class to hold state information about the stepper.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Application Action for StepperRKBase.
virtual Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Ptr< T > ptr() const
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions, make them consistent, and set needed memory.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Teuchos::RCP< Teuchos::ParameterList > getValidParametersBasicERK() 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.
virtual Teuchos::RCP< Tempus::StepperState< Scalar > > getDefaultStepperState()
Get a default (initial) StepperState.
Thyra Base interface for implicit time steppers.
std::string toString(const T &t)
virtual void setup(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &appModel, bool useFSAL, std::string ICConsistency, bool ICConsistencyCheck, bool useEmbedded, const Teuchos::RCP< StepperRKAppAction< Scalar > > &stepperRKAppAction)
Setup for constructor.