Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_StepperImplicit_impl.hpp
Go to the documentation of this file.
1 //@HEADER
2 // *****************************************************************************
3 // Tempus: Time Integration and Sensitivity Analysis Package
4 //
5 // Copyright 2017 NTESS and the Tempus contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 //@HEADER
9 
10 #ifndef Tempus_StepperImplicit_impl_hpp
11 #define Tempus_StepperImplicit_impl_hpp
12 
13 // Thrya
14 #include "NOX_Thyra.H"
15 
16 namespace Tempus {
17 
18 template <class Scalar>
20  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& appModel)
21 {
22  validImplicitODE_DAE(appModel);
23  wrapperModel_ =
25 
26  TEUCHOS_TEST_FOR_EXCEPTION(solver_ == Teuchos::null, std::logic_error,
27  "Error - Solver is not set!\n");
28  solver_->setModel(wrapperModel_);
29 
30  this->isInitialized_ = false;
31 }
32 
33 template <class Scalar>
35  const Teuchos::RCP<SolutionHistory<Scalar> >& solutionHistory)
36 {
37  using Teuchos::RCP;
38 
39  int numStates = solutionHistory->getNumStates();
40 
42  numStates < 1, std::logic_error,
43  "Error - setInitialConditions() needs at least one SolutionState\n"
44  " to set the initial condition. Number of States = "
45  << numStates);
46 
47  RCP<SolutionState<Scalar> > initialState = solutionHistory->getCurrentState();
48  RCP<Thyra::VectorBase<Scalar> > x = initialState->getX();
49  RCP<Thyra::VectorBase<Scalar> > xDot = initialState->getXDot();
50  if (xDot() == Teuchos::null) xDot = this->getStepperXDot();
51 
52  auto inArgs = this->wrapperModel_->getNominalValues();
53  if (this->getOrderODE() == SECOND_ORDER_ODE) {
54  RCP<Thyra::VectorBase<Scalar> > initialXDot = initialState->getXDot();
55  // If initialState has x and xDot set, treat them as the initial conditions.
56  // Otherwise use the x and xDot from getNominalValues() as the ICs.
58  !((x != Teuchos::null && initialXDot != Teuchos::null) ||
59  (inArgs.get_x() != Teuchos::null &&
60  inArgs.get_x_dot() != Teuchos::null)),
61  std::logic_error,
62  "Error - We need to set the initial conditions for x and xDot from\n"
63  " either initialState or appModel_->getNominalValues::InArgs\n"
64  " (but not from a mixture of the two).\n");
65  }
66 
67  if (this->getOrderODE() == FIRST_ORDER_ODE) {
68  // Use x from inArgs as ICs.
69  if (x == Teuchos::null) {
71  (x == Teuchos::null) && (inArgs.get_x() == Teuchos::null),
72  std::logic_error,
73  "Error - setInitialConditions needs the ICs from the "
74  "SolutionHistory\n"
75  " or getNominalValues()!\n");
76 
77  x = Teuchos::rcp_const_cast<Thyra::VectorBase<Scalar> >(inArgs.get_x());
78  initialState->setX(x);
79  }
80  }
81  else if (this->getOrderODE() == SECOND_ORDER_ODE) {
82  // Use the x and xDot from getNominalValues() as the ICs.
83  using Teuchos::rcp_const_cast;
84  if (x == Teuchos::null || xDot == Teuchos::null) {
86  (inArgs.get_x() == Teuchos::null) ||
87  (inArgs.get_x_dot() == Teuchos::null),
88  std::logic_error,
89  "Error - setInitialConditions() needs the ICs from the initialState\n"
90  " or getNominalValues()!\n");
91  x = rcp_const_cast<Thyra::VectorBase<Scalar> >(inArgs.get_x());
92  initialState->setX(x);
93  RCP<Thyra::VectorBase<Scalar> > x_dot =
94  rcp_const_cast<Thyra::VectorBase<Scalar> >(inArgs.get_x_dot());
95  initialState->setXDot(x_dot);
96  }
97  }
98 
99  // Perform IC Consistency
100  std::string icConsistency = this->getICConsistency();
101  if (icConsistency == "None") {
102  if (this->getOrderODE() == FIRST_ORDER_ODE) {
103  if (initialState->getXDot() == Teuchos::null)
104  Thyra::assign(xDot.ptr(), Scalar(0.0));
105  }
106  else if (this->getOrderODE() == SECOND_ORDER_ODE) {
107  if (initialState->getXDotDot() == Teuchos::null)
108  Thyra::assign(this->getStepperXDotDot(initialState).ptr(), Scalar(0.0));
109  }
110  }
111  else if (icConsistency == "Zero") {
112  if (this->getOrderODE() == FIRST_ORDER_ODE)
113  Thyra::assign(xDot.ptr(), Scalar(0.0));
114  else if (this->getOrderODE() == SECOND_ORDER_ODE)
115  Thyra::assign(this->getStepperXDotDot(initialState).ptr(), Scalar(0.0));
116  }
117  else if (icConsistency == "App") {
118  if (this->getOrderODE() == FIRST_ORDER_ODE) {
119  auto x_dot = Teuchos::rcp_const_cast<Thyra::VectorBase<Scalar> >(
120  inArgs.get_x_dot());
122  x_dot == Teuchos::null, std::logic_error,
123  "Error - setInitialConditions() requested 'App' for IC consistency,\n"
124  " but 'App' returned a null pointer for xDot!\n");
125  Thyra::assign(xDot.ptr(), *x_dot);
126  }
127  else if (this->getOrderODE() == SECOND_ORDER_ODE) {
128  auto xDotDot = Teuchos::rcp_const_cast<Thyra::VectorBase<Scalar> >(
129  inArgs.get_x_dot_dot());
131  xDotDot == Teuchos::null, std::logic_error,
132  "Error - setInitialConditions() requested 'App' for IC consistency,\n"
133  " but 'App' returned a null pointer for xDotDot!\n");
134  Thyra::assign(this->getStepperXDotDot(initialState).ptr(), *xDotDot);
135  }
136  }
137  else if (icConsistency == "Consistent") {
138  if (this->getOrderODE() == FIRST_ORDER_ODE) {
139  // Solve f(x, xDot,t) = 0.
140  const Scalar time = initialState->getTime();
141  const Scalar dt = initialState->getTimeStep();
142  RCP<TimeDerivative<Scalar> > timeDer = Teuchos::null;
143  const Scalar alpha = Scalar(1.0); // d(xDot)/d(xDot)
144  const Scalar beta = Scalar(0.0); // d(x )/d(xDot)
146  timeDer, dt, alpha, beta, SOLVE_FOR_XDOT_CONST_X));
147 
148  const Thyra::SolveStatus<Scalar> sStatus =
149  this->solveImplicitODE(x, xDot, time, p);
150 
153  std::logic_error,
154  "Error - Solver failed while determining the initial conditions.\n"
155  " Solver status is "
156  << Thyra::toString(sStatus.solveStatus) << ".\n");
157  }
158  else if (this->getOrderODE() == SECOND_ORDER_ODE) {
160  true, std::logic_error,
161  "Error - setInitialConditions(): 'Consistent' for second-order ODE\n"
162  " has not been implemented.\n");
163  }
164  }
165  else {
167  true, std::logic_error,
168  "Error - setInitialConditions() invalid IC consistency, "
169  << icConsistency << ".\n");
170  }
171 
172  // At this point, x and xDot are sync'ed or consistent
173  // at the same time level for the initialState.
174  initialState->setIsSynced(true);
175 
176  // Test for consistency.
177  if (this->getICConsistencyCheck()) {
178  auto f = initialState->getX()->clone_v();
179 
180  const Scalar time = initialState->getTime();
181  const Scalar dt = initialState->getTimeStep();
182  RCP<TimeDerivative<Scalar> > timeDer = Teuchos::null;
183  const Scalar alpha = Scalar(0.0);
184  const Scalar beta = Scalar(0.0);
186  timeDer, dt, alpha, beta, EVALUATE_RESIDUAL));
187 
188  this->evaluateImplicitODE(f, x, xDot, time, p);
189 
190  Scalar normX = Thyra::norm(*x);
191  Scalar reldiff = Scalar(0.0);
192  if (normX == Scalar(0.0))
193  reldiff = Thyra::norm(*f);
194  else
195  reldiff = Thyra::norm(*f) / normX;
196 
197  Scalar eps = Scalar(100.0) * std::abs(Teuchos::ScalarTraits<Scalar>::eps());
198  RCP<Teuchos::FancyOStream> out = this->getOStream();
199  Teuchos::OSTab ostab(out, 1, "StepperImplicit::setInitialConditions()");
200  if (reldiff < eps) {
201  *out << "\n---------------------------------------------------\n"
202  << "Info -- Stepper = " << this->getStepperType() << "\n"
203  << " Initial condition PASSED consistency check!\n"
204  << " (||f(x,xDot,t)||/||x|| = " << reldiff << ") < "
205  << "(eps = " << eps << ")" << std::endl
206  << "---------------------------------------------------\n"
207  << std::endl;
208  }
209  else {
210  *out << "\n---------------------------------------------------\n"
211  << "Info -- Stepper = " << this->getStepperType() << "\n"
212  << " Initial condition FAILED consistency check but continuing!\n"
213  << " (||f(x,xDot,t)||/||x|| = " << reldiff << ") > "
214  << "(eps = " << eps << ")" << std::endl
215  << " ||f(x,xDot,t)|| = " << Thyra::norm(*f) << std::endl
216  << " ||x|| = " << Thyra::norm(*x) << std::endl
217  << "---------------------------------------------------\n"
218  << std::endl;
219  }
220  }
221 }
222 
223 template <class Scalar>
225 {
226  solver_ = rcp(new Thyra::NOXNonlinearSolver());
227  auto solverPL = defaultSolverParameters();
228  this->setSolverName("Default Solver");
229  auto subPL = sublist(solverPL, "NOX");
230  solver_->setParameterList(subPL);
231 
232  if (wrapperModel_ != Teuchos::null) solver_->setModel(wrapperModel_);
233 
234  this->isInitialized_ = false;
235 }
236 
237 template <class Scalar>
240 {
242  solver == Teuchos::null, std::logic_error,
243  "Error - Can not set the solver to Teuchos::null.\n");
244 
245  solver_ = solver;
246  if (wrapperModel_ != Teuchos::null) solver_->setModel(wrapperModel_);
247 
248  this->isInitialized_ = false;
249 }
250 
251 template <class Scalar>
254  const Teuchos::RCP<Thyra::VectorBase<Scalar> >& xDot, const Scalar time,
256  const Teuchos::RCP<Thyra::VectorBase<Scalar> >& y, const int index)
257 {
258  wrapperModel_->setForSolve(x, xDot, time, p, y, index);
259 
262  switch (p->evaluationType_) {
263  case SOLVE_FOR_X: {
264  if (getZeroInitialGuess()) Thyra::assign(x.ptr(), ST::zero());
265  sStatus = (*solver_).solve(&*x);
266  break;
267  }
268  case SOLVE_FOR_XDOT_CONST_X: {
269  // if (getZeroInitialGuess()) Thyra::assign(xDot.ptr(), ST::zero());
270  sStatus = (*solver_).solve(&*xDot);
271  break;
272  }
273  default: {
274  TEUCHOS_TEST_FOR_EXCEPT("Invalid EVALUATION_TYPE!");
275  }
276  }
277 
278  return sStatus;
279 }
280 
281 template <class Scalar>
285  const Teuchos::RCP<Thyra::VectorBase<Scalar> >& xDot, const Scalar time,
287 {
288  typedef Thyra::ModelEvaluatorBase MEB;
289  MEB::InArgs<Scalar> inArgs = wrapperModel_->createInArgs();
290  inArgs.set_x(x);
291  if (inArgs.supports(MEB::IN_ARG_x_dot)) inArgs.set_x_dot(xDot);
292  if (inArgs.supports(MEB::IN_ARG_t)) inArgs.set_t(time);
293  if (inArgs.supports(MEB::IN_ARG_step_size))
294  inArgs.set_step_size(p->timeStepSize_);
295  if (inArgs.supports(MEB::IN_ARG_alpha)) inArgs.set_alpha(Scalar(0.0));
296  if (inArgs.supports(MEB::IN_ARG_beta)) inArgs.set_beta(Scalar(0.0));
297 
298  MEB::OutArgs<Scalar> outArgs = wrapperModel_->createOutArgs();
299  outArgs.set_f(f);
300 
301  wrapperModel_->setForSolve(x, xDot, time, p);
302 
303  wrapperModel_->evalModel(inArgs, outArgs);
304 }
305 
306 template <class Scalar>
308  Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel verbLevel) const
309 {
310  out.setOutputToRootOnly(0);
311  out << "--- StepperImplicit ---\n";
312  out << " wrapperModel_ = " << wrapperModel_ << std::endl;
313  out << " solver_ = " << solver_ << std::endl;
314  out << " initialGuess_ = " << initialGuess_ << std::endl;
315  out << " zeroInitialGuess_ = " << Teuchos::toString(zeroInitialGuess_)
316  << std::endl;
317 }
318 
319 template <class Scalar>
321 {
322  out.setOutputToRootOnly(0);
323  bool isValidSetup = true;
324 
325  if (wrapperModel_->getAppModel() == Teuchos::null) {
326  isValidSetup = false;
327  out << "The application ModelEvaluator is not set!\n";
328  }
329 
330  if (wrapperModel_ == Teuchos::null) {
331  isValidSetup = false;
332  out << "The wrapper ModelEvaluator is not set!\n";
333  }
334 
335  if (solver_ == Teuchos::null) {
336  isValidSetup = false;
337  out << "The solver is not set!\n";
338  }
339 
340  if (solver_ != Teuchos::null) {
341  if (solver_->getModel() == Teuchos::null) {
342  isValidSetup = false;
343  out << "The solver's ModelEvaluator is not set!\n";
344  }
345  }
346 
347  return isValidSetup;
348 }
349 
350 template <class Scalar>
353 {
354  return this->getValidParametersBasicImplicit();
355 }
356 
357 template <class Scalar>
360 {
361  auto pl = this->getValidParametersBasic();
362  pl->template set<std::string>("Solver Name", this->getSolverName());
363  pl->template set<bool>("Zero Initial Guess", this->getZeroInitialGuess());
364  auto noxSolverPL = this->getSolver()->getParameterList();
365  auto solverPL = Teuchos::parameterList(this->getSolverName());
366  solverPL->set("NOX", *noxSolverPL);
367  pl->set(this->getSolverName(), *solverPL);
368 
369  return pl;
370 }
371 
372 template <class Scalar>
375 {
376  if (pl != Teuchos::null) {
377  // Can not validate because of optional Parameters, e.g., 'Solver Name'.
378  // pl->validateParametersAndSetDefaults(*this->getValidParameters());
379  this->setStepperValues(pl);
380  this->setZeroInitialGuess(pl->get<bool>("Zero Initial Guess", false));
381  }
382  this->setStepperSolverValues(pl);
383 }
384 
385 template <class Scalar>
388 {
389  if (pl != Teuchos::null) {
390  setDefaultSolver();
391  std::string solverName = pl->get<std::string>("Solver Name");
392  if (pl->isSublist(solverName)) {
393  auto solverPL = Teuchos::parameterList();
394  solverPL = Teuchos::sublist(pl, solverName);
395  this->setSolverName(solverName);
397  Teuchos::sublist(solverPL, "NOX", true);
398  getSolver()->setParameterList(noxPL);
399  }
400  }
401 }
402 
403 } // namespace Tempus
404 #endif // Tempus_StepperImplicit_impl_hpp
virtual Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const override
virtual void setSolver(Teuchos::RCP< Thyra::NonlinearSolverBase< Scalar > > solver) override
Set solver.
Evaluate residual for the implicit ODE.
virtual bool isValidSetup(Teuchos::FancyOStream &out) const override
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void setStepperImplicitValues(Teuchos::RCP< Teuchos::ParameterList > pl)
Set StepperImplicit member data from the ParameterList.
Teuchos::RCP< Teuchos::ParameterList > defaultSolverParameters()
Returns the default solver ParameterList for implicit Steppers.
virtual void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const override
const Thyra::SolveStatus< Scalar > solveImplicitODE(const Teuchos::RCP< Thyra::VectorBase< Scalar > > &x, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &xDot, const Scalar time, const Teuchos::RCP< ImplicitODEParameters< Scalar > > &p, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &y=Teuchos::null, const int index=-1)
Solve implicit ODE, f(x, xDot, t, p) = 0.
virtual void setModel(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &appModel) override
Set the model.
virtual void setInitialConditions(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory) override
Set the initial conditions and make them consistent.
void evaluateImplicitODE(Teuchos::RCP< Thyra::VectorBase< Scalar > > &f, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &x, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &xDot, const Scalar time, const Teuchos::RCP< ImplicitODEParameters< Scalar > > &p)
Evaluate implicit ODE residual, f(x, xDot, t, p).
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Stepper integrates second-order ODEs.
bool isSublist(const std::string &name) const
TEUCHOSCORE_LIB_DLL_EXPORT std::string toString(const EVerbosityLevel verbLevel)
void setStepperSolverValues(Teuchos::RCP< Teuchos::ParameterList > pl)
Set solver from ParameterList.
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
Solve for xDot keeping x constant (for ICs).
ESolveStatus solveStatus
Stepper integrates first-order ODEs.
Teuchos::RCP< Teuchos::ParameterList > getValidParametersBasicImplicit() const
void validImplicitODE_DAE(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &model)
Validate ME supports implicit ODE/DAE evaluation, f(xdot,x,t) [= 0].
A ModelEvaluator for residual evaluations given a state. This ModelEvaluator takes a state...
Solve for x and determine xDot from x.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
std::string toString(const T &t)