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