Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_TimeStepControl_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_TimeStepControl_impl_hpp
10 #define Tempus_TimeStepControl_impl_hpp
11 
12 #include "Teuchos_TimeMonitor.hpp"
13 
18 #include "Tempus_TimeEventRange.hpp"
19 #include "Tempus_TimeEventRangeIndex.hpp"
20 #include "Tempus_TimeEventList.hpp"
21 #include "Tempus_TimeEventListIndex.hpp"
22 
23 namespace Tempus {
24 
25 template <class Scalar>
27  : isInitialized_(false),
28  initTime_(0.0),
29  finalTime_(1.0e+99),
30  minTimeStep_(0.0),
31  initTimeStep_(1.0e+99),
32  maxTimeStep_(1.0e+99),
33  initIndex_(0),
34  finalIndex_(1000000),
35  maxAbsError_(1.0e-08),
36  maxRelError_(1.0e-08),
37  maxFailures_(10),
38  maxConsecFailures_(5),
39  numTimeSteps_(-1),
40  printDtChanges_(true),
41  teAdjustedDt_(false),
42  dtAfterTimeEvent_(0.0)
43 {
45  setTimeEvents();
46  this->initialize();
47 }
48 
49 template <class Scalar>
51  Scalar initTime, Scalar finalTime, Scalar minTimeStep, Scalar initTimeStep,
52  Scalar maxTimeStep, int initIndex, int finalIndex, Scalar maxAbsError,
53  Scalar maxRelError, int maxFailures, int maxConsecFailures,
54  int numTimeSteps, bool printDtChanges, bool outputExactly,
55  std::vector<int> outputIndices, std::vector<Scalar> outputTimes,
56  int outputIndexInterval, Scalar outputTimeInterval,
58  Teuchos::RCP<TimeStepControlStrategy<Scalar>> stepControlStrategy)
59  : isInitialized_(false),
60  initTime_(initTime),
61  finalTime_(finalTime),
62  minTimeStep_(minTimeStep),
63  initTimeStep_(initTimeStep),
64  maxTimeStep_(maxTimeStep),
65  initIndex_(initIndex),
66  finalIndex_(finalIndex),
67  maxAbsError_(maxAbsError),
68  maxRelError_(maxRelError),
69  maxFailures_(maxFailures),
70  maxConsecFailures_(maxConsecFailures),
71  printDtChanges_(printDtChanges),
72  teAdjustedDt_(false),
73  dtAfterTimeEvent_(0.0)
74 {
75  using Teuchos::rcp;
76 
77  setTimeStepControlStrategy(stepControlStrategy);
78  setNumTimeSteps(numTimeSteps);
79 
80  auto tec = rcp(new TimeEventComposite<Scalar>());
81  tec->setName("Time Step Control Events");
82  auto tes = timeEvent->getTimeEvents();
83  for (auto& e : tes) tec->add(e);
84 
85  // Add a range of times.
86  auto teRange =
87  rcp(new TimeEventRange<Scalar>(initTime, finalTime, outputTimeInterval,
88  "Output Time Interval", outputExactly));
89  tec->add(teRange);
90 
91  // Add a list of times.
92  if (!outputTimes.empty())
93  tec->add(rcp(new TimeEventList<Scalar>(outputTimes, "Output Time List",
94  outputExactly)));
95 
96  // Add a range of indices.
97  tec->add(rcp(new TimeEventRangeIndex<Scalar>(
98  initIndex, finalIndex, outputIndexInterval, "Output Index Interval")));
99 
100  // Add a list of indices.
101  if (!outputTimes.empty())
102  tec->add(rcp(
103  new TimeEventListIndex<Scalar>(outputIndices, "Output Index List")));
104 
105  setTimeEvents(tec);
106 
107  this->initialize();
108 }
109 
110 template <class Scalar>
112 {
114  (getInitTime() > getFinalTime()), std::logic_error,
115  "Error - Inconsistent time range.\n"
116  " (timeMin = "
117  << getInitTime() << ") > (timeMax = " << getFinalTime() << ")\n");
118 
120  (getMinTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
121  std::logic_error,
122  "Error - Negative minimum time step. dtMin = " << getMinTimeStep() << ")\n");
124  (getMaxTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
125  std::logic_error,
126  "Error - Negative maximum time step. dtMax = " << getMaxTimeStep() << ")\n");
128  (getMinTimeStep() > getMaxTimeStep()), std::logic_error,
129  "Error - Inconsistent time step range.\n"
130  << " (dtMin = "
131  << getMinTimeStep() << ") > (dtMax = " << getMaxTimeStep() << ")\n");
133  (getInitTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
134  std::logic_error,
135  "Error - Negative initial time step. dtInit = " << getInitTimeStep() << ")\n");
136  TEUCHOS_TEST_FOR_EXCEPTION((getInitTimeStep() < getMinTimeStep() ||
137  getInitTimeStep() > getMaxTimeStep()),
138  std::out_of_range,
139  "Error - Initial time step is out of range.\n"
140  << " [dtMin, dtMax] = [" << getMinTimeStep()
141  << ", " << getMaxTimeStep() << "]\n"
142  << " dtInit = " << getInitTimeStep()
143  << "\n");
144 
146  (getInitIndex() > getFinalIndex()), std::logic_error,
147  "Error - Inconsistent time index range.\n"
148  " (iStepMin = "
149  << getInitIndex() << ") > (iStepMax = " << getFinalIndex() << ")\n");
150 
152  (getMaxAbsError() < Teuchos::ScalarTraits<Scalar>::zero()),
153  std::logic_error,
154  "Error - Negative maximum time step. errorMaxAbs = " << getMaxAbsError() << ")\n");
156  (getMaxRelError() < Teuchos::ScalarTraits<Scalar>::zero()),
157  std::logic_error,
158  "Error - Negative maximum time step. errorMaxRel = " << getMaxRelError() << ")\n");
159 
160  TEUCHOS_TEST_FOR_EXCEPTION((stepControlStrategy_ == Teuchos::null),
161  std::logic_error, "Error - Strategy is unset!\n");
162 
163  stepControlStrategy_->initialize();
164 
166  (getStepType() != "Constant" && getStepType() != "Variable"),
167  std::out_of_range,
168  "Error - 'Step Type' does not equal one of these:\n"
169  << " 'Constant' - Integrator will take constant time step sizes.\n"
170  << " 'Variable' - Integrator will allow changes to the time step "
171  << "size.\n"
172  << " stepType = " << getStepType() << "\n");
173 
174  isInitialized_ = true; // Only place where this is set to true!
175 }
176 
177 template <class Scalar>
178 void TimeStepControl<Scalar>::printDtChanges(int istep, Scalar dt_old,
179  Scalar dt_new,
180  std::string reason) const
181 {
182  if (!getPrintDtChanges()) return;
183 
184  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
185  out->setOutputToRootOnly(0);
186  Teuchos::OSTab ostab(out, 0, "printDtChanges");
187 
188  std::stringstream message;
189  message << std::scientific << std::setw(6) << std::setprecision(3) << istep
190  << " * (dt = " << std::setw(9) << std::setprecision(3) << dt_old
191  << ", new = " << std::setw(9) << std::setprecision(3) << dt_new
192  << ") " << reason << std::endl;
193  *out << message.str();
194 }
195 
196 template <class Scalar>
198 {
199  if (!isInitialized_) {
200  this->describe(*(this->getOStream()), Teuchos::VERB_MEDIUM);
202  !isInitialized_, std::logic_error,
203  "Error - " << this->description() << " is not initialized!");
204  }
205 }
206 
207 template <class Scalar>
209  const Teuchos::RCP<SolutionHistory<Scalar>>& solutionHistory,
210  Status& integratorStatus)
211 {
212  using Teuchos::RCP;
213 
214  checkInitialized();
215 
216  TEMPUS_FUNC_TIME_MONITOR("Tempus::TimeStepControl::setNextTimeStep()");
217  {
218  RCP<SolutionState<Scalar>> workingState =
219  solutionHistory->getWorkingState();
220  const Scalar lastTime = solutionHistory->getCurrentState()->getTime();
221  const int iStep = workingState->getIndex();
222  Scalar dt = workingState->getTimeStep();
223  Scalar time = workingState->getTime();
224 
225  RCP<StepperState<Scalar>> stepperState = workingState->getStepperState();
226 
227  // If last time step was adjusted for time event, reinstate previous dt.
228  if (getStepType() == "Variable") {
229  if (teAdjustedDt_ == true) {
230  printDtChanges(iStep, dt, dtAfterTimeEvent_,
231  "Reset dt after time event.");
232  dt = dtAfterTimeEvent_;
233  time = lastTime + dt;
234  teAdjustedDt_ = false;
235  dtAfterTimeEvent_ = 0.0;
236  }
237 
238  if (dt <= 0.0) {
239  printDtChanges(iStep, dt, getInitTimeStep(), "Reset dt to initial dt.");
240  dt = getInitTimeStep();
241  time = lastTime + dt;
242  }
243 
244  if (dt < getMinTimeStep()) {
245  printDtChanges(iStep, dt, getMinTimeStep(), "Reset dt to minimum dt.");
246  dt = getMinTimeStep();
247  time = lastTime + dt;
248  }
249  }
250 
251  // Update dt for the step control strategy to be informed
252  workingState->setTimeStep(dt);
253  workingState->setTime(time);
254 
255  // Call the step control strategy (to update dt if needed)
256  stepControlStrategy_->setNextTimeStep(*this, solutionHistory,
257  integratorStatus);
258 
259  // Get the dt (It was probably changed by stepControlStrategy_.)
260  dt = workingState->getTimeStep();
261  time = workingState->getTime();
262 
263  if (getStepType() == "Variable") {
264  if (dt < getMinTimeStep()) { // decreased below minimum dt
265  printDtChanges(iStep, dt, getMinTimeStep(),
266  "dt is too small. Resetting to minimum dt.");
267  dt = getMinTimeStep();
268  time = lastTime + dt;
269  }
270  if (dt > getMaxTimeStep()) { // increased above maximum dt
271  printDtChanges(iStep, dt, getMaxTimeStep(),
272  "dt is too large. Resetting to maximum dt.");
273  dt = getMaxTimeStep();
274  time = lastTime + dt;
275  }
276  }
277 
278  // Check if this index is a TimeEvent and whether it is an output event.
279  bool outputDueToIndex = false;
280  std::vector<Teuchos::RCP<TimeEventBase<Scalar>>> constrainingTEs;
281  if (timeEvent_->isIndex(iStep, constrainingTEs)) {
282  for (auto& e : constrainingTEs) {
283  if (e->getName() == "Output Index Interval" ||
284  e->getName() == "Output Index List") {
285  outputDueToIndex = true;
286  }
287  }
288  }
289 
290  // Check if during this time step is there a TimeEvent.
291  Scalar endTime = lastTime + dt;
292  // For "Variable", need to check t+dt+t_min in case we need to split
293  // the time step into two steps (e.g., time step lands within dt_min).
294  if (getStepType() == "Variable") endTime = lastTime + dt + getMinTimeStep();
295 
296  bool teThisStep =
297  timeEvent_->eventInRange(lastTime, endTime, constrainingTEs);
298 
299  bool outputDueToTime = false;
300  Scalar tone = endTime;
301  bool landOnExactly = false;
302  if (teThisStep) {
303  for (auto& e : constrainingTEs) {
304  if (e->getName() == "Output Time Interval" ||
305  e->getName() == "Output Time List") {
306  outputDueToTime = true;
307  }
308 
309  if (e->getLandOnExactly() == true) {
310  landOnExactly = true;
311  tone = e->timeOfNextEvent(lastTime);
312  break;
313  }
314  }
315  }
316 
317  Scalar reltol = 1.0e-6;
318  if (teThisStep && getStepType() == "Variable") {
319  if (landOnExactly == true) {
320  // Adjust time step to hit TimeEvent.
321  if (time > tone) {
322  // Next TimeEvent is not near next time. It is more than
323  // getMinTimeStep() away from it.
324  printDtChanges(iStep, dt, tone - lastTime,
325  "Adjusting dt to hit the next TimeEvent.");
326  teAdjustedDt_ = true;
327  dtAfterTimeEvent_ = dt;
328  dt = tone - lastTime;
329  time = lastTime + dt;
330  }
331  else if (std::fabs(time - tone) < reltol * std::fabs(time)) {
332  // Next TimeEvent IS VERY near next time. It is less than
333  // reltol away from it, e.g., adjust for numerical roundoff.
334  printDtChanges(
335  iStep, dt, tone - lastTime,
336  "Adjusting dt for numerical roundoff to hit the next TimeEvent.");
337  teAdjustedDt_ = true;
338  dtAfterTimeEvent_ = dt;
339  dt = tone - lastTime;
340  time = lastTime + dt;
341  }
342  else if (std::fabs(time + getMinTimeStep() - tone) <
343  reltol * std::fabs(tone)) {
344  // Next TimeEvent IS near next time. It is less than
345  // getMinTimeStep() away from it. Take two time steps
346  // to get to next TimeEvent.
347  printDtChanges(
348  iStep, dt, (tone - lastTime) / 2.0,
349  "The next TimeEvent is within the minimum dt of the next time. "
350  "Adjusting dt to take two steps.");
351  dt = (tone - lastTime) / 2.0;
352  time = lastTime + dt;
353  // This time step is no longer an output step due the time constraint.
354  outputDueToTime = false;
355  }
356  }
357  }
358 
359  // Adjust time step to hit final time or correct for small
360  // numerical differences.
361  if (getStepType() == "Variable") {
362  if ((lastTime + dt > getFinalTime()) ||
363  (std::fabs((lastTime + dt - getFinalTime())) <
364  reltol * std::fabs(lastTime + dt))) {
365  printDtChanges(iStep, dt, getFinalTime() - lastTime,
366  "Adjusting dt to hit final time.");
367  dt = getFinalTime() - lastTime;
368  time = lastTime + dt;
369  }
370  }
371 
372  // Check for negative time step.
374  dt <= Scalar(0.0), std::out_of_range,
375  "Error - Time step is not positive. dt = " << dt << "\n");
376 
377  // Time step always needs to keep time within range.
379  (lastTime + dt < getInitTime()), std::out_of_range,
380  "Error - Time step does not move time INTO time range.\n"
381  << " [timeMin, timeMax] = ["
382  << getInitTime() << ", " << getFinalTime()
383  << "]\n T + dt = "
384  << lastTime << " + " << dt << " = " << lastTime + dt << "\n");
385 
386  if (getStepType() == "Variable") {
388  (lastTime + dt > getFinalTime()), std::out_of_range,
389  "Error - Time step move time OUT OF time range.\n"
390  << " [timeMin, timeMax] = ["
391  << getInitTime() << ", " << getFinalTime()
392  << "]\n T + dt = "
393  << lastTime << " + " << dt << " = " << lastTime + dt << "\n");
394  }
395 
396  workingState->setTimeStep(dt);
397  workingState->setTime(time);
398  workingState->setOutput(outputDueToIndex || outputDueToTime);
399  }
400  return;
401 }
402 
404 template <class Scalar>
405 bool TimeStepControl<Scalar>::timeInRange(const Scalar time) const
406 {
407  // Get absolute tolerance 1.0e-(i+14), i.e., 14 digits of accuracy.
408  const int relTol = 14;
409  const int i = (getInitTime() == 0)
410  ? 0
411  : 1 + (int)std::floor(std::log10(std::fabs(getInitTime())));
412  const Scalar absTolInit = std::pow(10, i - relTol);
413  const int j =
414  (getFinalTime() == 0)
415  ? 0
416  : 1 + (int)std::floor(std::log10(std::fabs(getFinalTime())));
417  const Scalar absTolFinal = std::pow(10, j - relTol);
418 
419  const bool test1 = getInitTime() - absTolInit <= time;
420  const bool test2 = time < getFinalTime() - absTolFinal;
421 
422  return (test1 && test2);
423 }
424 
426 template <class Scalar>
427 bool TimeStepControl<Scalar>::indexInRange(const int iStep) const
428 {
429  bool iir = (getInitIndex() <= iStep && iStep < getFinalIndex());
430  return iir;
431 }
432 
433 template <class Scalar>
435 {
436  TEUCHOS_TEST_FOR_EXCEPTION((stepControlStrategy_ == Teuchos::null),
437  std::logic_error,
438  "Error - getStepType() - Strategy is unset!\n");
439  return stepControlStrategy_->getStepType();
440 }
441 
442 template <class Scalar>
444 {
445  auto event = timeEvent_->find("Output Time Interval");
446  if (event != Teuchos::null) return event->getLandOnExactly();
447 
448  event = timeEvent_->find("Output Time List");
449  if (event != Teuchos::null) return event->getLandOnExactly();
450 
451  return true;
452 }
453 
454 template <class Scalar>
456 {
457  std::vector<int> indices;
458  if (timeEvent_->find("Output Index List") == Teuchos::null) return indices;
459  auto teli = Teuchos::rcp_dynamic_cast<TimeEventListIndex<Scalar>>(
460  timeEvent_->find("Output Index List"));
461  return teli->getIndexList();
462 }
463 
464 template <class Scalar>
465 std::vector<Scalar> TimeStepControl<Scalar>::getOutputTimes() const
466 {
467  std::vector<Scalar> times;
468  if (timeEvent_->find("Output Time List") == Teuchos::null) return times;
469  auto tel = Teuchos::rcp_dynamic_cast<TimeEventList<Scalar>>(
470  timeEvent_->find("Output Time List"));
471  return tel->getTimeList();
472 }
473 
474 template <class Scalar>
476 {
477  if (timeEvent_->find("Output Index Interval") == Teuchos::null)
478  return 1000000;
479  auto teri = Teuchos::rcp_dynamic_cast<TimeEventRangeIndex<Scalar>>(
480  timeEvent_->find("Output Index Interval"));
481  return teri->getIndexStride();
482 }
483 
484 template <class Scalar>
486 {
487  if (timeEvent_->find("Output Time Interval") == Teuchos::null) return 1.0e+99;
488  auto ter = Teuchos::rcp_dynamic_cast<TimeEventRange<Scalar>>(
489  timeEvent_->find("Output Time Interval"));
490  return ter->getTimeStride();
491 }
492 
493 template <class Scalar>
495 {
496  TEUCHOS_TEST_FOR_EXCEPTION((getStepType() != "Constant"), std::out_of_range,
497  "Error - Can only use setNumTimeSteps() when "
498  "'Step Type' == 'Constant'.\n");
499 
500  numTimeSteps_ = numTimeSteps;
501  if (numTimeSteps_ >= 0) {
502  setFinalIndex(getInitIndex() + numTimeSteps_);
503  Scalar initTimeStep;
504  if (numTimeSteps_ == 0)
505  initTimeStep = Scalar(0.0);
506  else
507  initTimeStep = (getFinalTime() - getInitTime()) / numTimeSteps_;
508  setInitTimeStep(initTimeStep);
509  setMinTimeStep(initTimeStep);
510  setMaxTimeStep(initTimeStep);
511 
512  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
513  out->setOutputToRootOnly(0);
514  Teuchos::OSTab ostab(out, 1, "setNumTimeSteps");
515  *out << "Warning - setNumTimeSteps() Setting 'Number of Time Steps' = "
516  << getNumTimeSteps() << " Set the following parameters: \n"
517  << " 'Final Time Index' = " << getFinalIndex() << "\n"
518  << " 'Initial Time Step' = " << getInitTimeStep() << "\n"
519  << " 'Step Type' = " << getStepType() << std::endl;
520 
521  isInitialized_ = false;
522  }
523 }
524 
525 template <class Scalar>
527 {
528  auto event = timeEvent_->find("Output Time Interval");
529  if (event != Teuchos::null) {
530  auto ter = Teuchos::rcp_dynamic_cast<TimeEventRange<Scalar>>(event);
531  ter->setLandOnExactly(b);
532  }
533  event = timeEvent_->find("Output Time List");
534  if (event != Teuchos::null) {
535  auto tel = Teuchos::rcp_dynamic_cast<TimeEventList<Scalar>>(event);
536  tel->setLandOnExactly(b);
537  }
538 }
539 
540 template <class Scalar>
541 void TimeStepControl<Scalar>::setOutputIndices(std::vector<int> outputIndices)
542 {
544  outputIndices, "Output Index List")));
545  isInitialized_ = false;
546 }
547 
548 template <class Scalar>
549 void TimeStepControl<Scalar>::setOutputTimes(std::vector<Scalar> outputTimes)
550 {
551  timeEvent_->add(Teuchos::rcp(new Tempus::TimeEventList<Scalar>(
552  outputTimes, "Output Time List", getOutputExactly())));
553  isInitialized_ = false;
554 }
555 
556 template <class Scalar>
558 {
559  timeEvent_->add(Teuchos::rcp(new TimeEventRangeIndex<Scalar>(
560  getInitIndex(), getFinalIndex(), i, "Output Index Interval")));
561  isInitialized_ = false;
562 }
563 
564 template <class Scalar>
566 {
567  timeEvent_->add(Teuchos::rcp(
568  new TimeEventRange<Scalar>(getInitTime(), getFinalTime(), t,
569  "Output Time Interval", getOutputExactly())));
570  isInitialized_ = false;
571 }
572 
573 template <class Scalar>
576 {
577  using Teuchos::rcp;
578 
579  if (timeEvent != Teuchos::null) {
580  timeEvent_ = timeEvent;
581  }
582  else {
583  auto tec = rcp(new TimeEventComposite<Scalar>());
584  tec->setName("Time Step Control Events");
585  tec->add(rcp(new TimeEventRangeIndex<Scalar>(
586  getInitIndex(), getFinalIndex(), 1000000, "Output Index Interval")));
587  tec->add(rcp(new TimeEventRange<Scalar>(
588  getInitTime(), getFinalTime(), 1.0e+99, "Output Time Interval", true)));
589  timeEvent_ = tec;
590  }
591  isInitialized_ = false;
592 }
593 
594 template <class Scalar>
597 {
598  using Teuchos::rcp;
599 
600  if (tscs != Teuchos::null) {
601  stepControlStrategy_ = tscs;
602  }
603  else {
604  stepControlStrategy_ =
605  rcp(new TimeStepControlStrategyConstant<Scalar>(getInitTimeStep()));
606  }
607  isInitialized_ = false;
608 }
609 
610 template <class Scalar>
612 {
613  std::string name = "Tempus::TimeStepControl";
614  return (name);
615 }
616 
617 template <class Scalar>
619  Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel verbLevel) const
620 {
621  auto l_out = Teuchos::fancyOStream(out.getOStream());
622  Teuchos::OSTab ostab(*l_out, 2, this->description());
623  l_out->setOutputToRootOnly(0);
624 
625  *l_out << "\n--- " << this->description() << " ---" << std::endl;
626 
627  if (Teuchos::as<int>(verbLevel) >= Teuchos::as<int>(Teuchos::VERB_MEDIUM)) {
628  std::vector<int> idx = getOutputIndices();
629  std::ostringstream listIdx;
630  if (!idx.empty()) {
631  for (std::size_t i = 0; i < idx.size() - 1; ++i)
632  listIdx << idx[i] << ", ";
633  listIdx << idx[idx.size() - 1];
634  }
635 
636  std::vector<Scalar> times = getOutputTimes();
637  std::ostringstream listTimes;
638  if (!times.empty()) {
639  for (std::size_t i = 0; i < times.size() - 1; ++i)
640  listTimes << times[i] << ", ";
641  listTimes << times[times.size() - 1];
642  }
643 
644  *l_out << " stepType = " << getStepType() << std::endl
645  << " initTime = " << getInitTime() << std::endl
646  << " finalTime = " << getFinalTime() << std::endl
647  << " minTimeStep = " << getMinTimeStep() << std::endl
648  << " initTimeStep = " << getInitTimeStep() << std::endl
649  << " maxTimeStep = " << getMaxTimeStep() << std::endl
650  << " initIndex = " << getInitIndex() << std::endl
651  << " finalIndex = " << getFinalIndex() << std::endl
652  << " maxAbsError = " << getMaxAbsError() << std::endl
653  << " maxRelError = " << getMaxRelError() << std::endl
654  << " maxFailures = " << getMaxFailures() << std::endl
655  << " maxConsecFailures = " << getMaxConsecFailures() << std::endl
656  << " numTimeSteps = " << getNumTimeSteps() << std::endl
657  << " printDtChanges = " << getPrintDtChanges() << std::endl
658  << " outputExactly = " << getOutputExactly() << std::endl
659  << " outputIndices = " << listIdx.str() << std::endl
660  << " outputTimes = " << listTimes.str() << std::endl
661  << " outputIndexInterval= " << getOutputIndexInterval() << std::endl
662  << " outputTimeInterval = " << getOutputTimeInterval() << std::endl
663  << " outputAdjustedDt = " << teAdjustedDt_ << std::endl
664  << " dtAfterOutput = " << dtAfterTimeEvent_ << std::endl;
665  stepControlStrategy_->describe(*l_out, verbLevel);
666  timeEvent_->describe(*l_out, verbLevel);
667  }
668  *l_out << std::string(this->description().length() + 8, '-') << std::endl;
669 }
670 
671 template <class Scalar>
674 {
676  Teuchos::parameterList("Time Step Control");
677 
678  pl->set<double>("Initial Time", getInitTime(), "Initial time");
679  pl->set<double>("Final Time", getFinalTime(), "Final time");
680  pl->set<double>("Minimum Time Step", getMinTimeStep(),
681  "Minimum time step size");
682  pl->set<double>("Initial Time Step", getInitTimeStep(),
683  "Initial time step size");
684  pl->set<double>("Maximum Time Step", getMaxTimeStep(),
685  "Maximum time step size");
686  pl->set<int>("Initial Time Index", getInitIndex(), "Initial time index");
687  pl->set<int>("Final Time Index", getFinalIndex(), "Final time index");
688  pl->set<int>(
689  "Number of Time Steps", getNumTimeSteps(),
690  "The number of constant time steps. The actual step size gets computed\n"
691  "on the fly given the size of the time domain. Overides and resets\n"
692  " 'Final Time Index' = 'Initial Time Index' + 'Number of Time "
693  "Steps'\n"
694  " 'Initial Time Step' = "
695  "('Final Time' - 'Initial Time')/'Number of Time Steps'\n");
696  pl->set<double>("Maximum Absolute Error", getMaxAbsError(),
697  "Maximum absolute error");
698  pl->set<double>("Maximum Relative Error", getMaxRelError(),
699  "Maximum relative error");
700 
701  pl->set<bool>("Print Time Step Changes", getPrintDtChanges(),
702  "Print timestep size when it changes");
703 
704  auto event = timeEvent_->find("Output Index Interval");
705  if (event != Teuchos::null) {
706  auto teri = Teuchos::rcp_dynamic_cast<TimeEventRangeIndex<Scalar>>(event);
707  pl->set<int>("Output Index Interval", teri->getIndexStride(),
708  "Output Index Interval");
709  }
710 
711  event = timeEvent_->find("Output Time Interval");
712  if (event != Teuchos::null) {
713  auto ter = Teuchos::rcp_dynamic_cast<TimeEventRange<Scalar>>(event);
714  pl->set<double>("Output Time Interval", ter->getTimeStride(),
715  "Output time interval");
716  }
717 
718  pl->set<bool>(
719  "Output Exactly On Output Times", getOutputExactly(),
720  "This determines if the timestep size will be adjusted to exactly land\n"
721  "on the output times for 'Variable' timestepping (default=true).\n"
722  "When set to 'false' or for 'Constant' time stepping, the timestep\n"
723  "following the output time will be flagged for output.\n");
724 
725  {
726  event = timeEvent_->find("Output Index List");
727  std::ostringstream list;
728  if (event != Teuchos::null) {
729  auto teli = Teuchos::rcp_dynamic_cast<TimeEventListIndex<Scalar>>(event);
730  std::vector<int> idx = teli->getIndexList();
731  if (!idx.empty()) {
732  for (std::size_t i = 0; i < idx.size() - 1; ++i) list << idx[i] << ", ";
733  list << idx[idx.size() - 1];
734  }
735  }
736  pl->set<std::string>("Output Index List", list.str(),
737  "Comma deliminated list of output indices");
738  }
739 
740  {
741  event = timeEvent_->find("Output Time List");
742  std::ostringstream list;
743  if (event != Teuchos::null) {
744  auto teli = Teuchos::rcp_dynamic_cast<TimeEventList<Scalar>>(event);
745  std::vector<Scalar> times = teli->getTimeList();
746  if (!times.empty()) {
747  for (std::size_t i = 0; i < times.size() - 1; ++i)
748  list << times[i] << ", ";
749  list << times[times.size() - 1];
750  }
751  }
752  pl->set<std::string>("Output Time List", list.str(),
753  "Comma deliminated list of output times");
754  }
755 
756  { // Do not duplicate the above "Output" events in "Time Step Control
757  // Events".
758  auto tecTmp = Teuchos::rcp(new TimeEventComposite<Scalar>());
759  tecTmp->setTimeEvents(timeEvent_->getTimeEvents());
760  tecTmp->remove("Output Index Interval");
761  tecTmp->remove("Output Time Interval");
762  tecTmp->remove("Output Index List");
763  tecTmp->remove("Output Time List");
764  if (tecTmp->getSize() > 0)
765  pl->set("Time Step Control Events", *tecTmp->getValidParameters());
766  }
767 
768  pl->set<int>("Maximum Number of Stepper Failures", getMaxFailures(),
769  "Maximum number of Stepper failures");
770  pl->set<int>("Maximum Number of Consecutive Stepper Failures",
771  getMaxConsecFailures(),
772  "Maximum number of consecutive Stepper failures");
773 
774  pl->set("Time Step Control Strategy",
775  *stepControlStrategy_->getValidParameters());
776 
777  return pl;
778 }
779 
780 // Nonmember constructor - ParameterList
781 // ------------------------------------------------------------------------
782 template <class Scalar>
784  Teuchos::RCP<Teuchos::ParameterList> const& pList, bool runInitialize)
785 {
787  using Teuchos::RCP;
788  using Teuchos::rcp;
789 
790  auto tsc = Teuchos::rcp(new TimeStepControl<Scalar>());
791  if (pList == Teuchos::null || pList->numParams() == 0) return tsc;
792 
793  auto tscValidPL =
794  Teuchos::rcp_const_cast<ParameterList>(tsc->getValidParameters());
795  // Handle optional "Time Step Control Events" sublist.
796  if (pList->isSublist("Time Step Control Events")) {
797  RCP<ParameterList> tsctePL =
798  Teuchos::sublist(pList, "Time Step Control Events", true);
799  tscValidPL->set("Time Step Control Events", *tsctePL);
800  }
801 
802  pList->validateParametersAndSetDefaults(*tscValidPL, 0);
803 
804  tsc->setInitTime(pList->get<double>("Initial Time"));
805  tsc->setFinalTime(pList->get<double>("Final Time"));
806  tsc->setMinTimeStep(pList->get<double>("Minimum Time Step"));
807  tsc->setInitTimeStep(pList->get<double>("Initial Time Step"));
808  tsc->setMaxTimeStep(pList->get<double>("Maximum Time Step"));
809  tsc->setInitIndex(pList->get<int>("Initial Time Index"));
810  tsc->setFinalIndex(pList->get<int>("Final Time Index"));
811  tsc->setMaxAbsError(pList->get<double>("Maximum Absolute Error"));
812  tsc->setMaxRelError(pList->get<double>("Maximum Relative Error"));
813  tsc->setMaxFailures(pList->get<int>("Maximum Number of Stepper Failures"));
814  tsc->setMaxConsecFailures(
815  pList->get<int>("Maximum Number of Consecutive Stepper Failures"));
816  tsc->setPrintDtChanges(pList->get<bool>("Print Time Step Changes"));
817  tsc->setNumTimeSteps(pList->get<int>("Number of Time Steps"));
818 
819  auto tec = rcp(new TimeEventComposite<Scalar>());
820  tec->setName("Time Step Control Events");
821 
822  { // Parse output indices, "Output Index List".
823  std::vector<int> outputIndices;
824  outputIndices.clear();
825  std::string str = pList->get<std::string>("Output Index List");
826  std::string delimiters(",");
827  std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
828  std::string::size_type pos = str.find_first_of(delimiters, lastPos);
829  while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
830  std::string token = str.substr(lastPos, pos - lastPos);
831  outputIndices.push_back(int(std::stoi(token)));
832  if (pos == std::string::npos) break;
833 
834  lastPos = str.find_first_not_of(delimiters, pos);
835  pos = str.find_first_of(delimiters, lastPos);
836  }
837 
838  if (!outputIndices.empty()) {
839  // order output indices
840  std::sort(outputIndices.begin(), outputIndices.end());
841  outputIndices.erase(
842  std::unique(outputIndices.begin(), outputIndices.end()),
843  outputIndices.end());
844 
846  outputIndices, "Output Index List")));
847  }
848  }
849 
850  // Parse output index internal
851  tec->add(rcp(new TimeEventRangeIndex<Scalar>(
852  tsc->getInitIndex(), tsc->getFinalIndex(),
853  pList->get<int>("Output Index Interval"), "Output Index Interval")));
854 
855  auto outputExactly = pList->get<bool>("Output Exactly On Output Times", true);
856 
857  { // Parse output times, "Output Time List".
858  std::vector<Scalar> outputTimes;
859  outputTimes.clear();
860  std::string str = pList->get<std::string>("Output Time List");
861  std::string delimiters(",");
862  // Skip delimiters at the beginning
863  std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
864  // Find the first delimiter
865  std::string::size_type pos = str.find_first_of(delimiters, lastPos);
866  while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
867  // Found a token, add it to the vector
868  std::string token = str.substr(lastPos, pos - lastPos);
869  outputTimes.push_back(Scalar(std::stod(token)));
870  if (pos == std::string::npos) break;
871 
872  lastPos = str.find_first_not_of(delimiters, pos); // Skip delimiters
873  pos = str.find_first_of(delimiters, lastPos); // Find next delimiter
874  }
875 
876  if (!outputTimes.empty()) {
877  // order output times
878  std::sort(outputTimes.begin(), outputTimes.end());
879  outputTimes.erase(std::unique(outputTimes.begin(), outputTimes.end()),
880  outputTimes.end());
881 
882  tec->add(rcp(new Tempus::TimeEventList<Scalar>(
883  outputTimes, "Output Time List", outputExactly)));
884  }
885  }
886 
887  // Parse output time interval
888  tec->add(
889  rcp(new TimeEventRange<Scalar>(tsc->getInitTime(), tsc->getFinalTime(),
890  pList->get<double>("Output Time Interval"),
891  "Output Time Interval", outputExactly)));
892 
893  if (pList->isSublist("Time Step Control Events")) {
894  RCP<ParameterList> tsctePL =
895  Teuchos::sublist(pList, "Time Step Control Events", true);
896 
897  auto timeEventType = tsctePL->get<std::string>("Type", "Unknown");
898  if (timeEventType == "Range") {
899  tec->add(createTimeEventRange<Scalar>(tsctePL));
900  }
901  else if (timeEventType == "Range Index") {
902  tec->add(createTimeEventRangeIndex<Scalar>(tsctePL));
903  }
904  else if (timeEventType == "List") {
905  tec->add(createTimeEventList<Scalar>(tsctePL));
906  }
907  else if (timeEventType == "List Index") {
908  tec->add(createTimeEventListIndex<Scalar>(tsctePL));
909  }
910  else if (timeEventType == "Composite") {
911  auto tecTmp = createTimeEventComposite<Scalar>(tsctePL);
912  auto timeEvents = tecTmp->getTimeEvents();
913  for (auto& e : timeEvents) tec->add(e);
914  }
915  else {
916  RCP<Teuchos::FancyOStream> out =
917  Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
918  out->setOutputToRootOnly(0);
919  Teuchos::OSTab ostab(out, 1, "createTimeStepControl()");
920  *out << "Warning -- Unknown Time Event Type!\n"
921  << "'Type' = '" << timeEventType << "'\n"
922  << "Should call add() with this "
923  << "(app-specific?) Time Event.\n"
924  << std::endl;
925  }
926  }
927 
928  tsc->setTimeEvents(tec);
929 
930  if (!pList->isParameter("Time Step Control Strategy")) {
931  tsc->setTimeStepControlStrategy(); // i.e., set default Constant timestep
932  // strategy.
933  }
934  else {
935  RCP<ParameterList> tscsPL =
936  Teuchos::sublist(pList, "Time Step Control Strategy", true);
937 
938  auto strategyType = tscsPL->get<std::string>("Strategy Type");
939  if (strategyType == "Constant") {
940  tsc->setTimeStepControlStrategy(
941  createTimeStepControlStrategyConstant<Scalar>(tscsPL));
942  }
943  else if (strategyType == "Basic VS") {
944  tsc->setTimeStepControlStrategy(
945  createTimeStepControlStrategyBasicVS<Scalar>(tscsPL));
946  }
947  else if (strategyType == "Integral Controller") {
948  tsc->setTimeStepControlStrategy(
949  createTimeStepControlStrategyIntegralController<Scalar>(tscsPL));
950  }
951  else if (strategyType == "Composite") {
952  tsc->setTimeStepControlStrategy(
953  createTimeStepControlStrategyComposite<Scalar>(tscsPL));
954  }
955  else {
956  RCP<Teuchos::FancyOStream> out =
957  Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
958  out->setOutputToRootOnly(0);
959  Teuchos::OSTab ostab(out, 1, "createTimeStepControl()");
960  *out << "Warning -- Did not find a Tempus strategy to create!\n"
961  << "'Strategy Type' = '" << strategyType << "'\n"
962  << "Should call setTimeStepControlStrategy() with this\n"
963  << "(app-specific?) strategy, and initialize().\n"
964  << std::endl;
965  }
966  }
967 
968  if (runInitialize) tsc->initialize();
969  return tsc;
970 }
971 
972 } // namespace Tempus
973 #endif // Tempus_TimeStepControl_impl_hpp
TimeEventRangeIndex specifies a start, stop and stride index.
virtual void setTimeEvents(Teuchos::RCP< TimeEventComposite< Scalar >> teb=Teuchos::null)
Teuchos::RCP< TimeStepControl< Scalar > > createTimeStepControl(Teuchos::RCP< Teuchos::ParameterList > const &pList, bool runInitialize=true)
Nonmember constructor from ParameterList.
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
virtual void setNumTimeSteps(int numTimeSteps)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
TimeEventListIndex specifies a list of index events.
virtual void setLandOnExactly(bool LOE)
Set if the time event should be landed on exactly.
Ordinal numParams() const
virtual void printDtChanges(int istep, Scalar dt_old, Scalar dt_new, std::string reason) const
virtual void setOutputTimes(std::vector< Scalar > outputTimes)
virtual void setTimeStepControlStrategy(Teuchos::RCP< TimeStepControlStrategy< Scalar >> tscs=Teuchos::null)
bool isParameter(const std::string &name) const
virtual std::string getStepType() const
virtual int getIndexStride() const
Return the stride of the index range.
TimeEventRange specifies a start, stop and stride time.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Status
Status for the Integrator, the Stepper and the SolutionState.
bool isSublist(const std::string &name) const
virtual Scalar getTimeStride() const
Return the stride of the time range.
This composite TimeEvent loops over added TimeEvents.
virtual bool indexInRange(const int iStep) const
Check if time step index is within minimum and maximum index.
TimeStepControl manages the time step size. There several mechanisms that effect the time step size a...
TimeStepControl()
Default Constructor.
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
virtual std::vector< int > getIndexList() const
Return a vector of event indices.
virtual void setOutputTimeInterval(Scalar t)
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
virtual void setNextTimeStep(const Teuchos::RCP< SolutionHistory< Scalar >> &solutionHistory, Status &integratorStatus)
Determine the time step size.
StepControlStrategy class for TimeStepControl.
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
virtual bool timeInRange(const Scalar time) const
Check if time is within minimum and maximum time.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
virtual int getOutputIndexInterval() const
virtual Scalar getOutputTimeInterval() const
virtual bool getOutputExactly() const
Return if the output needs to exactly happen on output time.
virtual void setLandOnExactly(bool LOE)
Set if the time event should be landed on exactly.
TimeEventList specifies a list of time events.
TimeStepControlStrategy class for TimeStepControl.
virtual void setOutputIndices(std::vector< int > v)
virtual std::vector< Scalar > getOutputTimes() const
virtual Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return ParameterList with current values.
virtual std::vector< int > getOutputIndices() const
virtual std::vector< Scalar > getTimeList() const
Return the list of time events.