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