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,
60 : isInitialized_(false),
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),
72 printDtChanges_(printDtChanges),
74 dtAfterTimeEvent_(0.0)
82 tec->setName(
"Time Step Control Events");
83 auto tes = timeEvent->getTimeEvents();
84 for (
auto& e : tes) tec->add(e);
89 "Output Time Interval", outputExactly));
93 if (!outputTimes.empty())
99 initIndex, finalIndex, outputIndexInterval,
"Output Index Interval")));
102 if (!outputTimes.empty())
114 TEUCHOS_TEST_FOR_EXCEPTION(
115 (getInitTime() > getFinalTime()), std::logic_error,
116 "Error - Inconsistent time range.\n"
118 << getInitTime() <<
") > (timeMax = " << getFinalTime() <<
")\n");
120 TEUCHOS_TEST_FOR_EXCEPTION(
121 (getMinTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
123 "Error - Negative minimum time step. dtMin = " << getMinTimeStep() <<
")\n");
124 TEUCHOS_TEST_FOR_EXCEPTION(
125 (getMaxTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
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"
132 << getMinTimeStep() <<
") > (dtMax = " << getMaxTimeStep() <<
")\n");
133 TEUCHOS_TEST_FOR_EXCEPTION(
134 (getInitTimeStep() < Teuchos::ScalarTraits<Scalar>::zero()),
136 "Error - Negative initial time step. dtInit = " << getInitTimeStep() <<
")\n");
137 TEUCHOS_TEST_FOR_EXCEPTION((getInitTimeStep() < getMinTimeStep() ||
138 getInitTimeStep() > getMaxTimeStep()),
140 "Error - Initial time step is out of range.\n"
141 <<
" [dtMin, dtMax] = [" << getMinTimeStep()
142 <<
", " << getMaxTimeStep() <<
"]\n"
143 <<
" dtInit = " << getInitTimeStep()
146 TEUCHOS_TEST_FOR_EXCEPTION(
147 (getInitIndex() > getFinalIndex()), std::logic_error,
148 "Error - Inconsistent time index range.\n"
150 << getInitIndex() <<
") > (iStepMax = " << getFinalIndex() <<
")\n");
152 TEUCHOS_TEST_FOR_EXCEPTION(
153 (getMaxAbsError() < Teuchos::ScalarTraits<Scalar>::zero()),
155 "Error - Negative maximum time step. errorMaxAbs = " << getMaxAbsError() <<
")\n");
156 TEUCHOS_TEST_FOR_EXCEPTION(
157 (getMaxRelError() < Teuchos::ScalarTraits<Scalar>::zero()),
159 "Error - Negative maximum time step. errorMaxRel = " << getMaxRelError() <<
")\n");
161 TEUCHOS_TEST_FOR_EXCEPTION((stepControlStrategy_ == Teuchos::null),
162 std::logic_error,
"Error - Strategy is unset!\n");
164 stepControlStrategy_->initialize();
166 TEUCHOS_TEST_FOR_EXCEPTION(
167 (getStepType() !=
"Constant" && getStepType() !=
"Variable"),
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 "
173 <<
" stepType = " << getStepType() <<
"\n");
175 isInitialized_ =
true;
217 TEMPUS_FUNC_TIME_MONITOR(
"Tempus::TimeStepControl::setNextTimeStep()");
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();
226 RCP<StepperState<Scalar>> stepperState = workingState->getStepperState();
229 if (getStepType() ==
"Variable") {
230 if (teAdjustedDt_ ==
true) {
231 printDtChanges(iStep, dt, dtAfterTimeEvent_,
232 "Reset dt after time event.");
233 dt = dtAfterTimeEvent_;
234 time = lastTime + dt;
235 teAdjustedDt_ =
false;
236 dtAfterTimeEvent_ = 0.0;
240 printDtChanges(iStep, dt, getInitTimeStep(),
"Reset dt to initial dt.");
241 dt = getInitTimeStep();
242 time = lastTime + dt;
245 if (dt < getMinTimeStep()) {
246 printDtChanges(iStep, dt, getMinTimeStep(),
"Reset dt to minimum dt.");
247 dt = getMinTimeStep();
248 time = lastTime + dt;
253 workingState->setTimeStep(dt);
254 workingState->setTime(time);
257 stepControlStrategy_->setNextTimeStep(*
this, solutionHistory,
261 dt = workingState->getTimeStep();
262 time = workingState->getTime();
264 if (getStepType() ==
"Variable") {
265 if (dt < getMinTimeStep()) {
266 printDtChanges(iStep, dt, getMinTimeStep(),
267 "dt is too small. Resetting to minimum dt.");
268 dt = getMinTimeStep();
269 time = lastTime + dt;
271 if (dt > getMaxTimeStep()) {
272 printDtChanges(iStep, dt, getMaxTimeStep(),
273 "dt is too large. Resetting to maximum dt.");
274 dt = getMaxTimeStep();
275 time = lastTime + dt;
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;
292 Scalar endTime = lastTime + dt;
295 if (getStepType() ==
"Variable") endTime = lastTime + dt + getMinTimeStep();
298 timeEvent_->eventInRange(lastTime, endTime, constrainingTEs);
300 bool outputDueToTime =
false;
301 Scalar tone = endTime;
302 bool landOnExactly =
false;
304 for (
auto& e : constrainingTEs) {
305 if (e->getName() ==
"Output Time Interval" ||
306 e->getName() ==
"Output Time List") {
307 outputDueToTime =
true;
310 if (e->getLandOnExactly() ==
true) {
311 landOnExactly =
true;
312 tone = e->timeOfNextEvent(lastTime);
318 Scalar reltol = 1.0e-6;
319 if (teThisStep && getStepType() ==
"Variable") {
320 if (landOnExactly ==
true) {
325 printDtChanges(iStep, dt, tone - lastTime,
326 "Adjusting dt to hit the next TimeEvent.");
327 teAdjustedDt_ =
true;
328 dtAfterTimeEvent_ = dt;
329 dt = tone - lastTime;
330 time = lastTime + dt;
332 else if (std::fabs(time - tone) < reltol * std::fabs(time)) {
336 iStep, dt, tone - lastTime,
337 "Adjusting dt for numerical roundoff to hit the next TimeEvent.");
338 teAdjustedDt_ =
true;
339 dtAfterTimeEvent_ = dt;
340 dt = tone - lastTime;
341 time = lastTime + dt;
343 else if (std::fabs(time + getMinTimeStep() - tone) <
344 reltol * std::fabs(tone)) {
349 iStep, dt, (tone - lastTime) / 2.0,
350 "The next TimeEvent is within the minimum dt of the next time. "
351 "Adjusting dt to take two steps.");
352 dt = (tone - lastTime) / 2.0;
353 time = lastTime + dt;
355 outputDueToTime =
false;
362 if (getStepType() ==
"Variable") {
363 if ((lastTime + dt > getFinalTime()) ||
364 (std::fabs((lastTime + dt - getFinalTime())) <
365 reltol * std::fabs(lastTime + dt))) {
366 printDtChanges(iStep, dt, getFinalTime() - lastTime,
367 "Adjusting dt to hit final time.");
368 dt = getFinalTime() - lastTime;
369 time = lastTime + dt;
374 TEUCHOS_TEST_FOR_EXCEPTION(
375 dt <= Scalar(0.0), std::out_of_range,
376 "Error - Time step is not positive. dt = " << dt <<
"\n");
379 TEUCHOS_TEST_FOR_EXCEPTION(
380 (lastTime + dt < getInitTime()), std::out_of_range,
381 "Error - Time step does not move time INTO time range.\n"
382 <<
" [timeMin, timeMax] = ["
383 << getInitTime() <<
", " << getFinalTime()
385 << lastTime <<
" + " << dt <<
" = " << lastTime + dt <<
"\n");
387 if (getStepType() ==
"Variable") {
388 TEUCHOS_TEST_FOR_EXCEPTION(
389 (lastTime + dt > getFinalTime()), std::out_of_range,
390 "Error - Time step move time OUT OF time range.\n"
391 <<
" [timeMin, timeMax] = ["
392 << getInitTime() <<
", " << getFinalTime()
394 << lastTime <<
" + " << dt <<
" = " << lastTime + dt <<
"\n");
397 workingState->setTimeStep(dt);
398 workingState->setTime(time);
399 workingState->setOutput(outputDueToIndex || outputDueToTime);
620 Teuchos::FancyOStream& out,
const Teuchos::EVerbosityLevel verbLevel)
const
622 auto l_out = Teuchos::fancyOStream(out.getOStream());
623 Teuchos::OSTab ostab(*l_out, 2, this->description());
624 l_out->setOutputToRootOnly(0);
626 *l_out <<
"\n--- " << this->description() <<
" ---" << std::endl;
628 if (Teuchos::as<int>(verbLevel) >= Teuchos::as<int>(Teuchos::VERB_MEDIUM)) {
629 std::vector<int> idx = getOutputIndices();
630 std::ostringstream listIdx;
632 for (std::size_t i = 0; i < idx.size() - 1; ++i)
633 listIdx << idx[i] <<
", ";
634 listIdx << idx[idx.size() - 1];
637 std::vector<Scalar> times = getOutputTimes();
638 std::ostringstream listTimes;
639 if (!times.empty()) {
640 for (std::size_t i = 0; i < times.size() - 1; ++i)
641 listTimes << times[i] <<
", ";
642 listTimes << times[times.size() - 1];
645 *l_out <<
" stepType = " << getStepType() << std::endl
646 <<
" initTime = " << getInitTime() << std::endl
647 <<
" finalTime = " << getFinalTime() << std::endl
648 <<
" minTimeStep = " << getMinTimeStep() << std::endl
649 <<
" initTimeStep = " << getInitTimeStep() << std::endl
650 <<
" maxTimeStep = " << getMaxTimeStep() << std::endl
651 <<
" initIndex = " << getInitIndex() << std::endl
652 <<
" finalIndex = " << getFinalIndex() << std::endl
653 <<
" maxAbsError = " << getMaxAbsError() << std::endl
654 <<
" maxRelError = " << getMaxRelError() << std::endl
655 <<
" maxFailures = " << getMaxFailures() << std::endl
656 <<
" maxConsecFailures = " << getMaxConsecFailures() << std::endl
657 <<
" numTimeSteps = " << getNumTimeSteps() << std::endl
658 <<
" printDtChanges = " << getPrintDtChanges() << std::endl
659 <<
" outputExactly = " << getOutputExactly() << std::endl
660 <<
" outputIndices = " << listIdx.str() << std::endl
661 <<
" outputTimes = " << listTimes.str() << std::endl
662 <<
" outputIndexInterval= " << getOutputIndexInterval() << std::endl
663 <<
" outputTimeInterval = " << getOutputTimeInterval() << std::endl
664 <<
" outputAdjustedDt = " << teAdjustedDt_ << std::endl
665 <<
" dtAfterOutput = " << dtAfterTimeEvent_ << std::endl;
666 stepControlStrategy_->describe(*l_out, verbLevel);
667 timeEvent_->describe(*l_out, verbLevel);
669 *l_out << std::string(this->description().length() + 8,
'-') << std::endl;
676 Teuchos::RCP<Teuchos::ParameterList> pl =
677 Teuchos::parameterList(
"Time Step Control");
679 pl->set<
double>(
"Initial Time", getInitTime(),
"Initial time");
680 pl->set<
double>(
"Final Time", getFinalTime(),
"Final time");
681 pl->set<
double>(
"Minimum Time Step", getMinTimeStep(),
682 "Minimum time step size");
683 pl->set<
double>(
"Initial Time Step", getInitTimeStep(),
684 "Initial time step size");
685 pl->set<
double>(
"Maximum Time Step", getMaxTimeStep(),
686 "Maximum time step size");
687 pl->set<
int>(
"Initial Time Index", getInitIndex(),
"Initial time index");
688 pl->set<
int>(
"Final Time Index", getFinalIndex(),
"Final time index");
690 "Number of Time Steps", getNumTimeSteps(),
691 "The number of constant time steps. The actual step size gets computed\n"
692 "on the fly given the size of the time domain. Overides and resets\n"
693 " 'Final Time Index' = 'Initial Time Index' + 'Number of Time "
695 " 'Initial Time Step' = "
696 "('Final Time' - 'Initial Time')/'Number of Time Steps'\n");
697 pl->set<
double>(
"Maximum Absolute Error", getMaxAbsError(),
698 "Maximum absolute error");
699 pl->set<
double>(
"Maximum Relative Error", getMaxRelError(),
700 "Maximum relative error");
702 pl->set<
bool>(
"Print Time Step Changes", getPrintDtChanges(),
703 "Print timestep size when it changes");
705 auto event = timeEvent_->find(
"Output Index Interval");
706 if (event != Teuchos::null) {
707 auto teri = Teuchos::rcp_dynamic_cast<TimeEventRangeIndex<Scalar>>(event);
708 pl->set<
int>(
"Output Index Interval", teri->getIndexStride(),
709 "Output Index Interval");
712 event = timeEvent_->find(
"Output Time Interval");
713 if (event != Teuchos::null) {
714 auto ter = Teuchos::rcp_dynamic_cast<TimeEventRange<Scalar>>(event);
715 pl->set<
double>(
"Output Time Interval", ter->getTimeStride(),
716 "Output time interval");
720 "Output Exactly On Output Times", getOutputExactly(),
721 "This determines if the timestep size will be adjusted to exactly land\n"
722 "on the output times for 'Variable' timestepping (default=true).\n"
723 "When set to 'false' or for 'Constant' time stepping, the timestep\n"
724 "following the output time will be flagged for output.\n");
727 event = timeEvent_->find(
"Output Index List");
728 std::ostringstream list;
729 if (event != Teuchos::null) {
730 auto teli = Teuchos::rcp_dynamic_cast<TimeEventListIndex<Scalar>>(event);
731 std::vector<int> idx = teli->getIndexList();
733 for (std::size_t i = 0; i < idx.size() - 1; ++i) list << idx[i] <<
", ";
734 list << idx[idx.size() - 1];
737 pl->set<std::string>(
"Output Index List", list.str(),
738 "Comma deliminated list of output indices");
742 event = timeEvent_->find(
"Output Time List");
743 std::ostringstream list;
744 if (event != Teuchos::null) {
745 auto teli = Teuchos::rcp_dynamic_cast<TimeEventList<Scalar>>(event);
746 std::vector<Scalar> times = teli->getTimeList();
747 if (!times.empty()) {
748 for (std::size_t i = 0; i < times.size() - 1; ++i)
749 list << times[i] <<
", ";
750 list << times[times.size() - 1];
753 pl->set<std::string>(
"Output Time List", list.str(),
754 "Comma deliminated list of output times");
760 tecTmp->setTimeEvents(timeEvent_->getTimeEvents());
761 tecTmp->remove(
"Output Index Interval");
762 tecTmp->remove(
"Output Time Interval");
763 tecTmp->remove(
"Output Index List");
764 tecTmp->remove(
"Output Time List");
765 if (tecTmp->getSize() > 0)
766 pl->set(
"Time Step Control Events", *tecTmp->getValidParameters());
769 pl->set<
int>(
"Maximum Number of Stepper Failures", getMaxFailures(),
770 "Maximum number of Stepper failures");
771 pl->set<
int>(
"Maximum Number of Consecutive Stepper Failures",
772 getMaxConsecFailures(),
773 "Maximum number of consecutive Stepper failures");
775 pl->set(
"Time Step Control Strategy",
776 *stepControlStrategy_->getValidParameters());
785 Teuchos::RCP<Teuchos::ParameterList>
const& pList,
bool runInitialize)
787 using Teuchos::ParameterList;
792 if (pList == Teuchos::null || pList->numParams() == 0)
return tsc;
795 Teuchos::rcp_const_cast<ParameterList>(tsc->getValidParameters());
797 if (pList->isSublist(
"Time Step Control Events")) {
798 RCP<ParameterList> tsctePL =
799 Teuchos::sublist(pList,
"Time Step Control Events",
true);
800 tscValidPL->set(
"Time Step Control Events", *tsctePL);
803 pList->validateParametersAndSetDefaults(*tscValidPL, 0);
805 tsc->setInitTime(pList->get<
double>(
"Initial Time"));
806 tsc->setFinalTime(pList->get<
double>(
"Final Time"));
807 tsc->setMinTimeStep(pList->get<
double>(
"Minimum Time Step"));
808 tsc->setInitTimeStep(pList->get<
double>(
"Initial Time Step"));
809 tsc->setMaxTimeStep(pList->get<
double>(
"Maximum Time Step"));
810 tsc->setInitIndex(pList->get<
int>(
"Initial Time Index"));
811 tsc->setFinalIndex(pList->get<
int>(
"Final Time Index"));
812 tsc->setMaxAbsError(pList->get<
double>(
"Maximum Absolute Error"));
813 tsc->setMaxRelError(pList->get<
double>(
"Maximum Relative Error"));
814 tsc->setMaxFailures(pList->get<
int>(
"Maximum Number of Stepper Failures"));
815 tsc->setMaxConsecFailures(
816 pList->get<
int>(
"Maximum Number of Consecutive Stepper Failures"));
817 tsc->setPrintDtChanges(pList->get<
bool>(
"Print Time Step Changes"));
818 tsc->setNumTimeSteps(pList->get<
int>(
"Number of Time Steps"));
821 tec->setName(
"Time Step Control Events");
824 std::vector<int> outputIndices;
825 outputIndices.clear();
826 std::string str = pList->get<std::string>(
"Output Index List");
827 std::string delimiters(
",");
828 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
829 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
830 while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
831 std::string token = str.substr(lastPos, pos - lastPos);
832 outputIndices.push_back(
int(std::stoi(token)));
833 if (pos == std::string::npos)
break;
835 lastPos = str.find_first_not_of(delimiters, pos);
836 pos = str.find_first_of(delimiters, lastPos);
839 if (!outputIndices.empty()) {
841 std::sort(outputIndices.begin(), outputIndices.end());
843 std::unique(outputIndices.begin(), outputIndices.end()),
844 outputIndices.end());
847 outputIndices,
"Output Index List")));
853 tsc->getInitIndex(), tsc->getFinalIndex(),
854 pList->get<
int>(
"Output Index Interval"),
"Output Index Interval")));
856 auto outputExactly = pList->get<
bool>(
"Output Exactly On Output Times",
true);
859 std::vector<Scalar> outputTimes;
861 std::string str = pList->get<std::string>(
"Output Time List");
862 std::string delimiters(
",");
864 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
866 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
867 while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
869 std::string token = str.substr(lastPos, pos - lastPos);
870 outputTimes.push_back(Scalar(std::stod(token)));
871 if (pos == std::string::npos)
break;
873 lastPos = str.find_first_not_of(delimiters, pos);
874 pos = str.find_first_of(delimiters, lastPos);
877 if (!outputTimes.empty()) {
879 std::sort(outputTimes.begin(), outputTimes.end());
880 outputTimes.erase(std::unique(outputTimes.begin(), outputTimes.end()),
884 outputTimes,
"Output Time List", outputExactly)));
891 pList->get<
double>(
"Output Time Interval"),
892 "Output Time Interval", outputExactly)));
894 if (pList->isSublist(
"Time Step Control Events")) {
895 RCP<ParameterList> tsctePL =
896 Teuchos::sublist(pList,
"Time Step Control Events",
true);
898 auto timeEventType = tsctePL->get<std::string>(
"Type",
"Unknown");
899 if (timeEventType ==
"Range") {
900 tec->add(createTimeEventRange<Scalar>(tsctePL));
902 else if (timeEventType ==
"Range Index") {
903 tec->add(createTimeEventRangeIndex<Scalar>(tsctePL));
905 else if (timeEventType ==
"List") {
906 tec->add(createTimeEventList<Scalar>(tsctePL));
908 else if (timeEventType ==
"List Index") {
909 tec->add(createTimeEventListIndex<Scalar>(tsctePL));
911 else if (timeEventType ==
"Composite") {
912 auto tecTmp = createTimeEventComposite<Scalar>(tsctePL);
913 auto timeEvents = tecTmp->getTimeEvents();
914 for (
auto& e : timeEvents) tec->add(e);
917 RCP<Teuchos::FancyOStream> out =
918 Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
919 out->setOutputToRootOnly(0);
920 Teuchos::OSTab ostab(out, 1,
"createTimeStepControl()");
921 *out <<
"Warning -- Unknown Time Event Type!\n"
922 <<
"'Type' = '" << timeEventType <<
"'\n"
923 <<
"Should call add() with this "
924 <<
"(app-specific?) Time Event.\n"
929 tsc->setTimeEvents(tec);
931 if (!pList->isParameter(
"Time Step Control Strategy")) {
932 tsc->setTimeStepControlStrategy();
936 RCP<ParameterList> tscsPL =
937 Teuchos::sublist(pList,
"Time Step Control Strategy",
true);
939 auto strategyType = tscsPL->get<std::string>(
"Strategy Type");
940 if (strategyType ==
"Constant") {
941 tsc->setTimeStepControlStrategy(
942 createTimeStepControlStrategyConstant<Scalar>(tscsPL));
944 else if (strategyType ==
"Basic VS") {
945 tsc->setTimeStepControlStrategy(
946 createTimeStepControlStrategyBasicVS<Scalar>(tscsPL));
948 else if (strategyType ==
"Integral Controller") {
949 tsc->setTimeStepControlStrategy(
950 createTimeStepControlStrategyIntegralController<Scalar>(tscsPL));
952 else if (strategyType ==
"Composite") {
953 tsc->setTimeStepControlStrategy(
954 createTimeStepControlStrategyComposite<Scalar>(tscsPL));
957 RCP<Teuchos::FancyOStream> out =
958 Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
959 out->setOutputToRootOnly(0);
960 Teuchos::OSTab ostab(out, 1,
"createTimeStepControl()");
961 *out <<
"Warning -- Did not find a Tempus strategy to create!\n"
962 <<
"'Strategy Type' = '" << strategyType <<
"'\n"
963 <<
"Should call setTimeStepControlStrategy() with this\n"
964 <<
"(app-specific?) strategy, and initialize().\n"
969 if (runInitialize) tsc->initialize();
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...