9 #ifndef Tempus_TimeStepControl_impl_hpp
10 #define Tempus_TimeStepControl_impl_hpp
22 template<
class Scalar>
24 : isInitialized_ (false),
29 maxTimeStep_ (1.0e+99),
31 finalIndex_ (1000000),
32 maxAbsError_ (1.0e-08),
33 maxRelError_ (1.0e-08),
35 maxConsecFailures_ (5),
37 printDtChanges_ (true),
38 outputExactly_ (true),
41 outputIndexInterval_(1000000),
42 outputTimeInterval_ (1.0e+99),
43 outputAdjustedDt_(false),
51 template<
class Scalar>
63 int maxConsecFailures,
67 std::vector<int> outputIndices,
68 std::vector<Scalar> outputTimes,
69 int outputIndexInterval,
70 Scalar outputTimeInterval,
72 : isInitialized_ (false ),
73 initTime_ (initTime ),
74 finalTime_ (finalTime ),
75 minTimeStep_ (minTimeStep ),
76 initTimeStep_ (initTimeStep ),
77 maxTimeStep_ (maxTimeStep ),
78 initIndex_ (initIndex ),
79 finalIndex_ (finalIndex ),
80 maxAbsError_ (maxAbsError ),
81 maxRelError_ (maxRelError ),
82 maxFailures_ (maxFailures ),
83 maxConsecFailures_ (maxConsecFailures ),
84 numTimeSteps_ (numTimeSteps ),
85 printDtChanges_ (printDtChanges ),
86 outputExactly_ (outputExactly ),
87 outputIndices_ (outputIndices ),
88 outputTimes_ (outputTimes ),
89 outputIndexInterval_(outputIndexInterval),
90 outputTimeInterval_ (outputTimeInterval ),
91 outputAdjustedDt_ (false ),
92 dtAfterOutput_ (0.0 ),
93 stepControlStrategy_(stepControlStrategy)
100 template<
class Scalar>
104 (getInitTime() > getFinalTime() ), std::logic_error,
105 "Error - Inconsistent time range.\n"
106 " (timeMin = "<<getInitTime()<<
") > (timeMax = "<<getFinalTime()<<
")\n");
111 "Error - Negative minimum time step. dtMin = "<<getMinTimeStep()<<
")\n");
115 "Error - Negative maximum time step. dtMax = "<<getMaxTimeStep()<<
")\n");
117 (getMinTimeStep() > getMaxTimeStep() ), std::logic_error,
118 "Error - Inconsistent time step range.\n"
119 " (dtMin = "<<getMinTimeStep()<<
") > (dtMax = "<<getMaxTimeStep()<<
")\n");
123 "Error - Negative initial time step. dtInit = "<<getInitTimeStep()<<
")\n");
125 (getInitTimeStep() < getMinTimeStep() ||
126 getInitTimeStep() > getMaxTimeStep() ),
128 "Error - Initial time step is out of range.\n"
129 <<
" [dtMin, dtMax] = [" << getMinTimeStep() <<
", "
130 << getMaxTimeStep() <<
"]\n"
131 <<
" dtInit = " << getInitTimeStep() <<
"\n");
134 (getInitIndex() > getFinalIndex() ), std::logic_error,
135 "Error - Inconsistent time index range.\n"
136 " (iStepMin = "<<getInitIndex()<<
") > (iStepMax = "
137 <<getFinalIndex()<<
")\n");
142 "Error - Negative maximum time step. errorMaxAbs = "
143 <<getMaxAbsError()<<
")\n");
147 "Error - Negative maximum time step. errorMaxRel = "
148 <<getMaxRelError()<<
")\n");
151 (getStepType() !=
"Constant" && getStepType() !=
"Variable"),
153 "Error - 'Step Type' does not equal one of these:\n"
154 <<
" 'Constant' - Integrator will take constant time step sizes.\n"
155 <<
" 'Variable' - Integrator will allow changes to the time step size.\n"
156 <<
" stepType = " << getStepType() <<
"\n");
159 (stepControlStrategy_ == Teuchos::null), std::logic_error,
160 "Error - Strategy is unset!\n");
162 stepControlStrategy_->initialize();
164 isInitialized_ =
true;
168 template<
class Scalar>
170 printDtChanges(
int istep, Scalar dt_old, Scalar dt_new, std::string reason)
const
172 if (!getPrintDtChanges())
return;
178 std::stringstream message;
179 message << std::scientific
180 <<std::setw(6)<<std::setprecision(3)<<istep
181 <<
" * (dt = "<<std::setw(9)<<std::setprecision(3)<<dt_old
182 <<
", new = "<<std::setw(9)<<std::setprecision(3)<<dt_new
183 <<
") " << reason << std::endl;
184 *out << message.str();
188 template<
class Scalar>
191 if ( !isInitialized_ ) {
194 "Error - " << this->description() <<
" is not initialized!");
199 template<
class Scalar>
202 Status & integratorStatus)
208 TEMPUS_FUNC_TIME_MONITOR(
"Tempus::TimeStepControl::setNextTimeStep()");
210 RCP<SolutionState<Scalar> > workingState=solutionHistory->getWorkingState();
211 const Scalar lastTime = solutionHistory->getCurrentState()->getTime();
212 const int iStep = workingState->getIndex();
213 Scalar dt = workingState->getTimeStep();
214 Scalar time = workingState->getTime();
217 RCP<StepperState<Scalar> > stepperState = workingState->getStepperState();
220 if (getStepType() ==
"Variable") {
221 if (outputAdjustedDt_ ==
true) {
222 printDtChanges(iStep, dt, dtAfterOutput_,
"Reset dt after output.");
224 time = lastTime + dt;
225 outputAdjustedDt_ =
false;
226 dtAfterOutput_ = 0.0;
230 printDtChanges(iStep, dt, getInitTimeStep(),
"Reset dt to initial dt.");
231 dt = getInitTimeStep();
232 time = lastTime + dt;
235 if (dt < getMinTimeStep()) {
236 printDtChanges(iStep, dt, getMinTimeStep(),
"Reset dt to minimum dt.");
237 dt = getMinTimeStep();
238 time = lastTime + dt;
243 workingState->setTimeStep(dt);
244 workingState->setTime(time);
247 stepControlStrategy_->setNextTimeStep(*
this, solutionHistory,
251 dt = workingState->getTimeStep();
252 time = workingState->getTime();
254 if (getStepType() ==
"Variable") {
255 if (dt < getMinTimeStep()) {
256 printDtChanges(iStep, dt, getMinTimeStep(),
257 "dt is too small. Resetting to minimum dt.");
258 dt = getMinTimeStep();
259 time = lastTime + dt;
261 if (dt > getMaxTimeStep()) {
262 printDtChanges(iStep, dt, getMaxTimeStep(),
263 "dt is too large. Resetting to maximum dt.");
264 dt = getMaxTimeStep();
265 time = lastTime + dt;
271 std::vector<int>::const_iterator it =
272 std::find(getOutputIndices().begin(), getOutputIndices().end(), iStep);
273 if (it != getOutputIndices().end()) output =
true;
275 const int iInterval = getOutputIndexInterval();
276 if ( (iStep - getInitIndex()) % iInterval == 0) output =
true;
280 Scalar reltol = 1.0e-6;
281 Scalar endTime = lastTime+dt+getMinTimeStep();
284 if (getStepType() ==
"Constant") endTime = lastTime+dt;
285 bool checkOutput =
false;
286 Scalar oTime = getInitTime();
287 for (
size_t i=0; i < outputTimes_.size(); ++i) {
288 oTime = outputTimes_[i];
289 if (lastTime < oTime && oTime <= endTime) {
294 const Scalar tInterval = getOutputTimeInterval();
295 Scalar oTime2 = ceil((lastTime-getInitTime())/tInterval)*tInterval
297 if (lastTime < oTime2 && oTime2 <= endTime) {
298 if (checkOutput ==
true) {
299 if (oTime2 < oTime) oTime = oTime2;
306 if (checkOutput ==
true) {
307 const bool outputExactly = getOutputExactly();
308 if (getStepType() ==
"Variable" && outputExactly ==
true) {
310 if ( time > oTime ) {
312 printDtChanges(iStep, dt, oTime - lastTime,
313 "Adjusting dt to hit the next output time.");
317 outputAdjustedDt_ =
true;
319 dt = oTime - lastTime;
320 time = lastTime + dt;
321 }
else if (std::fabs((time-oTime)/(time)) < reltol) {
323 printDtChanges(iStep, dt, oTime - lastTime,
324 "Adjusting dt for numerical roundoff to hit the next output time.");
327 outputAdjustedDt_ =
true;
329 dt = oTime - lastTime;
330 time = lastTime + dt;
331 }
else if (std::fabs((time + getMinTimeStep() - oTime)/oTime) < reltol ) {
332 printDtChanges(iStep, dt, (oTime - lastTime)/2.0,
333 "The next output time is within the minimum dt of the next time. "
334 "Adjusting dt to take two steps.");
338 dt = (oTime - lastTime)/2.0;
339 time = lastTime + dt;
351 if (getStepType() ==
"Variable") {
352 if ((lastTime + dt > getFinalTime() ) ||
353 (std::fabs((lastTime+dt-getFinalTime())/(lastTime+dt)) < reltol)) {
354 printDtChanges(iStep, dt, getFinalTime() - lastTime,
355 "Adjusting dt to hit final time.");
356 dt = getFinalTime() - lastTime;
357 time = lastTime + dt;
363 "Error - Time step is not positive. dt = " << dt <<
"\n");
367 (lastTime + dt < getInitTime()), std::out_of_range,
368 "Error - Time step does not move time INTO time range.\n"
369 " [timeMin, timeMax] = [" << getInitTime() <<
", "
370 << getFinalTime() <<
"]\n"
371 " T + dt = " << lastTime <<
" + "<< dt <<
" = " << lastTime + dt <<
"\n");
373 if (getStepType() ==
"Variable") {
375 (lastTime + dt > getFinalTime()), std::out_of_range,
376 "Error - Time step move time OUT OF time range.\n"
377 " [timeMin, timeMax] = [" << getInitTime() <<
", "
378 << getFinalTime() <<
"]\n"
379 " T + dt = " << lastTime <<
" + "<< dt <<
" = " << lastTime + dt <<
"\n");
382 workingState->setTimeStep(dt);
383 workingState->setTime(time);
384 workingState->setOutput(output);
391 template<
class Scalar>
395 const int relTol = 14;
397 (getInitTime() == 0) ? 0 : 1 + (
int)std::floor(std::log10(std::fabs(getInitTime()) ) );
398 const Scalar absTolInit = std::pow(10, i-relTol);
400 (getFinalTime() == 0) ? 0 : 1 + (
int)std::floor(std::log10(std::fabs(getFinalTime()) ) );
401 const Scalar absTolFinal = std::pow(10, j-relTol);
403 const bool test1 = getInitTime() - absTolInit <= time;
404 const bool test2 = time < getFinalTime() - absTolFinal;
406 return (test1 && test2);
411 template<
class Scalar>
413 bool iir = (getInitIndex() <= iStep && iStep < getFinalIndex());
418 template<
class Scalar>
422 "Error - Can only use setNumTimeSteps() when 'Step Type' == 'Constant'.\n");
424 if (numTimeSteps >= 0) {
425 numTimeSteps_ = numTimeSteps;
426 setFinalIndex(getInitIndex() + numTimeSteps_);
428 if (numTimeSteps_ == 0)
429 initTimeStep = Scalar(0.0);
431 initTimeStep = (getFinalTime() - getInitTime())/numTimeSteps_;
432 setInitTimeStep(initTimeStep);
433 setMinTimeStep (initTimeStep);
434 setMaxTimeStep (initTimeStep);
439 *out <<
"Warning - setNumTimeSteps() Setting 'Number of Time Steps' = " << getNumTimeSteps()
440 <<
" Set the following parameters: \n"
441 <<
" 'Final Time Index' = " << getFinalIndex() <<
"\n"
442 <<
" 'Initial Time Step' = " << getInitTimeStep() <<
"\n"
443 <<
" 'Step Type' = " << getStepType() << std::endl;
445 isInitialized_ =
false;
450 template<
class Scalar>
453 std::string name =
"Tempus::TimeStepControl";
458 template<
class Scalar>
465 std::vector<int> idx = getOutputIndices();
466 std::ostringstream listIdx;
468 for(std::size_t i = 0; i < idx.size()-1; ++i) listIdx << idx[i] <<
", ";
469 listIdx << idx[idx.size()-1];
472 std::vector<Scalar> times = getOutputTimes();
473 std::ostringstream listTimes;
474 if (!times.empty()) {
475 for(std::size_t i = 0; i < times.size()-1; ++i) listTimes << times[i] <<
", ";
476 listTimes << times[times.size()-1];
479 auto l_out = Teuchos::fancyOStream( out.
getOStream() );
480 l_out->setOutputToRootOnly(0);
481 *l_out << description() <<
"::describe:" << std::endl
482 <<
"stepType = " << getStepType() << std::endl
483 <<
"initTime = " << getInitTime() << std::endl
484 <<
"finalTime = " << getFinalTime() << std::endl
485 <<
"minTimeStep = " << getMinTimeStep() << std::endl
486 <<
"initTimeStep = " << getInitTimeStep() << std::endl
487 <<
"maxTimeStep = " << getMaxTimeStep() << std::endl
488 <<
"initIndex = " << getInitIndex() << std::endl
489 <<
"finalIndex = " << getFinalIndex() << std::endl
490 <<
"maxAbsError = " << getMaxAbsError() << std::endl
491 <<
"maxRelError = " << getMaxRelError() << std::endl
492 <<
"maxFailures = " << getMaxFailures() << std::endl
493 <<
"maxConsecFailures = " << getMaxConsecFailures() << std::endl
494 <<
"numTimeSteps = " << getNumTimeSteps() << std::endl
495 <<
"printDtChanges = " << getPrintDtChanges() << std::endl
496 <<
"outputExactly = " << getOutputExactly() << std::endl
497 <<
"outputIndices = " << listIdx.str() << std::endl
498 <<
"outputTimes = " << listTimes.str() << std::endl
499 <<
"outputIndexInterval= " << getOutputIndexInterval() << std::endl
500 <<
"outputTimeInterval = " << getOutputTimeInterval() << std::endl
501 <<
"outputAdjustedDt = " << outputAdjustedDt_ << std::endl
502 <<
"dtAfterOutput = " << dtAfterOutput_ << std::endl
503 <<
"stepControlSrategy = " << std::endl;
504 stepControlStrategy_->describe(out, verbLevel);
509 template<
class Scalar>
515 if ( tscs != Teuchos::null ) {
516 stepControlStrategy_ = tscs;
518 stepControlStrategy_ =
521 isInitialized_ =
false;
525 template<
class Scalar>
531 pl->
set<
double>(
"Initial Time" , getInitTime() ,
"Initial time");
532 pl->
set<
double>(
"Final Time" , getFinalTime() ,
"Final time");
533 pl->
set<
double>(
"Minimum Time Step" , getMinTimeStep() ,
"Minimum time step size");
534 pl->
set<
double>(
"Initial Time Step" , getInitTimeStep(),
"Initial time step size");
535 pl->
set<
double>(
"Maximum Time Step" , getMaxTimeStep() ,
"Maximum time step size");
536 pl->
set<
int> (
"Initial Time Index" , getInitIndex() ,
"Initial time index");
537 pl->
set<
int> (
"Final Time Index" , getFinalIndex() ,
"Final time index");
538 pl->
set<
int> (
"Number of Time Steps", getNumTimeSteps(),
539 "The number of constant time steps. The actual step size gets computed\n"
540 "on the fly given the size of the time domain. Overides and resets\n"
541 " 'Final Time Index' = 'Initial Time Index' + 'Number of Time Steps'\n"
542 " 'Initial Time Step' = "
543 "('Final Time' - 'Initial Time')/'Number of Time Steps'\n");
544 pl->
set<
double>(
"Maximum Absolute Error", getMaxAbsError() ,
"Maximum absolute error");
545 pl->
set<
double>(
"Maximum Relative Error", getMaxRelError() ,
"Maximum relative error");
547 pl->
set<
bool> (
"Print Time Step Changes", getPrintDtChanges(),
548 "Print timestep size when it changes");
550 pl->
set<
bool>(
"Output Exactly On Output Times", getOutputExactly(),
551 "This determines if the timestep size will be adjusted to exactly land\n"
552 "on the output times for 'Variable' timestepping (default=true).\n"
553 "When set to 'false' or for 'Constant' time stepping, the timestep\n"
554 "following the output time will be flagged for output.\n");
556 pl->
set<
int> (
"Output Index Interval", getOutputIndexInterval(),
"Output index interval");
557 pl->
set<
double>(
"Output Time Interval", getOutputTimeInterval(),
"Output time interval");
560 std::vector<int> idx = getOutputIndices();
561 std::ostringstream list;
563 for(std::size_t i = 0; i < idx.size()-1; ++i) list << idx[i] <<
", ";
564 list << idx[idx.size()-1];
566 pl->
set<std::string>(
"Output Index List", list.str(),
567 "Comma deliminated list of output indices");
570 std::vector<Scalar> times = getOutputTimes();
571 std::ostringstream list;
572 if (!times.empty()) {
573 for(std::size_t i = 0; i < times.size()-1; ++i) list << times[i] <<
", ";
574 list << times[times.size()-1];
576 pl->
set<std::string>(
"Output Time List", list.str(),
577 "Comma deliminated list of output times");
580 pl->
set<
int> (
"Maximum Number of Stepper Failures", getMaxFailures(),
581 "Maximum number of Stepper failures");
582 pl->
set<
int> (
"Maximum Number of Consecutive Stepper Failures", getMaxConsecFailures(),
583 "Maximum number of consecutive Stepper failures");
585 pl->
set(
"Time Step Control Strategy", *stepControlStrategy_->getValidParameters());
593 template <
class Scalar>
601 if (pList == Teuchos::null)
return tsc;
605 tsc->setInitTime( pList->
get<
double>(
"Initial Time"));
606 tsc->setFinalTime( pList->
get<
double>(
"Final Time"));
607 tsc->setMinTimeStep( pList->
get<
double>(
"Minimum Time Step"));
608 tsc->setInitTimeStep( pList->
get<
double>(
"Initial Time Step"));
609 tsc->setMaxTimeStep( pList->
get<
double>(
"Maximum Time Step"));
610 tsc->setInitIndex( pList->
get<
int> (
"Initial Time Index"));
611 tsc->setFinalIndex( pList->
get<
int> (
"Final Time Index"));
612 tsc->setMaxAbsError( pList->
get<
double>(
"Maximum Absolute Error"));
613 tsc->setMaxRelError( pList->
get<
double>(
"Maximum Relative Error"));
614 tsc->setMaxFailures( pList->
get<
int> (
"Maximum Number of Stepper Failures"));
615 tsc->setMaxConsecFailures(pList->
get<
int> (
"Maximum Number of Consecutive Stepper Failures"));
616 tsc->setPrintDtChanges( pList->
get<
bool> (
"Print Time Step Changes"));
617 tsc->setNumTimeSteps( pList->
get<
int> (
"Number of Time Steps"));
619 tsc->setOutputExactly( pList->
get<
bool> (
"Output Exactly On Output Times"));
623 std::vector<int> outputIndices;
624 outputIndices.clear();
625 std::string str = pList->
get<std::string>(
"Output Index List");
626 std::string delimiters(
",");
627 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
628 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
629 while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
630 std::string token = str.substr(lastPos,pos-lastPos);
631 outputIndices.push_back(
int(std::stoi(token)));
632 if(pos==std::string::npos)
break;
634 lastPos = str.find_first_not_of(delimiters, pos);
635 pos = str.find_first_of(delimiters, lastPos);
639 std::sort(outputIndices.begin(),outputIndices.end());
640 tsc->setOutputIndices(outputIndices);
643 tsc->setOutputIndexInterval(pList->
get<
int>(
"Output Index Interval"));
647 std::vector<Scalar> outputTimes;
649 std::string str = pList->
get<std::string>(
"Output Time List");
650 std::string delimiters(
",");
652 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
654 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
655 while ((pos != std::string::npos) || (lastPos != std::string::npos)) {
657 std::string token = str.substr(lastPos,pos-lastPos);
658 outputTimes.push_back(Scalar(std::stod(token)));
659 if(pos==std::string::npos)
break;
661 lastPos = str.find_first_not_of(delimiters, pos);
662 pos = str.find_first_of(delimiters, lastPos);
666 std::sort(outputTimes.begin(),outputTimes.end());
667 outputTimes.erase(std::unique(outputTimes.begin(),
670 tsc->setOutputTimes(outputTimes);
673 tsc->setOutputTimeInterval(pList->
get<
double>(
"Output Time Interval"));
676 if ( !pList->
isParameter(
"Time Step Control Strategy") ) {
678 tsc->setTimeStepControlStrategy();
682 RCP<ParameterList> tscsPL =
683 Teuchos::sublist(pList,
"Time Step Control Strategy",
true);
685 auto strategyType = tscsPL->get<std::string>(
"Strategy Type");
686 if (strategyType ==
"Constant") {
687 tsc->setTimeStepControlStrategy(
688 createTimeStepControlStrategyConstant<Scalar>(tscsPL));
689 }
else if (strategyType ==
"Basic VS") {
690 tsc->setTimeStepControlStrategy(
691 createTimeStepControlStrategyBasicVS<Scalar>(tscsPL));
692 }
else if (strategyType ==
"Integral Controller") {
693 tsc->setTimeStepControlStrategy(
694 createTimeStepControlStrategyIntegralController<Scalar>(tscsPL));
695 }
else if (strategyType ==
"Composite") {
696 tsc->setTimeStepControlStrategy(
697 createTimeStepControlStrategyComposite<Scalar>(tscsPL));
699 RCP<Teuchos::FancyOStream> out =
700 Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
701 out->setOutputToRootOnly(0);
703 *out <<
"Warning -- Did not find a Tempus strategy to create!\n"
704 <<
"'Strategy Type' = '" << strategyType <<
"'\n"
705 <<
"Should call setTimeStepControlStrategy() with this\n"
706 <<
"(app-specific?) strategy, and initialize().\n" << std::endl;
710 if (runInitialize) tsc->initialize();
716 #endif // Tempus_TimeStepControl_impl_hpp
virtual void checkInitialized()
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)
std::string description() const
virtual void printDtChanges(int istep, Scalar dt_old, Scalar dt_new, std::string reason) const
bool isParameter(const std::string &name) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void setTimeStepControlStrategy(Teuchos::RCP< TimeStepControlStrategy< Scalar > > tscs=Teuchos::null)
Status
Status for the Integrator, the Stepper and the SolutionState.
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)
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
StepControlStrategy class for TimeStepControl.
virtual int getNumTimeSteps() const
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
virtual void setNextTimeStep(const Teuchos::RCP< SolutionHistory< Scalar > > &solutionHistory, Status &integratorStatus)
Determine the time step size.
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
TimeStepControlStrategy class for TimeStepControl.
virtual void initialize() const
virtual Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Return ParameterList with current values.