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 "RungeKuttaFehlbergIvpOdeSolver.hpp"
00037 #include <cmath>
00038 #include <cfloat>
00039 #include <iostream>
00040 #include "Exception.hpp"
00041
00042
00043
00044
00045
00046 void RungeKuttaFehlbergIvpOdeSolver::InternalSolve(OdeSolution& rSolution,
00047 AbstractOdeSystem* pOdeSystem,
00048 std::vector<double>& rYValues,
00049 std::vector<double>& rWorkingMemory,
00050 double startTime,
00051 double endTime,
00052 double maxTimeStep,
00053 double minTimeStep,
00054 double tolerance,
00055 bool outputSolution)
00056 {
00057 const unsigned number_of_variables = pOdeSystem->GetNumberOfStateVariables();
00058 mError.resize(number_of_variables);
00059 mk1.resize(number_of_variables);
00060 mk2.resize(number_of_variables);
00061 mk3.resize(number_of_variables);
00062 mk4.resize(number_of_variables);
00063 mk5.resize(number_of_variables);
00064 mk6.resize(number_of_variables);
00065 myk2.resize(number_of_variables);
00066 myk3.resize(number_of_variables);
00067 myk4.resize(number_of_variables);
00068 myk5.resize(number_of_variables);
00069 myk6.resize(number_of_variables);
00070
00071 double current_time = startTime;
00072 double time_step = maxTimeStep;
00073 bool got_to_end = false;
00074 bool accurate_enough = false;
00075 unsigned number_of_time_steps = 0;
00076
00077 if (outputSolution)
00078 {
00079 rSolution.rGetTimes().push_back(current_time);
00080 rSolution.rGetSolutions().push_back(rYValues);
00081 }
00082
00083
00084 assert(!mStoppingEventOccurred);
00085 while (!got_to_end)
00086 {
00087
00088 while (!accurate_enough)
00089 {
00090 accurate_enough = true;
00091
00092
00093 CalculateNextYValue(pOdeSystem,
00094 time_step,
00095 current_time,
00096 rYValues,
00097 rWorkingMemory);
00098
00099
00100 double max_error = -DBL_MAX;
00101 for (unsigned i=0; i<number_of_variables; i++)
00102 {
00103 if (mError[i] > max_error)
00104 {
00105 max_error = mError[i];
00106 }
00107 }
00108
00109 if (max_error > tolerance)
00110 {
00111 accurate_enough = false;
00112
00113 }
00114 else
00115 {
00116
00117 current_time = current_time + time_step;
00118
00119
00120 if (outputSolution)
00121 {
00122
00123 rSolution.rGetTimes().push_back(current_time);
00124 rSolution.rGetSolutions().push_back(rWorkingMemory);
00125 number_of_time_steps++;
00126 }
00127 }
00128
00129
00130 AdjustStepSize(time_step, max_error, tolerance, maxTimeStep, minTimeStep);
00131 }
00132
00133
00134 if (current_time + time_step > endTime)
00135 {
00136 time_step = endTime - current_time;
00137 }
00138
00139 if ( pOdeSystem->CalculateStoppingEvent(current_time,
00140 rWorkingMemory) == true )
00141 {
00142 mStoppingTime = current_time;
00143 mStoppingEventOccurred = true;
00144 }
00145
00146 if (mStoppingEventOccurred || current_time>=endTime)
00147 {
00148 got_to_end = true;
00149 }
00150
00151
00152 rYValues.assign(rWorkingMemory.begin(), rWorkingMemory.end());
00153 accurate_enough = false;
00154
00155 }
00156 rSolution.SetNumberOfTimeSteps(number_of_time_steps);
00157 }
00158
00159 void RungeKuttaFehlbergIvpOdeSolver::CalculateNextYValue(AbstractOdeSystem* pAbstractOdeSystem,
00160 double timeStep,
00161 double time,
00162 std::vector<double>& rCurrentYValues,
00163 std::vector<double>& rNextYValues)
00164 {
00165 const unsigned num_equations = pAbstractOdeSystem->GetNumberOfStateVariables();
00166
00167
00168 std::vector<double>& dy = rNextYValues;
00169
00170 pAbstractOdeSystem->EvaluateYDerivatives(time, rCurrentYValues, dy);
00171
00172 for (unsigned i=0; i<num_equations; i++)
00173 {
00174 mk1[i] = timeStep*dy[i];
00175 myk2[i] = rCurrentYValues[i] + 0.25*mk1[i];
00176 }
00177
00178 pAbstractOdeSystem->EvaluateYDerivatives(time + 0.25*timeStep, myk2, dy);
00179 for (unsigned i=0; i<num_equations; i++)
00180 {
00181 mk2[i] = timeStep*dy[i];
00182 myk3[i] = rCurrentYValues[i] + 0.09375*mk1[i] + 0.28125*mk2[i];
00183 }
00184
00185 pAbstractOdeSystem->EvaluateYDerivatives(time + 0.375*timeStep, myk3, dy);
00186 for (unsigned i=0; i<num_equations; i++)
00187 {
00188 mk3[i] = timeStep*dy[i];
00189 myk4[i] = rCurrentYValues[i] + m1932o2197*mk1[i] - m7200o2197*mk2[i]
00190 + m7296o2197*mk3[i];
00191 }
00192
00193 pAbstractOdeSystem->EvaluateYDerivatives(time+m12o13*timeStep, myk4, dy);
00194 for (unsigned i=0; i<num_equations; i++)
00195 {
00196 mk4[i] = timeStep*dy[i];
00197 myk5[i] = rCurrentYValues[i] + m439o216*mk1[i] - 8*mk2[i]
00198 + m3680o513*mk3[i]- m845o4104*mk4[i];
00199 }
00200
00201 pAbstractOdeSystem->EvaluateYDerivatives(time+timeStep, myk5, dy);
00202 for (unsigned i=0; i<num_equations; i++)
00203 {
00204 mk5[i] = timeStep*dy[i];
00205 myk6[i] = rCurrentYValues[i] - m8o27*mk1[i] + 2*mk2[i] - m3544o2565*mk3[i]
00206 + m1859o4104*mk4[i] - 0.275*mk5[i];
00207 }
00208
00209 pAbstractOdeSystem->EvaluateYDerivatives(time+0.5*timeStep, myk6, dy);
00210 for (unsigned i=0; i<num_equations; i++)
00211 {
00212 mk6[i] = timeStep*dy[i];
00213 mError[i] = (1/timeStep)*fabs(m1o360*mk1[i] - m128o4275*mk3[i]
00214 - m2197o75240*mk4[i] + 0.02*mk5[i]+ m2o55*mk6[i]);
00215 rNextYValues[i] = rCurrentYValues[i] + m25o216*mk1[i] + m1408o2565*mk3[i]
00216 + m2197o4104*mk4[i] - 0.2*mk5[i];
00217 }
00218 }
00219
00220 void RungeKuttaFehlbergIvpOdeSolver::AdjustStepSize(double& rCurrentStepSize,
00221 const double& rError,
00222 const double& rTolerance,
00223 const double& rMaxTimeStep,
00224 const double& rMinTimeStep)
00225 {
00226
00227 double delta = pow(rTolerance/(2.0*rError), 0.25);
00228
00229
00230 if (delta <= 0.1)
00231 {
00232 rCurrentStepSize *= 0.1;
00233 }
00234 else if (delta >= 4.0)
00235 {
00236 rCurrentStepSize *= 4.0;
00237 }
00238 else
00239 {
00240 rCurrentStepSize *= delta;
00241 }
00242
00243 if (rCurrentStepSize > rMaxTimeStep)
00244 {
00245 rCurrentStepSize = rMaxTimeStep;
00246 }
00247
00248 if (rCurrentStepSize < rMinTimeStep)
00249 {
00250 std::cout << "rCurrentStepSize = " << rCurrentStepSize << "\n" << std::flush;
00251 std::cout << "rMinTimeStep = " << rMinTimeStep << "\n" << std::flush;
00252
00253 EXCEPTION("RKF45 Solver: Ode needs a smaller timestep than the set minimum\n");
00254 }
00255
00256 }
00257
00258
00259
00260
00261
00262
00263 RungeKuttaFehlbergIvpOdeSolver::RungeKuttaFehlbergIvpOdeSolver()
00264 : m1932o2197(1932.0/2197.0),
00265 m7200o2197(7200.0/2197.0),
00266 m7296o2197(7296.0/2197.0),
00267 m12o13(12.0/13.0),
00268 m439o216(439.0/216.0),
00269 m3680o513(3680.0/513.0),
00270 m845o4104(845.0/4104.0),
00271 m8o27(8.0/27.0),
00272 m3544o2565(3544.0/2565.0),
00273 m1859o4104(1859.0/4104.0),
00274 m1o360(1.0/360.0),
00275 m128o4275(128.0/4275.0),
00276 m2197o75240(2197.0/75240.0),
00277 m2o55(2.0/55.0),
00278 m25o216(25.0/216.0),
00279 m1408o2565(1408.0/2565.0),
00280 m2197o4104(2197.0/4104.0)
00281 {
00282 }
00283
00284 OdeSolution RungeKuttaFehlbergIvpOdeSolver::Solve(AbstractOdeSystem* pOdeSystem,
00285 std::vector<double>& rYValues,
00286 double startTime,
00287 double endTime,
00288 double timeStep,
00289 double tolerance)
00290 {
00291 assert(rYValues.size()==pOdeSystem->GetNumberOfStateVariables());
00292 assert(endTime > startTime);
00293 assert(timeStep > 0.0);
00294
00295 mStoppingEventOccurred = false;
00296 if ( pOdeSystem->CalculateStoppingEvent(startTime, rYValues) == true )
00297 {
00298 EXCEPTION("(Solve with sampling) Stopping event is true for initial condition");
00299 }
00300
00301 std::vector<double> working_memory(rYValues.size());
00302
00303 OdeSolution solutions;
00304
00305 bool return_solution = true;
00306 InternalSolve(solutions, pOdeSystem, rYValues, working_memory, startTime, endTime, timeStep, 1e-5, tolerance, return_solution);
00307 return solutions;
00308 }
00309
00310 void RungeKuttaFehlbergIvpOdeSolver::Solve(AbstractOdeSystem* pOdeSystem,
00311 std::vector<double>& rYValues,
00312 double startTime,
00313 double endTime,
00314 double timeStep)
00315 {
00316 assert(rYValues.size()==pOdeSystem->GetNumberOfStateVariables());
00317 assert(endTime > startTime);
00318 assert(timeStep > 0.0);
00319
00320 mStoppingEventOccurred = false;
00321 if ( pOdeSystem->CalculateStoppingEvent(startTime, rYValues) == true )
00322 {
00323 EXCEPTION("(Solve without sampling) Stopping event is true for initial condition");
00324 }
00325
00326 std::vector<double> working_memory(rYValues.size());
00327
00328 OdeSolution not_required_solution;
00329 bool return_solution = false;
00330 InternalSolve(not_required_solution, pOdeSystem, rYValues, working_memory, startTime, endTime, timeStep, 1e-4, 1e-5, return_solution);
00331 }
00332
00333
00334
00335 #include "SerializationExportWrapperForCpp.hpp"
00336 CHASTE_CLASS_EXPORT(RungeKuttaFehlbergIvpOdeSolver)