void ForwardEulerSolver::solve(double &pVoi, double pVoiEnd) const { // Y_n+1 = Y_n + h * f(t_n, Y_n) double voiStart = pVoi; int stepNumber = 0; double realStep = mStep; while (!qFuzzyCompare(pVoi, pVoiEnd)) { // Check that the time step is correct if (pVoi+realStep > pVoiEnd) { realStep = pVoiEnd-pVoi; } // Compute f(t_n, Y_n) mComputeRates(pVoi, mConstants, mRates, mStates, mAlgebraic); // Compute Y_n+1 for (int i = 0; i < mRatesStatesCount; ++i) { mStates[i] += realStep*mRates[i]; } // Advance through time if (!qFuzzyCompare(realStep, mStep)) { pVoi = pVoiEnd; } else { pVoi = voiStart+(++stepNumber)*mStep; } } }
void CvodeSolver::solve(double &pVoi, const double &pVoiEnd) const { // Solve the model CVode(mSolver, pVoiEnd, mStatesVector, &pVoi, CV_NORMAL); // Compute the rates one more time to get up-to-date values for the rates // Note: another way of doing this would be to copy the contents of the // calculated rates in rhsFunction, but that's bound to be more time // consuming since a call to CVode is likely to generate at least a // few calls to rhsFunction, so that would be quite a few memory // transfers while here we 'only' compute the rates one more time, // so... mComputeRates(pVoiEnd, mConstants, mRates, N_VGetArrayPointer_Serial(mStatesVector), mAlgebraic); }
void FourthOrderRungeKuttaSolver::solve(double &pVoi, const double &pVoiEnd) const { // k1 = h * f(t_n, Y_n) // k2 = h * f(t_n + h / 2, Y_n + k1 / 2) // k3 = h * f(t_n + h / 2, Y_n + k2 / 2) // k4 = h * f(t_n + h, Y_n + k3) // Y_n+1 = Y_n + k1 / 6 + k2 / 3 + k3 / 3 + k4 / 6 // Note: the algorithm hereafter doesn't compute k1, k2, k3 and k4 as such // and this simply for performance reasons... static const double OneOverThree = 1.0/3.0; static const double OneOverSix = 1.0/6.0; double voiStart = pVoi; int stepNumber = 0; double realStep = mStep; double realHalfStep = 0.5*realStep; while (pVoi != pVoiEnd) { // Check that the time step is correct if (pVoi+realStep > pVoiEnd) { realStep = pVoiEnd-pVoi; realHalfStep = 0.5*realStep; } // Compute f(t_n, Y_n) mComputeRates(pVoi, mConstants, mRates, mStates, mAlgebraic); // Compute k1 and Yk1 for (int i = 0; i < mRatesStatesCount; ++i) { mK1[i] = mRates[i]; mYk123[i] = mStates[i]+realHalfStep*mK1[i]; } // Compute f(t_n + h / 2, Y_n + k1 / 2) mComputeRates(pVoi+realHalfStep, mConstants, mRates, mYk123, mAlgebraic); // Compute k2 and Yk2 for (int i = 0; i < mRatesStatesCount; ++i) { mK23[i] = mRates[i]; mYk123[i] = mStates[i]+realHalfStep*mK23[i]; } // Compute f(t_n + h / 2, Y_n + k2 / 2) mComputeRates(pVoi+realHalfStep, mConstants, mRates, mYk123, mAlgebraic); // Compute k3 and Yk3 for (int i = 0; i < mRatesStatesCount; ++i) { mK23[i] += mRates[i]; mYk123[i] = mStates[i]+realStep*mK23[i]; } // Compute f(t_n + h, Y_n + k3) mComputeRates(pVoi+realStep, mConstants, mRates, mYk123, mAlgebraic); // Compute k4 and therefore Y_n+1 for (int i = 0; i < mRatesStatesCount; ++i) mStates[i] += realStep*(OneOverSix*(mK1[i]+mRates[i])+OneOverThree*mK23[i]); // Advance through time if (realStep != mStep) pVoi = pVoiEnd; else pVoi = voiStart+(++stepNumber)*mStep; } }