Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_UnitTest_BackwardEuler.cpp
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 
11 
12 #include "Tempus_StepperForwardEuler.hpp"
13 #include "Tempus_StepperBackwardEuler.hpp"
14 
21 
22 namespace Tempus_Unit_Test {
23 
25 using Teuchos::RCP;
26 using Teuchos::rcp;
27 using Teuchos::rcp_const_cast;
28 using Teuchos::rcp_dynamic_cast;
29 using Teuchos::sublist;
30 
31 // ************************************************************
32 // ************************************************************
33 TEUCHOS_UNIT_TEST(BackwardEuler, Default_Construction)
34 {
35  auto model = rcp(new Tempus_Test::SinCosModel<double>());
36 
37  // Default construction.
38  auto stepper = rcp(new Tempus::StepperBackwardEuler<double>());
39  stepper->setModel(model);
40  stepper->initialize();
41  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
42 
43  // Default values for construction.
44  auto modifier =
46  auto modifierX =
48  auto observer =
50  auto solver = rcp(new Thyra::NOXNonlinearSolver());
51  solver->setParameterList(Tempus::defaultSolverParameters());
52 
53  auto predictorStepper = rcp(new Tempus::StepperForwardEuler<double>());
54  predictorStepper->setModel(
55  model); // Can use the same model since both steppers are implicit ODEs.
56  predictorStepper->initialize();
57 
58  auto defaultStepper = rcp(new Tempus::StepperBackwardEuler<double>());
59  bool useFSAL = defaultStepper->getUseFSAL();
60  std::string ICConsistency = defaultStepper->getICConsistency();
61  bool ICConsistencyCheck = defaultStepper->getICConsistencyCheck();
62  bool zeroInitialGuess = defaultStepper->getZeroInitialGuess();
63 
64  // Test the set functions.
65  stepper->setAppAction(modifier);
66  stepper->initialize();
67  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
68  stepper->setAppAction(modifierX);
69  stepper->initialize();
70  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
71  stepper->setAppAction(observer);
72  stepper->initialize();
73  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
74  stepper->setSolver(solver);
75  stepper->initialize();
76  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
77  stepper->setPredictor(predictorStepper);
78  stepper->initialize();
79  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
80  stepper->setUseFSAL(useFSAL);
81  stepper->initialize();
82  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
83  stepper->setICConsistency(ICConsistency);
84  stepper->initialize();
85  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
86  stepper->setICConsistencyCheck(ICConsistencyCheck);
87  stepper->initialize();
88  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
89  stepper->setZeroInitialGuess(zeroInitialGuess);
90  stepper->initialize();
91  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
92 
93  // Full argument list construction.
95  model, solver, predictorStepper, useFSAL, ICConsistency,
96  ICConsistencyCheck, zeroInitialGuess, modifier));
97  TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized());
98 
99  // Test stepper properties.
100  TEUCHOS_ASSERT(stepper->getOrder() == 1);
101 }
102 
103 // ************************************************************
104 // ************************************************************
105 TEUCHOS_UNIT_TEST(BackwardEuler, StepperFactory_Construction)
106 {
107  auto model = rcp(new Tempus_Test::SinCosModel<double>());
108  testFactoryConstruction("Backward Euler", model);
109 }
110 
111 // ************************************************************
112 // ************************************************************
113 class StepperBackwardEulerModifierTest
114  : virtual public Tempus::StepperBackwardEulerModifierBase<double> {
115  public:
117  StepperBackwardEulerModifierTest()
118  : testBEGIN_STEP(false),
119  testBEFORE_SOLVE(false),
120  testAFTER_SOLVE(false),
121  testEND_STEP(false),
122  testCurrentValue(-0.99),
123  testWorkingValue(-0.99),
124  testDt(-1.5),
125  testName("")
126  {
127  }
128 
130  virtual ~StepperBackwardEulerModifierTest() {}
131 
133  virtual void modify(
137  double>::ACTION_LOCATION actLoc)
138  {
139  switch (actLoc) {
141  testBEGIN_STEP = true;
142  auto x = sh->getCurrentState()->getX();
143  testCurrentValue = get_ele(*(x), 0);
144  break;
145  }
147  testBEFORE_SOLVE = true;
148  testDt = sh->getWorkingState()->getTimeStep() / 10.0;
149  sh->getWorkingState()->setTimeStep(testDt);
150  break;
151  }
153  testAFTER_SOLVE = true;
154  testName = "Backward Euler - Modifier";
155  stepper->setStepperName(testName);
156  break;
157  }
159  testEND_STEP = true;
160  auto x = sh->getWorkingState()->getX();
161  testWorkingValue = get_ele(*(x), 0);
162  break;
163  }
164  default:
165  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
166  "Error - unknown action location.\n");
167  }
168  }
169 
170  bool testBEGIN_STEP;
171  bool testBEFORE_SOLVE;
172  bool testAFTER_SOLVE;
173  bool testEND_STEP;
174  double testCurrentValue;
175  double testWorkingValue;
176  double testDt;
177  std::string testName;
178 };
179 
180 TEUCHOS_UNIT_TEST(BackwardEuler, AppAction_Modifier)
181 {
184 
185  // Setup Stepper for field solve ----------------------------
186  auto stepper = rcp(new Tempus::StepperBackwardEuler<double>());
187  stepper->setModel(model);
188  auto modifier = rcp(new StepperBackwardEulerModifierTest());
189  stepper->setAppAction(modifier);
190  stepper->initialize();
191 
192  // Create a SolutionHistory.
193  auto solutionHistory = Tempus::createSolutionHistoryME(model);
194 
195  // Take one time step.
196  stepper->setInitialConditions(solutionHistory);
197  solutionHistory->initWorkingState();
198  double dt = 0.1;
199  solutionHistory->getWorkingState()->setTimeStep(dt);
200  stepper->takeStep(solutionHistory);
201 
202  // Testing that each ACTION_LOCATION has been called.
203  TEST_COMPARE(modifier->testBEGIN_STEP, ==, true);
204  TEST_COMPARE(modifier->testBEFORE_SOLVE, ==, true);
205  TEST_COMPARE(modifier->testAFTER_SOLVE, ==, true);
206  TEST_COMPARE(modifier->testEND_STEP, ==, true);
207 
208  // Testing that values can be set through the Modifier.
209  auto x = solutionHistory->getCurrentState()->getX();
210  TEST_FLOATING_EQUALITY(modifier->testCurrentValue, get_ele(*(x), 0), 1.0e-14);
211  x = solutionHistory->getWorkingState()->getX();
212  TEST_FLOATING_EQUALITY(modifier->testWorkingValue, get_ele(*(x), 0), 1.0e-14);
213  auto Dt = solutionHistory->getWorkingState()->getTimeStep();
214  TEST_FLOATING_EQUALITY(modifier->testDt, Dt, 1.0e-14);
215 
216  TEST_COMPARE(modifier->testName, ==, "Backward Euler - Modifier");
217 }
218 
219 // ************************************************************
220 // ************************************************************
221 class StepperBackwardEulerObserverTest
222  : virtual public Tempus::StepperBackwardEulerObserverBase<double> {
223  public:
225  StepperBackwardEulerObserverTest()
226  : testBEGIN_STEP(false),
227  testBEFORE_SOLVE(false),
228  testAFTER_SOLVE(false),
229  testEND_STEP(false),
230  testCurrentValue(-0.99),
231  testWorkingValue(-0.99),
232  testDt(-1.5),
233  testName("")
234  {
235  }
236 
238  virtual ~StepperBackwardEulerObserverTest() {}
239 
241  virtual void observe(
245  double>::ACTION_LOCATION actLoc)
246  {
247  switch (actLoc) {
249  testBEGIN_STEP = true;
250  auto x = sh->getCurrentState()->getX();
251  testCurrentValue = get_ele(*(x), 0);
252  break;
253  }
255  testBEFORE_SOLVE = true;
256  testDt = sh->getWorkingState()->getTimeStep();
257  break;
258  }
260  testAFTER_SOLVE = true;
261  testName = stepper->getStepperType();
262  break;
263  }
265  testEND_STEP = true;
266  auto x = sh->getWorkingState()->getX();
267  testWorkingValue = get_ele(*(x), 0);
268  break;
269  }
270  default:
271  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
272  "Error - unknown action location.\n");
273  }
274  }
275 
276  bool testBEGIN_STEP;
277  bool testBEFORE_SOLVE;
278  bool testAFTER_SOLVE;
279  bool testEND_STEP;
280  double testCurrentValue;
281  double testWorkingValue;
282  double testDt;
283  std::string testName;
284 };
285 
286 TEUCHOS_UNIT_TEST(BackwardEuler, AppAction_Observer)
287 {
290 
291  // Setup Stepper for field solve ----------------------------
292  auto stepper = rcp(new Tempus::StepperBackwardEuler<double>());
293  stepper->setModel(model);
294  auto observer = rcp(new StepperBackwardEulerObserverTest());
295  stepper->setAppAction(observer);
296  stepper->initialize();
297 
298  // Setup a SolutionHistory.
299  auto solutionHistory = Tempus::createSolutionHistoryME(model);
300 
301  // Take one time step.
302  stepper->setInitialConditions(solutionHistory);
303  solutionHistory->initWorkingState();
304  double dt = 0.1;
305  solutionHistory->getWorkingState()->setTimeStep(dt);
306  stepper->takeStep(solutionHistory);
307 
308  // Testing that each ACTION_LOCATION has been called.
309  TEST_COMPARE(observer->testBEGIN_STEP, ==, true);
310  TEST_COMPARE(observer->testBEFORE_SOLVE, ==, true);
311  TEST_COMPARE(observer->testAFTER_SOLVE, ==, true);
312  TEST_COMPARE(observer->testEND_STEP, ==, true);
313 
314  // Testing that values can be observed through the observer.
315  auto x = solutionHistory->getCurrentState()->getX();
316  TEST_FLOATING_EQUALITY(observer->testCurrentValue, get_ele(*(x), 0), 1.0e-14);
317  x = solutionHistory->getWorkingState()->getX();
318  TEST_FLOATING_EQUALITY(observer->testWorkingValue, get_ele(*(x), 0), 1.0e-14);
319  TEST_FLOATING_EQUALITY(observer->testDt, dt, 1.0e-14);
320 
321  TEST_COMPARE(observer->testName, ==, "Backward Euler");
322 }
323 
324 // ************************************************************
325 // ************************************************************
326 class StepperBackwardEulerModifierXTest
327  : virtual public Tempus::StepperBackwardEulerModifierXBase<double> {
328  public:
330  StepperBackwardEulerModifierXTest()
331  : testX_BEGIN_STEP(false),
332  testX_BEFORE_SOLVE(false),
333  testX_AFTER_SOLVE(false),
334  testXDOT_END_STEP(false),
335  testX(-0.99),
336  testXDot(-0.99),
337  testDt(-1.5),
338  testTime(-1.5)
339  {
340  }
341 
343  virtual ~StepperBackwardEulerModifierXTest() {}
344 
347  const double time, const double dt,
349  double>::MODIFIER_TYPE modType)
350  {
351  switch (modType) {
353  testX_BEGIN_STEP = true;
354  testX = get_ele(*(x), 0);
355  break;
356  }
358  testX_BEFORE_SOLVE = true;
359  testDt = dt;
360  break;
361  }
363  testX_AFTER_SOLVE = true;
364  testTime = time;
365  break;
366  }
368  testXDOT_END_STEP = true;
369  testXDot = get_ele(*(x), 0);
370  break;
371  }
372  default:
373  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
374  "Error - unknown action location.\n");
375  }
376  }
377 
378  bool testX_BEGIN_STEP;
379  bool testX_BEFORE_SOLVE;
380  bool testX_AFTER_SOLVE;
381  bool testXDOT_END_STEP;
382  double testX;
383  double testXDot;
384  double testDt;
385  double testTime;
386 };
387 
388 TEUCHOS_UNIT_TEST(BackwardEuler, AppAction_ModifierX)
389 {
392 
393  // Setup Stepper for field solve ----------------------------
394  auto stepper = rcp(new Tempus::StepperBackwardEuler<double>());
395  stepper->setModel(model);
396  auto modifierX = rcp(new StepperBackwardEulerModifierXTest());
397  stepper->setAppAction(modifierX);
398  stepper->initialize();
399 
400  // Setup a SolutionHistory.
401  auto solutionHistory = Tempus::createSolutionHistoryME(model);
402 
403  // Take one time step.
404  stepper->setInitialConditions(solutionHistory);
405  solutionHistory->initWorkingState();
406  double dt = 0.1;
407  solutionHistory->getWorkingState()->setTimeStep(dt);
408  stepper->takeStep(solutionHistory);
409 
410  // Testing that each ACTION_LOCATION has been called.
411  TEST_COMPARE(modifierX->testX_BEGIN_STEP, ==, true);
412  TEST_COMPARE(modifierX->testX_BEFORE_SOLVE, ==, true);
413  TEST_COMPARE(modifierX->testX_AFTER_SOLVE, ==, true);
414  TEST_COMPARE(modifierX->testXDOT_END_STEP, ==, true);
415 
416  // Testing that values can be set through the Modifier.
417  auto x = solutionHistory->getCurrentState()->getX();
418  TEST_FLOATING_EQUALITY(modifierX->testX, get_ele(*(x), 0), 1.0e-14);
419  // Temporary memory for xDot is not guarranteed to exist outside the Stepper.
420  auto xDot = solutionHistory->getWorkingState()->getXDot();
421  if (xDot == Teuchos::null) xDot = stepper->getStepperXDot();
422 
423  TEST_FLOATING_EQUALITY(modifierX->testXDot, get_ele(*(xDot), 0), 1.0e-14);
424  auto Dt = solutionHistory->getWorkingState()->getTimeStep();
425  TEST_FLOATING_EQUALITY(modifierX->testDt, Dt, 1.0e-14);
426 
427  auto time = solutionHistory->getWorkingState()->getTime();
428  TEST_FLOATING_EQUALITY(modifierX->testTime, time, 1.0e-14);
429 }
430 
431 // ************************************************************
432 // ************************************************************
434 {
435  // Read params from .xml file
436  RCP<ParameterList> pList =
437  Teuchos::getParametersFromXmlFile("Tempus_BackwardEuler_SinCos.xml");
438 
439  // Setup the SinCosModel
440  RCP<ParameterList> scm_pl = sublist(pList, "SinCosModel", true);
441  auto model = rcp(new Tempus_Test::SinCosModel<double>(scm_pl));
442 
443  RCP<ParameterList> tempusPL = sublist(pList, "Tempus", true);
444 
445  // Test constructor IntegratorBasic(tempusPL, model)
446  {
448  Tempus::createIntegratorBasic<double>(tempusPL, model);
449 
450  RCP<ParameterList> stepperPL = sublist(tempusPL, "Default Stepper", true);
451  RCP<const ParameterList> defaultPL =
452  integrator->getStepper()->getValidParameters();
453 
454  bool pass = haveSameValuesSorted(*stepperPL, *defaultPL, true);
455  if (!pass) {
456  out << std::endl;
457  out << "stepperPL -------------- \n"
458  << *stepperPL << std::endl;
459  out << "defaultPL -------------- \n"
460  << *defaultPL << std::endl;
461  }
462  TEST_ASSERT(pass)
463  }
464 
465  // Test constructor IntegratorBasic(model, stepperType)
466  {
468  Tempus::createIntegratorBasic<double>(model,
469  std::string("Backward Euler"));
470 
471  RCP<ParameterList> stepperPL = sublist(tempusPL, "Default Stepper", true);
472  // Match Predictor for comparison
473  stepperPL->set("Predictor Stepper Type", "None");
474  RCP<const ParameterList> defaultPL =
475  integrator->getStepper()->getValidParameters();
476 
477  bool pass = haveSameValuesSorted(*stepperPL, *defaultPL, true);
478  if (!pass) {
479  out << std::endl;
480  out << "stepperPL -------------- \n"
481  << *stepperPL << std::endl;
482  out << "defaultPL -------------- \n"
483  << *defaultPL << std::endl;
484  }
485  TEST_ASSERT(pass)
486  }
487 }
488 
489 // ************************************************************
490 // ************************************************************
491 TEUCHOS_UNIT_TEST(BackwardEuler, ConstructingFromDefaults)
492 {
493  double dt = 0.1;
494  std::vector<std::string> options;
495  options.push_back("Default Parameters");
496  options.push_back("ICConsistency and Check");
497 
498  for (const auto& option : options) {
499  // Read params from .xml file
500  RCP<ParameterList> pList =
501  Teuchos::getParametersFromXmlFile("Tempus_BackwardEuler_SinCos.xml");
502  RCP<ParameterList> pl = sublist(pList, "Tempus", true);
503 
504  // Setup the SinCosModel
505  RCP<ParameterList> scm_pl = sublist(pList, "SinCosModel", true);
506  // RCP<SinCosModel<double> > model = sineCosineModel(scm_pl);
507  auto model = rcp(new Tempus_Test::SinCosModel<double>(scm_pl));
508 
509  // Setup Stepper for field solve ----------------------------
510  auto stepper = rcp(new Tempus::StepperBackwardEuler<double>());
511  stepper->setModel(model);
512  if (option == "ICConsistency and Check") {
513  stepper->setICConsistency("Consistent");
514  stepper->setICConsistencyCheck(true);
515  }
516  stepper->initialize();
517 
518  // Setup TimeStepControl ------------------------------------
519  auto timeStepControl = rcp(new Tempus::TimeStepControl<double>());
520  ParameterList tscPL =
521  pl->sublist("Default Integrator").sublist("Time Step Control");
522  timeStepControl->setInitIndex(tscPL.get<int>("Initial Time Index"));
523  timeStepControl->setInitTime(tscPL.get<double>("Initial Time"));
524  timeStepControl->setFinalTime(tscPL.get<double>("Final Time"));
525  timeStepControl->setInitTimeStep(dt);
526  timeStepControl->initialize();
527 
528  // Setup initial condition SolutionState --------------------
529  auto inArgsIC = model->getNominalValues();
530  auto icSolution =
531  rcp_const_cast<Thyra::VectorBase<double> >(inArgsIC.get_x());
532  auto icState = Tempus::createSolutionStateX(icSolution);
533  icState->setTime(timeStepControl->getInitTime());
534  icState->setIndex(timeStepControl->getInitIndex());
535  icState->setTimeStep(0.0);
536  icState->setOrder(stepper->getOrder());
537  icState->setSolutionStatus(Tempus::Status::PASSED); // ICs are passing.
538 
539  // Setup SolutionHistory ------------------------------------
540  auto solutionHistory = rcp(new Tempus::SolutionHistory<double>());
541  solutionHistory->setName("Forward States");
542  solutionHistory->setStorageType(Tempus::STORAGE_TYPE_STATIC);
543  solutionHistory->setStorageLimit(2);
544  solutionHistory->addState(icState);
545 
546  // Ensure ICs are consistent and stepper memory is set (e.g., xDot is set).
547  stepper->setInitialConditions(solutionHistory);
548 
549  // Setup Integrator -----------------------------------------
551  Tempus::createIntegratorBasic<double>();
552  integrator->setStepper(stepper);
553  integrator->setTimeStepControl(timeStepControl);
554  integrator->setSolutionHistory(solutionHistory);
555  // integrator->setObserver(...);
556  integrator->initialize();
557 
558  // Integrate to timeMax
559  bool integratorStatus = integrator->advanceTime();
560  TEST_ASSERT(integratorStatus)
561 
562  // Test if at 'Final Time'
563  double time = integrator->getTime();
564  double timeFinal = pl->sublist("Default Integrator")
565  .sublist("Time Step Control")
566  .get<double>("Final Time");
567  TEST_FLOATING_EQUALITY(time, timeFinal, 1.0e-14);
568 
569  // Time-integrated solution and the exact solution
570  RCP<Thyra::VectorBase<double> > x = integrator->getX();
572  model->getExactSolution(time).get_x();
573 
574  // Calculate the error
575  RCP<Thyra::VectorBase<double> > xdiff = x->clone_v();
576  Thyra::V_StVpStV(xdiff.ptr(), 1.0, *x_exact, -1.0, *(x));
577 
578  // Check the order and intercept
579  out << " Stepper = " << stepper->description() << " with " << option
580  << std::endl;
581  out << " =========================" << std::endl;
582  out << " Exact solution : " << get_ele(*(x_exact), 0) << " "
583  << get_ele(*(x_exact), 1) << std::endl;
584  out << " Computed solution: " << get_ele(*(x), 0) << " "
585  << get_ele(*(x), 1) << std::endl;
586  out << " Difference : " << get_ele(*(xdiff), 0) << " "
587  << get_ele(*(xdiff), 1) << std::endl;
588  out << " =========================" << std::endl;
589  TEST_FLOATING_EQUALITY(get_ele(*(x), 0), 0.798923, 1.0e-4);
590  TEST_FLOATING_EQUALITY(get_ele(*(x), 1), 0.516729, 1.0e-4);
591  }
592 }
593 
594 } // namespace Tempus_Unit_Test
Teuchos::RCP< SolutionState< Scalar > > createSolutionStateX(const Teuchos::RCP< Thyra::VectorBase< Scalar > > &x, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &xdot=Teuchos::null, const Teuchos::RCP< Thyra::VectorBase< Scalar > > &xdotdot=Teuchos::null)
Nonmember constructor from non-const solution vectors, x.
void testFactoryConstruction(std::string stepperType, const Teuchos::RCP< const Thyra::ModelEvaluator< double > > &model)
Unit test utility for Stepper construction through StepperFactory.
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
#define TEST_COMPARE(v1, comp, v2)
#define TEST_FLOATING_EQUALITY(v1, v2, tol)
#define TEST_ASSERT(v1)
Sine-Cosine model problem from Rythmos. This is a canonical Sine-Cosine differential equation with a...
Teuchos::RCP< Teuchos::ParameterList > defaultSolverParameters()
Returns the default solver ParameterList for implicit Steppers.
virtual void modify(Teuchos::RCP< Thyra::VectorBase< double > >, const double, const double, const MODIFIER_TYPE modType)=0
Modify solution based on the MODIFIER_TYPE.
Application Action for StepperBackwardEuler.
Teuchos::RCP< SolutionHistory< Scalar > > createSolutionHistoryME(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &model)
Nonmember contructor from a Thyra ModelEvaluator.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Ptr< T > ptr() const
TEUCHOS_UNIT_TEST(BackwardEuler, Default_Construction)
TimeStepControl manages the time step size. There several mechanisms that effect the time step size a...
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Keep a fix number of states.
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
#define TEUCHOS_ASSERT(assertion_test)
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)