TimeStepper.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <cassert>
00037 #include <cmath>
00038
00039 #include "TimeStepper.hpp"
00040 #include "Exception.hpp"
00041 #include "MathsCustomFunctions.hpp"
00042
00043 TimeStepper::TimeStepper(double startTime, double endTime, double dt, bool enforceConstantTimeStep, std::vector<double> additionalTimes)
00044 : mStart(startTime),
00045 mEnd(endTime),
00046 mDt(dt),
00047 mTotalTimeStepsTaken(0),
00048 mAdditionalTimesReachedDeprecated(0),
00049 mTime(startTime),
00050 mEpsilon(DBL_EPSILON)
00051 {
00052 if (startTime > endTime)
00053 {
00054 EXCEPTION("The simulation duration must be positive, not " << endTime-startTime);
00055 }
00056
00057
00058 for (unsigned i=0; i<additionalTimes.size(); i++)
00059 {
00060 if (i > 0)
00061 {
00062 if (additionalTimes[i-1] >= additionalTimes[i])
00063 {
00064 EXCEPTION("The additional times vector should be in ascending numerical order; "
00065 "entry " << i << " is less than or equal to entry " << i-1 << ".");
00066 }
00067 }
00068
00069 double time_interval = additionalTimes[i] - startTime;
00070
00071
00072 if (!Divides(mDt, time_interval) && (time_interval > DBL_EPSILON))
00073 {
00074
00075 EXCEPTION("Additional times are now deprecated. Use only to check whether the given times are met: e.g. Electrode events should only happen on printing steps.");
00076 }
00077 }
00078
00079
00080
00081
00082
00083
00084 if (mEnd > 1.0)
00085 {
00086 mEpsilon = DBL_EPSILON*mEnd;
00087 }
00088
00089
00090 if (enforceConstantTimeStep)
00091 {
00092 double expected_end_time = mStart + mDt*EstimateTimeSteps();
00093
00094 if (fabs( mEnd - expected_end_time ) > mEpsilon)
00095 {
00096 EXCEPTION("TimeStepper estimates non-constant timesteps will need to be used: check timestep "
00097 "divides (end_time-start_time) (or divides printing timestep). "
00098 "[End time=" << mEnd << "; start=" << mStart << "; dt=" << mDt << "; error="
00099 << fabs(mEnd-expected_end_time) << "]");
00100 }
00101 }
00102
00103 mNextTime = CalculateNextTime();
00104 }
00105
00106 double TimeStepper::CalculateNextTime()
00107 {
00108 double next_time = mStart + (mTotalTimeStepsTaken + 1)*mDt;
00109
00110
00111
00112
00113 if (mEnd - next_time <= mEpsilon)
00114 {
00115 next_time = mEnd;
00116 }
00117
00118 assert(mAdditionalTimesDeprecated.empty());
00119
00120 return next_time;
00121 }
00122
00123 void TimeStepper::AdvanceOneTimeStep()
00124 {
00125 mTotalTimeStepsTaken++;
00126 if (mTotalTimeStepsTaken == 0)
00127 {
00128 EXCEPTION("Time step counter has overflowed.");
00129 }
00130 if (mTime >= mNextTime)
00131 {
00132 EXCEPTION("TimeStepper incremented beyond end time.");
00133 }
00134 mTime = mNextTime;
00135
00136 mNextTime = CalculateNextTime();
00137 }
00138
00139 double TimeStepper::GetTime() const
00140 {
00141 return mTime;
00142 }
00143
00144 double TimeStepper::GetNextTime() const
00145 {
00146 return mNextTime;
00147 }
00148
00149 double TimeStepper::GetNextTimeStep()
00150 {
00151 double dt = mDt;
00152
00153 if (mNextTime >= mEnd)
00154 {
00155 dt = mEnd - mTime;
00156 }
00157 assert(mAdditionalTimesDeprecated.empty());
00158 return dt;
00159 }
00160 double TimeStepper::GetIdealTimeStep()
00161 {
00162 return mDt;
00163 }
00164
00165 bool TimeStepper::IsTimeAtEnd() const
00166 {
00167 return (mTime >= mEnd);
00168 }
00169
00170 unsigned TimeStepper::EstimateTimeSteps() const
00171 {
00172 return (unsigned) floor((mEnd - mStart)/mDt + 0.5);
00173 }
00174
00175 unsigned TimeStepper::GetTotalTimeStepsTaken() const
00176 {
00177 return mTotalTimeStepsTaken;
00178 }
00179
00180 void TimeStepper::ResetTimeStep(double dt)
00181 {
00182 assert(dt > 0);
00183
00184
00185
00186
00187
00188
00189 double scale = DBL_EPSILON*(mDt + dt);
00190 if (mDt + dt < 1.0)
00191 {
00192 scale = DBL_EPSILON;
00193 }
00194 if (fabs(mDt-dt) > scale)
00195 {
00196 mDt = dt;
00197 mStart = mTime;
00198 mTotalTimeStepsTaken = 0;
00199
00200 mNextTime = CalculateNextTime();
00201 }
00202 }