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 #include "BackwardEulerLuoRudyIModel1991.hpp"
00029 #include "Exception.hpp"
00030 #include "CardiacNewtonSolver.hpp"
00031 #include "OdeSystemInformation.hpp"
00032
00033 #include <cmath>
00034 #include <cassert>
00035
00036
00037
00041 BackwardEulerLuoRudyIModel1991::BackwardEulerLuoRudyIModel1991(
00042 AbstractStimulusFunction *pIntracellularStimulus)
00043 : AbstractBackwardEulerCardiacCell<1>(8, 4, pIntracellularStimulus)
00044 {
00045 Init();
00046 }
00047
00048
00052 BackwardEulerLuoRudyIModel1991::BackwardEulerLuoRudyIModel1991(
00053 AbstractIvpOdeSolver *pSolver,
00054 AbstractStimulusFunction *pIntracellularStimulus)
00055 : AbstractBackwardEulerCardiacCell<1>(8, 4, pIntracellularStimulus)
00056 {
00057 Init();
00058 }
00059
00060
00064 BackwardEulerLuoRudyIModel1991::~BackwardEulerLuoRudyIModel1991(void)
00065 {
00066 }
00067
00068
00069 void BackwardEulerLuoRudyIModel1991::Init()
00070 {
00071 mpSystemInfo = OdeSystemInformation<BackwardEulerLuoRudyIModel1991>::Instance();
00072
00073
00074 fast_sodium_current_E_Na = ((membrane_R * membrane_T) / membrane_F) *
00075 log(ionic_concentrations_Nao / ionic_concentrations_Nai);
00076
00077 AbstractCardiacCell::Init();
00078 }
00079
00080 template<>
00081 void OdeSystemInformation<BackwardEulerLuoRudyIModel1991>::Initialise(void)
00082 {
00083 this->mVariableNames.push_back("h");
00084 this->mVariableUnits.push_back("");
00085 this->mInitialConditions.push_back(0.9804713);
00086
00087 this->mVariableNames.push_back("j");
00088 this->mVariableUnits.push_back("");
00089 this->mInitialConditions.push_back(0.98767124);
00090
00091 this->mVariableNames.push_back("m");
00092 this->mVariableUnits.push_back("");
00093 this->mInitialConditions.push_back(0.00187018);
00094
00095 this->mVariableNames.push_back("CaI");
00096 this->mVariableUnits.push_back("mMol");
00097 this->mInitialConditions.push_back(0.0002);
00098
00099 this->mVariableNames.push_back("V");
00100 this->mVariableUnits.push_back("mV");
00101 this->mInitialConditions.push_back(-83.853);
00102
00103 this->mVariableNames.push_back("d");
00104 this->mVariableUnits.push_back("");
00105 this->mInitialConditions.push_back(0.00316354);
00106
00107 this->mVariableNames.push_back("f");
00108 this->mVariableUnits.push_back("");
00109 this->mInitialConditions.push_back(0.99427859);
00110
00111 this->mVariableNames.push_back("x");
00112 this->mVariableUnits.push_back("");
00113 this->mInitialConditions.push_back(0.16647703);
00114
00115 this->mInitialised = true;
00116 }
00117
00118 double BackwardEulerLuoRudyIModel1991::GetIntracellularCalciumConcentration()
00119 {
00120 return mStateVariables[3];
00121 }
00122
00123
00124 void BackwardEulerLuoRudyIModel1991::UpdateTransmembranePotential(double time)
00125 {
00126
00127 std::vector<double> &rY = rGetStateVariables();
00128
00129 double fast_sodium_current_h_gate_h = rY[0];
00130 double fast_sodium_current_j_gate_j = rY[1];
00131 double fast_sodium_current_m_gate_m = rY[2];
00132 double intracellular_calcium_concentration_Cai = rY[3];
00133 double membrane_V = rY[4];
00134 double slow_inward_current_d_gate_d = rY[5];
00135 double slow_inward_current_f_gate_f = rY[6];
00136 double time_dependent_potassium_current_X_gate_X = rY[7];
00137
00138 double background_current_i_b = background_current_g_b*(membrane_V-background_current_E_b);
00139 double fast_sodium_current_i_Na = fast_sodium_current_g_Na*pow(fast_sodium_current_m_gate_m, 3.0)*fast_sodium_current_h_gate_h*fast_sodium_current_j_gate_j*(membrane_V-fast_sodium_current_E_Na);
00140 double slow_inward_current_E_si = 7.7-13.0287*log(intracellular_calcium_concentration_Cai);
00141 double slow_inward_current_i_si = 0.09*slow_inward_current_d_gate_d*slow_inward_current_f_gate_f*(membrane_V-slow_inward_current_E_si);
00142
00143 double time_dependent_potassium_current_g_K = 0.282*sqrt(ionic_concentrations_Ko/5.4);
00144 double time_dependent_potassium_current_Xi_gate_Xi;
00145
00146 if (membrane_V > -100.0)
00147 {
00148 time_dependent_potassium_current_Xi_gate_Xi = 2.837*(exp(0.04*(membrane_V+77.0))-1.0)/((membrane_V+77.0)*exp(0.04*(membrane_V+35.0)));
00149 }
00150 else
00151 {
00152 #define COVERAGE_IGNORE
00153 time_dependent_potassium_current_Xi_gate_Xi = 1.0;
00154 #undef COVERAGE_IGNORE
00155 }
00156
00157 double time_dependent_potassium_current_E_K = ((membrane_R*membrane_T)/membrane_F)*log((ionic_concentrations_Ko+time_dependent_potassium_current_PR_NaK*ionic_concentrations_Nao)/(ionic_concentrations_Ki+time_dependent_potassium_current_PR_NaK*ionic_concentrations_Nai));
00158 double time_dependent_potassium_current_i_K = time_dependent_potassium_current_g_K*time_dependent_potassium_current_X_gate_X*time_dependent_potassium_current_Xi_gate_Xi*(membrane_V-time_dependent_potassium_current_E_K);
00159 double time_independent_potassium_current_g_K1 = 0.6047*sqrt(ionic_concentrations_Ko/5.4);
00160 double time_independent_potassium_current_E_K1 =((membrane_R*membrane_T)/membrane_F)*log(ionic_concentrations_Ko/ionic_concentrations_Ki);
00161 double time_independent_potassium_current_K1_gate_alpha_K1 = 1.02/(1.0+exp(0.2385*(membrane_V-time_independent_potassium_current_E_K1-59.215)));
00162 double time_independent_potassium_current_K1_gate_beta_K1 = (0.49124*exp(0.08032*(membrane_V+5.476-time_independent_potassium_current_E_K1))+exp(0.06175*(membrane_V-(time_independent_potassium_current_E_K1+594.31))))/(1.0+exp(-0.5143*(membrane_V-time_independent_potassium_current_E_K1+4.753)));
00163 double time_independent_potassium_current_K1_gate_K1_infinity = time_independent_potassium_current_K1_gate_alpha_K1/(time_independent_potassium_current_K1_gate_alpha_K1+time_independent_potassium_current_K1_gate_beta_K1);
00164 double time_independent_potassium_current_i_K1 = time_independent_potassium_current_g_K1*time_independent_potassium_current_K1_gate_K1_infinity*(membrane_V-time_independent_potassium_current_E_K1);
00165 double plateau_potassium_current_Kp = 1.0/(1.0+exp((7.488-membrane_V)/5.98));
00166 double plateau_potassium_current_E_Kp = time_independent_potassium_current_E_K1;
00167 double plateau_potassium_current_i_Kp = plateau_potassium_current_g_Kp*plateau_potassium_current_Kp*(membrane_V-plateau_potassium_current_E_Kp);
00168 double i_stim = GetStimulus(time);
00169
00170
00171 double membrane_V_prime = (-1.0/membrane_C)*(fast_sodium_current_i_Na+slow_inward_current_i_si+time_dependent_potassium_current_i_K+time_independent_potassium_current_i_K1+plateau_potassium_current_i_Kp+background_current_i_b + i_stim);
00172
00173 rY[4] += mDt * membrane_V_prime;
00174 }
00175
00176 void BackwardEulerLuoRudyIModel1991::ComputeOneStepExceptVoltage(double tStart)
00177 {
00178
00179
00180 std::vector<double>& rY = rGetStateVariables();
00181 double fast_sodium_current_h_gate_h = rY[0];
00182 double fast_sodium_current_j_gate_j = rY[1];
00183 double fast_sodium_current_m_gate_m = rY[2];
00184
00185 double membrane_V = rY[4];
00186 double slow_inward_current_d_gate_d = rY[5];
00187 double slow_inward_current_f_gate_f = rY[6];
00188 double time_dependent_potassium_current_X_gate_X = rY[7];
00189
00190 double fast_sodium_current_h_gate_alpha_h;
00191
00192 if (membrane_V < -40.0)
00193 {
00194 fast_sodium_current_h_gate_alpha_h = 0.135*exp((80.0+membrane_V)/-6.8);
00195 }
00196 else
00197 {
00198 fast_sodium_current_h_gate_alpha_h = 0.0;
00199 }
00200
00201 double fast_sodium_current_h_gate_beta_h;
00202
00203 if (membrane_V < -40.0)
00204 {
00205 fast_sodium_current_h_gate_beta_h = 3.56*exp(0.079*membrane_V)+3.1e5*exp(0.35*membrane_V);
00206 }
00207 else
00208 {
00209 fast_sodium_current_h_gate_beta_h = 1.0/(0.13*(1.0+exp((membrane_V+10.66)/-11.1)));
00210 }
00211
00212 double fast_sodium_current_j_gate_alpha_j;
00213
00214 if (membrane_V < -40.0)
00215 {
00216 fast_sodium_current_j_gate_alpha_j = (-1.2714e5*exp(0.2444*membrane_V)-3.474e-5*exp(-0.04391*membrane_V))*(membrane_V+37.78)/(1.0+exp(0.311*(membrane_V+79.23)));
00217 }
00218 else
00219 {
00220 fast_sodium_current_j_gate_alpha_j = 0.0;
00221 }
00222
00223 double fast_sodium_current_j_gate_beta_j;
00224
00225 if (membrane_V < -40.0)
00226 {
00227 fast_sodium_current_j_gate_beta_j = 0.1212*exp(-0.01052*membrane_V)/(1.0+exp(-0.1378*(membrane_V+40.14)));
00228 }
00229 else
00230 {
00231 fast_sodium_current_j_gate_beta_j = 0.3*exp(-2.535e-7*membrane_V)/(1.0+exp(-0.1*(membrane_V+32.0)));
00232 }
00233
00234 double fast_sodium_current_m_gate_alpha_m = 0.32*(membrane_V+47.13)/(1.0-exp(-0.1*(membrane_V+47.13)));
00235 double fast_sodium_current_m_gate_beta_m = 0.08*exp(-membrane_V/11.0);
00236
00237 double slow_inward_current_d_gate_alpha_d = 0.095*exp(-0.01*(membrane_V-5.0))/(1.0+exp(-0.072*(membrane_V-5.0)));
00238 double slow_inward_current_d_gate_beta_d = 0.07*exp(-0.017*(membrane_V+44.0))/(1.0+exp(0.05*(membrane_V+44.0)));
00239
00240 double slow_inward_current_f_gate_alpha_f = 0.012*exp(-0.008*(membrane_V+28.0))/(1.0+exp(0.15*(membrane_V+28.0)));
00241 double slow_inward_current_f_gate_beta_f = 0.0065*exp(-0.02*(membrane_V+30.0))/(1.0+exp(-0.2*(membrane_V+30.0)));
00242
00243 double time_dependent_potassium_current_X_gate_alpha_X = 0.0005*exp(0.083*(membrane_V+50.0))/(1.0+exp(0.057*(membrane_V+50.0)));
00244 double time_dependent_potassium_current_X_gate_beta_X = 0.0013*exp(-0.06*(membrane_V+20.0))/(1.0+exp(-0.04*(membrane_V+20.0)));
00245
00246
00247 fast_sodium_current_h_gate_h = (fast_sodium_current_h_gate_h + fast_sodium_current_h_gate_alpha_h*mDt)
00248 / (1 + (fast_sodium_current_h_gate_alpha_h + fast_sodium_current_h_gate_beta_h)*mDt);
00249
00250
00251 fast_sodium_current_m_gate_m = (fast_sodium_current_m_gate_m + fast_sodium_current_m_gate_alpha_m*mDt)
00252 / (1 + (fast_sodium_current_m_gate_alpha_m + fast_sodium_current_m_gate_beta_m)*mDt);
00253
00254
00255 fast_sodium_current_j_gate_j = (fast_sodium_current_j_gate_j + fast_sodium_current_j_gate_alpha_j*mDt)
00256 / (1 + (fast_sodium_current_j_gate_alpha_j + fast_sodium_current_j_gate_beta_j)*mDt);
00257
00258
00259 slow_inward_current_d_gate_d = (slow_inward_current_d_gate_d + slow_inward_current_d_gate_alpha_d*mDt)
00260 / (1 + (slow_inward_current_d_gate_alpha_d + slow_inward_current_d_gate_beta_d)*mDt);
00261
00262
00263 slow_inward_current_f_gate_f = (slow_inward_current_f_gate_f + slow_inward_current_f_gate_alpha_f*mDt)
00264 / (1 + (slow_inward_current_f_gate_alpha_f + slow_inward_current_f_gate_beta_f)*mDt);
00265
00266
00267 time_dependent_potassium_current_X_gate_X = ( time_dependent_potassium_current_X_gate_X + time_dependent_potassium_current_X_gate_alpha_X*mDt)
00268 / ( 1 + (time_dependent_potassium_current_X_gate_alpha_X+time_dependent_potassium_current_X_gate_beta_X)*mDt);
00269
00270 rY[0] = fast_sodium_current_h_gate_h;
00271 rY[1] = fast_sodium_current_j_gate_j;
00272 rY[2] = fast_sodium_current_m_gate_m;
00273
00274 rY[5] = slow_inward_current_d_gate_d;
00275 rY[6] = slow_inward_current_f_gate_f;
00276 rY[7] = time_dependent_potassium_current_X_gate_X;
00277
00278
00279 double guess[1] = {rY[3]};
00280
00281 CardiacNewtonSolver<1> *solver = CardiacNewtonSolver<1>::Instance();
00282 solver->Solve(*this, guess);
00283
00284 rY[3] = guess[0];
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 }
00310
00311 void BackwardEulerLuoRudyIModel1991::ComputeResidual(const double rCurrentGuess[1], double rResidual[1])
00312 {
00313 std::vector<double>& rY = rGetStateVariables();
00314 double membrane_V = rY[4];
00315 double slow_inward_current_d_gate_d = rY[5];
00316 double slow_inward_current_f_gate_f = rY[6];
00317
00318 double slow_inward_current_E_si = 7.7-13.0287*log(rCurrentGuess[0]);
00319 double slow_inward_current_i_si = 0.09*slow_inward_current_d_gate_d*slow_inward_current_f_gate_f*(membrane_V-slow_inward_current_E_si);
00320
00321 double dCdt_using_current_guess = -1e-4*slow_inward_current_i_si+0.07*(1e-4-rCurrentGuess[0]);
00322
00323 rResidual[0] = rCurrentGuess[0] - rY[3] - mDt*dCdt_using_current_guess;
00324 }
00325
00326 void BackwardEulerLuoRudyIModel1991::ComputeJacobian(const double rCurrentGuess[1], double rJacobian[1][1])
00327 {
00328 std::vector<double>& rY = rGetStateVariables();
00329 double slow_inward_current_d_gate_d = rY[5];
00330 double slow_inward_current_f_gate_f = rY[6];
00331
00332 rJacobian[0][0] = 1 - mDt*(-0.1172583e-3*slow_inward_current_d_gate_d*slow_inward_current_f_gate_f/rCurrentGuess[0]
00333 - 0.07);
00334 }
00335
00336 double BackwardEulerLuoRudyIModel1991::GetIIonic()
00337 {
00338 double fast_sodium_current_h_gate_h = mStateVariables[0];
00339 double fast_sodium_current_j_gate_j = mStateVariables[1];
00340 double fast_sodium_current_m_gate_m = mStateVariables[2];
00341 double intracellular_calcium_concentration_Cai = mStateVariables[3];
00342 double membrane_V = mStateVariables[4];
00343 double slow_inward_current_d_gate_d = mStateVariables[5];
00344 double slow_inward_current_f_gate_f = mStateVariables[6];
00345 double time_dependent_potassium_current_X_gate_X = mStateVariables[7];
00346
00347
00348
00349
00350 double background_current_i_b = background_current_g_b*(membrane_V-background_current_E_b);
00351
00352 double fast_sodium_current_i_Na = fast_sodium_current_g_Na*pow(fast_sodium_current_m_gate_m, 3.0)*fast_sodium_current_h_gate_h*fast_sodium_current_j_gate_j*(membrane_V-fast_sodium_current_E_Na);
00353 double slow_inward_current_E_si = 7.7-13.0287*log(intracellular_calcium_concentration_Cai);
00354
00355 double slow_inward_current_i_si = 0.09*slow_inward_current_d_gate_d*slow_inward_current_f_gate_f*(membrane_V-slow_inward_current_E_si);
00356
00357 double time_dependent_potassium_current_g_K = 0.282*sqrt(ionic_concentrations_Ko/5.4);
00358 double time_dependent_potassium_current_Xi_gate_Xi;
00359
00360
00361
00362 if (membrane_V > -100.0)
00363 {
00364 time_dependent_potassium_current_Xi_gate_Xi = 2.837*(exp(0.04*(membrane_V+77.0))-1.0)/((membrane_V+77.0)*exp(0.04*(membrane_V+35.0)));
00365 }
00366 else
00367 {
00368 #define COVERAGE_IGNORE
00369 time_dependent_potassium_current_Xi_gate_Xi = 1.0;
00370 #undef COVERAGE_IGNORE
00371 }
00372
00373 double time_dependent_potassium_current_E_K = ((membrane_R*membrane_T)/membrane_F)*log((ionic_concentrations_Ko+time_dependent_potassium_current_PR_NaK*ionic_concentrations_Nao)/(ionic_concentrations_Ki+time_dependent_potassium_current_PR_NaK*ionic_concentrations_Nai));
00374 double time_dependent_potassium_current_i_K = time_dependent_potassium_current_g_K*time_dependent_potassium_current_X_gate_X*time_dependent_potassium_current_Xi_gate_Xi*(membrane_V-time_dependent_potassium_current_E_K);
00375
00376 double time_independent_potassium_current_g_K1 = 0.6047*sqrt(ionic_concentrations_Ko/5.4);
00377 double time_independent_potassium_current_E_K1 =((membrane_R*membrane_T)/membrane_F)*log(ionic_concentrations_Ko/ionic_concentrations_Ki);
00378 double time_independent_potassium_current_K1_gate_alpha_K1 = 1.02/(1.0+exp(0.2385*(membrane_V-time_independent_potassium_current_E_K1-59.215)));
00379 double time_independent_potassium_current_K1_gate_beta_K1 = (0.49124*exp(0.08032*(membrane_V+5.476-time_independent_potassium_current_E_K1))+exp(0.06175*(membrane_V-(time_independent_potassium_current_E_K1+594.31))))/(1.0+exp(-0.5143*(membrane_V-time_independent_potassium_current_E_K1+4.753)));
00380 double time_independent_potassium_current_K1_gate_K1_infinity = time_independent_potassium_current_K1_gate_alpha_K1/(time_independent_potassium_current_K1_gate_alpha_K1+time_independent_potassium_current_K1_gate_beta_K1);
00381 double time_independent_potassium_current_i_K1 = time_independent_potassium_current_g_K1*time_independent_potassium_current_K1_gate_K1_infinity*(membrane_V-time_independent_potassium_current_E_K1);
00382
00383 double plateau_potassium_current_Kp = 1.0/(1.0+exp((7.488-membrane_V)/5.98));
00384 double plateau_potassium_current_E_Kp = time_independent_potassium_current_E_K1;
00385 double plateau_potassium_current_i_Kp = plateau_potassium_current_g_Kp*plateau_potassium_current_Kp*(membrane_V-plateau_potassium_current_E_Kp);
00386
00387 double i_ionic = fast_sodium_current_i_Na+slow_inward_current_i_si+time_dependent_potassium_current_i_K+time_independent_potassium_current_i_K1+plateau_potassium_current_i_Kp+background_current_i_b;
00388
00389 assert( !isnan(i_ionic));
00390 return i_ionic;
00391 }
00392
00393
00394 void BackwardEulerLuoRudyIModel1991::VerifyStateVariables()
00395 {
00396 const std::vector<double>& rY = rGetStateVariables();
00397
00398 const double fast_sodium_current_h_gate_h = rY[0];
00399 const double fast_sodium_current_j_gate_j = rY[1];
00400 const double fast_sodium_current_m_gate_m = rY[2];
00401 const double intracellular_calcium_concentration_Cai = rY[3];
00402 const double slow_inward_current_d_gate_d = rY[5];
00403 const double slow_inward_current_f_gate_f = rY[6];
00404 const double time_dependent_potassium_current_X_gate_X = rY[7];
00405
00406 #define COVERAGE_IGNORE
00407 if (!(0.0<=fast_sodium_current_h_gate_h && fast_sodium_current_h_gate_h<=1.0))
00408 {
00409 EXCEPTION("h gate for fast sodium current has gone out of range. Check model parameters, for example spatial stepsize");
00410 }
00411
00412 if (!(0.0<=fast_sodium_current_j_gate_j && fast_sodium_current_j_gate_j<=1.0))
00413 {
00414 EXCEPTION("j gate for fast sodium current has gone out of range. Check model parameters, for example spatial stepsize");
00415 }
00416
00417 if (!(0.0<=fast_sodium_current_m_gate_m && fast_sodium_current_m_gate_m<=1.0))
00418 {
00419 EXCEPTION("m gate for fast sodium current has gone out of range. Check model parameters, for example spatial stepsize");
00420 }
00421
00422 if (!(0.0<intracellular_calcium_concentration_Cai))
00423 {
00424 EXCEPTION("intracellular_calcium_concentration_Cai has become non-positive, ie gone out of range. Check model parameters, for example spatial stepsize");
00425 }
00426
00427 if (!(0.0<=slow_inward_current_d_gate_d && slow_inward_current_d_gate_d<=1.0))
00428 {
00429 EXCEPTION("d gate for slow inward current has gone out of range. Check model parameters, for example spatial stepsize");
00430 }
00431
00432 if (!(0.0<=slow_inward_current_f_gate_f && slow_inward_current_f_gate_f<=1.0))
00433 {
00434 EXCEPTION("f gate for slow inward current has gone out of range. Check model parameters, for example spatial stepsize");
00435 }
00436
00437 if (!(0.0<=time_dependent_potassium_current_X_gate_X && time_dependent_potassium_current_X_gate_X<=1.0))
00438 {
00439 EXCEPTION("X gate for time dependent potassium current has gone out of range. Check model parameters, for example spatial stepsize");
00440 }
00441 #undef COVERAGE_IGNORE
00442 }
00443