Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Tempus_StepperDIRK_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_StepperDIRK_impl_hpp
10 #define Tempus_StepperDIRK_impl_hpp
11 
12 #include "Tempus_config.hpp"
14 #include "Tempus_WrapperModelEvaluatorBasic.hpp"
15 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
16 #include "Thyra_VectorStdOps.hpp"
17 #include "NOX_Thyra.H"
18 
19 
20 namespace Tempus {
21 
22 // Forward Declaration for recursive includes (this Stepper <--> StepperFactory)
23 template<class Scalar> class StepperFactory;
24 
25 template<class Scalar>
27 {
28  this->setUseFSAL( this->getUseFSALDefault());
29  this->setICConsistency( this->getICConsistencyDefault());
30  this->setICConsistencyCheck( this->getICConsistencyCheckDefault());
31  this->setUseEmbedded( this->getUseEmbeddedDefault());
32  this->setZeroInitialGuess( false);
33 
34  stepperObserver_ = Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
35 }
36 
37 
38 template<class Scalar>
40  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel,
41  const Teuchos::RCP<StepperRKObserver<Scalar> >& obs,
42  const Teuchos::RCP<Thyra::NonlinearSolverBase<Scalar> >& solver,
43  bool useFSAL,
44  std::string ICConsistency,
45  bool ICConsistencyCheck,
46  bool useEmbedded,
47  bool zeroInitialGuess)
48 {
49  this->setUseFSAL( useFSAL);
50  this->setICConsistency( ICConsistency);
51  this->setICConsistencyCheck( ICConsistencyCheck);
52  this->setUseEmbedded( useEmbedded);
53  this->setZeroInitialGuess( zeroInitialGuess);
54 
55  stepperObserver_ = Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
56  this->setObserver(obs);
57 
58  if (appModel != Teuchos::null) {
59  this->setModel(appModel);
60  this->setSolver(solver);
61  this->initialize();
62  }
63 }
64 
65 
66 template<class Scalar>
68  Teuchos::RCP<Teuchos::ParameterList> pl) const
69 {
70  getValidParametersBasic(pl, this->getStepperType());
71  pl->set<bool>("Use Embedded", false,
72  "'Whether to use Embedded Stepper (if available) or not\n"
73  " 'true' - Stepper will compute embedded solution and is adaptive.\n"
74  " 'false' - Stepper is not embedded(adaptive).\n");
75  pl->set<std::string>("Description", this->getDescription());
76  pl->set<std::string>("Solver Name", "Default Solver",
77  "Name of ParameterList containing the solver specifications.");
78  pl->set<bool>("Zero Initial Guess", false);
79  pl->set<bool>("Reset Initial Guess", true);
80  Teuchos::RCP<Teuchos::ParameterList> solverPL = defaultSolverParameters();
81  pl->set("Default Solver", *solverPL);
82 }
83 
84 
85 template<class Scalar>
87  Teuchos::RCP<StepperObserver<Scalar> > obs)
88 {
89 
90  if (this->stepperObserver_ == Teuchos::null)
91  this->stepperObserver_ =
92  Teuchos::rcp(new StepperRKObserverComposite<Scalar>());
93 
94  if (( obs == Teuchos::null ) and (this->stepperObserver_->getSize() >0 ) )
95  return;
96 
97  if (( obs == Teuchos::null ) and (this->stepperObserver_->getSize() == 0) )
98  obs = Teuchos::rcp(new StepperRKObserver<Scalar>());
99 
100  // Check that this casts to prevent a runtime error if it doesn't
101  if (Teuchos::rcp_dynamic_cast<StepperRKObserver<Scalar> > (obs) != Teuchos::null) {
102  this->stepperObserver_->addObserver(
103  Teuchos::rcp_dynamic_cast<StepperRKObserver<Scalar> > (obs, true) );
104  } else {
105  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
106  Teuchos::OSTab ostab(out,0,"setObserver");
107  *out << "Tempus::StepperIMEX_RK::setObserver: Warning: An observer has been provided that";
108  *out << " does not support Tempus::StepperRKObserver. This observer WILL NOT be added.";
109  *out << " In the future, this will result in a runtime error!" << std::endl;
110  }
111 
112 }
113 
114 
115 template<class Scalar>
117 {
118  TEUCHOS_TEST_FOR_EXCEPTION( tableau_ == Teuchos::null, std::logic_error,
119  "Error - Need to set the tableau, before calling "
120  "StepperDIRK::initialize()\n");
121 
122  TEUCHOS_TEST_FOR_EXCEPTION( this->wrapperModel_ == Teuchos::null,
123  std::logic_error,
124  "Error - Need to set the model, setModel(), before calling "
125  "StepperDIRK::initialize()\n");
126 
127  TEUCHOS_TEST_FOR_EXCEPTION( this->solver_ == Teuchos::null,
128  std::logic_error,
129  "Error - Need to set the solver, setSolver(), before calling "
130  "StepperDIRK::initialize()\n");
131 
132  this->setObserver();
133 
134  TEUCHOS_TEST_FOR_EXCEPTION( this->stepperObserver_ == Teuchos::null,
135  std::logic_error,
136  "Error - StepperRKObserver is null!\n");
137 
138  // Initialize the stage vectors
139  const int numStages = tableau_->numStages();
140  stageX_ = this->wrapperModel_->getNominalValues().get_x()->clone_v();
141  stageXDot_.resize(numStages);
142  for (int i=0; i<numStages; ++i) {
143  stageXDot_[i] = Thyra::createMember(this->wrapperModel_->get_f_space());
144  assign(stageXDot_[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
145  }
146  xTilde_ = Thyra::createMember(this->wrapperModel_->get_x_space());
147  assign(xTilde_.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
148 
149  if (tableau_->isEmbedded() and this->getUseEmbedded()) {
150  ee_ = Thyra::createMember(this->wrapperModel_->get_f_space());
151  abs_u0 = Thyra::createMember(this->wrapperModel_->get_f_space());
152  abs_u = Thyra::createMember(this->wrapperModel_->get_f_space());
153  sc = Thyra::createMember(this->wrapperModel_->get_f_space());
154  }
155 }
156 
157 
158 template<class Scalar>
160  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
161 {
162  using Teuchos::RCP;
163 
164  RCP<SolutionState<Scalar> > initialState = solutionHistory->getCurrentState();
165 
166  // Check if we need Stepper storage for xDot
167  if (initialState->getXDot() == Teuchos::null)
168  this->setStepperXDot(stageXDot_.back());
169 
171 }
172 
173 
174 template<class Scalar>
176  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
177 {
178  using Teuchos::RCP;
179 
180  TEMPUS_FUNC_TIME_MONITOR("Tempus::StepperDIRK::takeStep()");
181  {
182  TEUCHOS_TEST_FOR_EXCEPTION(solutionHistory->getNumStates() < 2,
183  std::logic_error,
184  "Error - StepperDIRK<Scalar>::takeStep(...)\n"
185  "Need at least two SolutionStates for DIRK.\n"
186  " Number of States = " << solutionHistory->getNumStates() << "\n"
187  "Try setting in \"Solution History\" \"Storage Type\" = \"Undo\"\n"
188  " or \"Storage Type\" = \"Static\" and \"Storage Limit\" = \"2\"\n");
189 
190  this->stepperObserver_->observeBeginTakeStep(solutionHistory, *this);
191  RCP<SolutionState<Scalar> > currentState=solutionHistory->getCurrentState();
192  RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
193  const Scalar dt = workingState->getTimeStep();
194  const Scalar time = currentState->getTime();
195 
196  const int numStages = tableau_->numStages();
197  Teuchos::SerialDenseMatrix<int,Scalar> A = tableau_->A();
198  Teuchos::SerialDenseVector<int,Scalar> b = tableau_->b();
199  Teuchos::SerialDenseVector<int,Scalar> c = tableau_->c();
200 
201  // Reset non-zero initial guess.
202  if ( this->getResetInitialGuess() && (!this->getZeroInitialGuess()) )
203  Thyra::assign(stageX_.ptr(), *(currentState->getX()));
204 
205  // Compute stage solutions
206  bool pass = true;
207  Thyra::SolveStatus<Scalar> sStatus;
208  for (int i=0; i < numStages; ++i) {
209  this->stepperObserver_->observeBeginStage(solutionHistory, *this);
210 
211  // ???: is it a good idea to leave this (no-op) here?
212  this->stepperObserver_
213  ->observeBeforeImplicitExplicitly(solutionHistory, *this);
214 
215  if ( i == 0 && this->getUseFSAL() &&
216  workingState->getNConsecutiveFailures() == 0 ) {
217 
218  RCP<Thyra::VectorBase<Scalar> > tmp = stageXDot_[0];
219  stageXDot_[0] = stageXDot_.back();
220  stageXDot_.back() = tmp;
221 
222  } else {
223 
224  Thyra::assign(xTilde_.ptr(), *(currentState->getX()));
225  for (int j=0; j < i; ++j) {
226  if (A(i,j) != Teuchos::ScalarTraits<Scalar>::zero()) {
227  Thyra::Vp_StV(xTilde_.ptr(), dt*A(i,j), *(stageXDot_[j]));
228  }
229  }
230 
231  Scalar ts = time + c(i)*dt;
232  if (A(i,i) == Teuchos::ScalarTraits<Scalar>::zero()) {
233  // Explicit stage for the ImplicitODE_DAE
234  bool isNeeded = false;
235  for (int k=i+1; k<numStages; ++k) if (A(k,i) != 0.0) isNeeded = true;
236  if (b(i) != 0.0) isNeeded = true;
237  if (isNeeded == false) {
238  // stageXDot_[i] is not needed.
239  assign(stageXDot_[i].ptr(), Teuchos::ScalarTraits<Scalar>::zero());
240  } else {
241  typedef Thyra::ModelEvaluatorBase MEB;
242  MEB::InArgs<Scalar> inArgs = this->wrapperModel_->getInArgs();
243  MEB::OutArgs<Scalar> outArgs = this->wrapperModel_->getOutArgs();
244  inArgs.set_x(xTilde_);
245  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(ts);
246  if (inArgs.supports(MEB::IN_ARG_x_dot))
247  inArgs.set_x_dot(Teuchos::null);
248  outArgs.set_f(stageXDot_[i]);
249 
250  this->stepperObserver_->observeBeforeExplicit(solutionHistory, *this);
251  this->wrapperModel_->getAppModel()->evalModel(inArgs,outArgs);
252  }
253  } else {
254  // Implicit stage for the ImplicitODE_DAE
255  const Scalar alpha = 1.0/(dt*A(i,i));
256  const Scalar beta = 1.0;
257 
258  // Setup TimeDerivative
259  Teuchos::RCP<TimeDerivative<Scalar> > timeDer =
260  Teuchos::rcp(new StepperDIRKTimeDerivative<Scalar>(
261  alpha,xTilde_.getConst()));
262 
263  auto p = Teuchos::rcp(new ImplicitODEParameters<Scalar>(
264  timeDer, dt, alpha, beta, SOLVE_FOR_X, i));
265 
266  this->stepperObserver_->observeBeforeSolve(solutionHistory, *this);
267 
268  sStatus = this->solveImplicitODE(stageX_, stageXDot_[i], ts, p);
269 
270  if (sStatus.solveStatus != Thyra::SOLVE_STATUS_CONVERGED) pass=false;
271 
272  this->stepperObserver_->observeAfterSolve(solutionHistory, *this);
273 
274  timeDer->compute(stageX_, stageXDot_[i]);
275  }
276  }
277 
278  this->stepperObserver_->observeEndStage(solutionHistory, *this);
279  }
280 
281  // Sum for solution: x_n = x_n-1 + Sum{ dt*b(i) * 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 (tableau_->isEmbedded() and this->getUseEmbedded()) {
290  RCP<SolutionStateMetaData<Scalar> > metaData=workingState->getMetaData();
291  const Scalar tolAbs = metaData->getTolRel();
292  const Scalar tolRel = metaData->getTolAbs();
293 
294  // just compute the error weight vector
295  // (all that is needed is the error, and not the embedded solution)
296  Teuchos::SerialDenseVector<int,Scalar> errWght = b ;
297  errWght -= tableau_->bstar();
298 
299  // compute local truncation error estimate: | u^{n+1} - \hat{u}^{n+1} |
300  // Sum for solution: ee_n = Sum{ (b(i) - bstar(i)) * dt*f(i) }
301  assign(ee_.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
302  for (int i=0; i < numStages; ++i) {
303  if (errWght(i) != Teuchos::ScalarTraits<Scalar>::zero()) {
304  Thyra::Vp_StV(ee_.ptr(), dt*errWght(i), *(stageXDot_[i]));
305  }
306  }
307 
308  // compute: Atol + max(|u^n|, |u^{n+1}| ) * Rtol
309  Thyra::abs( *(currentState->getX()), abs_u0.ptr());
310  Thyra::abs( *(workingState->getX()), abs_u.ptr());
311  Thyra::pair_wise_max_update(tolRel, *abs_u0, abs_u.ptr());
312  Thyra::add_scalar(tolAbs, abs_u.ptr());
313 
314  // compute: || ee / sc ||
315  assign(sc.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
316  Thyra::ele_wise_divide(Teuchos::as<Scalar>(1.0), *ee_, *abs_u, sc.ptr());
317  Scalar err = std::abs(Thyra::norm_inf(*sc));
318  metaData->setErrorRel(err);
319 
320  // test if step should be rejected
321  if (std::isinf(err) || std::isnan(err) || err > Teuchos::as<Scalar>(1.0))
322  pass = false;
323  }
324 
325  if (pass) workingState->setSolutionStatus(Status::PASSED);
326  else workingState->setSolutionStatus(Status::FAILED);
327 
328  workingState->setOrder(this->getOrder());
329  this->stepperObserver_->observeEndTakeStep(solutionHistory, *this);
330  }
331  return;
332 }
333 
334 /** \brief Provide a StepperState to the SolutionState.
335  * This Stepper does not have any special state data,
336  * so just provide the base class StepperState with the
337  * Stepper description. This can be checked to ensure
338  * that the input StepperState can be used by this Stepper.
339  */
340 template<class Scalar>
341 Teuchos::RCP<Tempus::StepperState<Scalar> >
344 {
345  Teuchos::RCP<Tempus::StepperState<Scalar> > stepperState =
346  rcp(new StepperState<Scalar>(this->getStepperType()));
347  return stepperState;
348 }
349 
350 
351 template<class Scalar>
353  Teuchos::FancyOStream &out,
354  const Teuchos::EVerbosityLevel /* verbLevel */) const
355 {
356  out << this->getStepperType() << "::describe:" << std::endl
357  << "wrapperModel_ = " << this->wrapperModel_->description() << std::endl;
358 }
359 
360 
361 template<class Scalar>
362 Teuchos::RCP<const Teuchos::ParameterList>
364 {
365  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
366  this->getValidParametersBasicDIRK(pl);
367 
368  return pl;
369 }
370 
371 
372 } // namespace Tempus
373 #endif // Tempus_StepperDIRK_impl_hpp
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions and make them consistent.
virtual Teuchos::RCP< Tempus::StepperState< Scalar > > getDefaultStepperState()
Get a default (initial) StepperState.
virtual void setup(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &wrapperModel, const Teuchos::RCP< StepperRKObserver< Scalar > > &obs, const Teuchos::RCP< Thyra::NonlinearSolverBase< Scalar > > &solver, bool useFSAL, std::string ICConsistency, bool ICConsistencyCheck, bool useEmbedded, bool zeroInitialGuess)
Setup for constructor.
void getValidParametersBasicDIRK(Teuchos::RCP< Teuchos::ParameterList > pl) const
Teuchos::RCP< Teuchos::ParameterList > defaultSolverParameters()
Returns the default solver ParameterList for implicit Steppers.
StepperState is a simple class to hold state information about the stepper.
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Set the initial conditions and make them consistent.
virtual void initialize()
Initialize during construction and after changing input parameters.
Time-derivative interface for DIRK.
virtual void setupDefault()
Default setup for constructor.
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< const Teuchos::ParameterList > getValidParameters() const
virtual void setObserver(Teuchos::RCP< StepperObserver< Scalar > > obs=Teuchos::null)
Set Observer.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
StepperRKObserver class for StepperRK.
Solve for x and determine xDot from x.
void getValidParametersBasic(Teuchos::RCP< Teuchos::ParameterList > pl, std::string stepperType)
Provide basic parameters to Steppers.
virtual void takeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory)
Take the specified timestep, dt, and return true if successful.