BackwardEulerIvpOdeSolver.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
00037 #include "BackwardEulerIvpOdeSolver.hpp"
00038 #include <cmath>
00039
00040 void BackwardEulerIvpOdeSolver::ComputeResidual(AbstractOdeSystem* pAbstractOdeSystem,
00041 double timeStep,
00042 double time,
00043 std::vector<double>& rCurrentYValues,
00044 std::vector<double>& rCurrentGuess)
00045 {
00046 std::vector<double> dy(mSizeOfOdeSystem);
00047 pAbstractOdeSystem->EvaluateYDerivatives(time+timeStep, rCurrentGuess, dy);
00048 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00049 {
00050 mResidual[i] = rCurrentGuess[i] - timeStep * dy[i] - rCurrentYValues[i];
00051 }
00052 }
00053
00054 void BackwardEulerIvpOdeSolver::ComputeJacobian(AbstractOdeSystem* pAbstractOdeSystem,
00055 double timeStep,
00056 double time,
00057 std::vector<double>& rCurrentYValues,
00058 std::vector<double>& rCurrentGuess)
00059 {
00060 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00061 {
00062 for (unsigned j=0; j<mSizeOfOdeSystem; j++)
00063 {
00064 mJacobian[i][j] = 0.0;
00065 }
00066 }
00067
00068 if (pAbstractOdeSystem->GetUseAnalyticJacobian() && !mForceUseOfNumericalJacobian)
00069 {
00070
00071 AbstractOdeSystemWithAnalyticJacobian* p_ode_system
00072 = static_cast<AbstractOdeSystemWithAnalyticJacobian*>(pAbstractOdeSystem);
00073 p_ode_system->AnalyticJacobian(rCurrentGuess, mJacobian, time, timeStep);
00074 }
00075 else
00076 {
00077 ComputeNumericalJacobian(pAbstractOdeSystem,
00078 timeStep,
00079 time,
00080 rCurrentYValues,
00081 rCurrentGuess);
00082 }
00083 }
00084
00085 void BackwardEulerIvpOdeSolver::SolveLinearSystem()
00086 {
00087 double fact;
00088 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00089 {
00090 for (unsigned ii=i+1; ii<mSizeOfOdeSystem; ii++)
00091 {
00092 fact = mJacobian[ii][i]/mJacobian[i][i];
00093 for (unsigned j=i; j<mSizeOfOdeSystem; j++)
00094 {
00095 mJacobian[ii][j] -= fact*mJacobian[i][j];
00096 }
00097 mResidual[ii] -= fact*mResidual[i];
00098 }
00099 }
00100
00101 for (int i=mSizeOfOdeSystem-1; i>=0; i--)
00102 {
00103 mUpdate[i] = mResidual[i];
00104 for (unsigned j=i+1; j<mSizeOfOdeSystem; j++)
00105 {
00106 mUpdate[i] -= mJacobian[i][j]*mUpdate[j];
00107 }
00108 mUpdate[i] /= mJacobian[i][i];
00109 }
00110 }
00111
00112 double BackwardEulerIvpOdeSolver::ComputeNorm(double* pVector)
00113 {
00114 double norm = 0.0;
00115 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00116 {
00117 if (fabs(pVector[i]) > norm)
00118 {
00119 norm = fabs(pVector[i]);
00120 }
00121 }
00122 return norm;
00123 }
00124
00125 void BackwardEulerIvpOdeSolver::ComputeNumericalJacobian(AbstractOdeSystem* pAbstractOdeSystem,
00126 double timeStep,
00127 double time,
00128 std::vector<double>& rCurrentYValues,
00129 std::vector<double>& rCurrentGuess)
00130 {
00131 std::vector<double> residual(mSizeOfOdeSystem);
00132 std::vector<double> residual_perturbed(mSizeOfOdeSystem);
00133 std::vector<double> guess_perturbed(mSizeOfOdeSystem);
00134
00135 double epsilon = mNumericalJacobianEpsilon;
00136
00137 ComputeResidual(pAbstractOdeSystem, timeStep, time, rCurrentYValues, rCurrentGuess);
00138 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00139 {
00140 residual[i] = mResidual[i];
00141 }
00142
00143 for (unsigned global_column=0; global_column<mSizeOfOdeSystem; global_column++)
00144 {
00145 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00146 {
00147 guess_perturbed[i] = rCurrentGuess[i];
00148 }
00149
00150 guess_perturbed[global_column] += epsilon;
00151
00152 ComputeResidual(pAbstractOdeSystem, timeStep, time, rCurrentYValues, guess_perturbed);
00153 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00154 {
00155 residual_perturbed[i] = mResidual[i];
00156 }
00157
00158
00159 double one_over_eps = 1.0/epsilon;
00160 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00161 {
00162 mJacobian[i][global_column] = one_over_eps*(residual_perturbed[i] - residual[i]);
00163 }
00164 }
00165 }
00166
00167 void BackwardEulerIvpOdeSolver::CalculateNextYValue(AbstractOdeSystem* pAbstractOdeSystem,
00168 double timeStep,
00169 double time,
00170 std::vector<double>& rCurrentYValues,
00171 std::vector<double>& rNextYValues)
00172 {
00173
00174 assert(mSizeOfOdeSystem == pAbstractOdeSystem->GetNumberOfStateVariables());
00175
00176 unsigned counter = 0;
00177
00178 const double eps = 1e-6;
00179 double norm = 2*eps;
00180
00181 std::vector<double> current_guess(mSizeOfOdeSystem);
00182 current_guess.assign(rCurrentYValues.begin(), rCurrentYValues.end());
00183
00184 while (norm > eps)
00185 {
00186
00187 ComputeResidual(pAbstractOdeSystem, timeStep, time, rCurrentYValues, current_guess);
00188 ComputeJacobian(pAbstractOdeSystem, timeStep, time, rCurrentYValues, current_guess);
00189
00190
00191
00192
00193 SolveLinearSystem();
00194
00195
00196 norm = ComputeNorm(mUpdate);
00197
00198
00199 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00200 {
00201 current_guess[i] -= mUpdate[i];
00202 }
00203
00204 counter++;
00205 assert(counter < 20);
00206 }
00207 rNextYValues.assign(current_guess.begin(), current_guess.end());
00208 }
00209
00210 BackwardEulerIvpOdeSolver::BackwardEulerIvpOdeSolver(unsigned sizeOfOdeSystem)
00211 {
00212 mSizeOfOdeSystem = sizeOfOdeSystem;
00213
00214
00215 mNumericalJacobianEpsilon = 1e-6;
00216 mForceUseOfNumericalJacobian = false;
00217
00218
00219 mResidual = new double[mSizeOfOdeSystem];
00220 mUpdate = new double[mSizeOfOdeSystem];
00221
00222 mJacobian = new double*[mSizeOfOdeSystem];
00223 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00224 {
00225 mJacobian[i] = new double[mSizeOfOdeSystem];
00226 }
00227 }
00228
00229 BackwardEulerIvpOdeSolver::~BackwardEulerIvpOdeSolver()
00230 {
00231
00232 delete[] mResidual;
00233 delete[] mUpdate;
00234
00235 for (unsigned i=0; i<mSizeOfOdeSystem; i++)
00236 {
00237 delete[] mJacobian[i];
00238 }
00239 delete[] mJacobian;
00240 }
00241
00242 void BackwardEulerIvpOdeSolver::SetEpsilonForNumericalJacobian(double epsilon)
00243 {
00244 assert(epsilon > 0);
00245 mNumericalJacobianEpsilon = epsilon;
00246 }
00247
00248 void BackwardEulerIvpOdeSolver::ForceUseOfNumericalJacobian()
00249 {
00250 mForceUseOfNumericalJacobian = true;
00251 }
00252
00253
00254
00255 #include "SerializationExportWrapperForCpp.hpp"
00256 CHASTE_CLASS_EXPORT(BackwardEulerIvpOdeSolver)