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 "NhsSystemWithImplicitSolver.hpp"
00029 #include "TimeStepper.hpp"
00030 #include <cmath>
00031 #include "LogFile.hpp"
00032 #include <iostream>
00033
00034
00035
00036
00037 void NhsSystemWithImplicitSolver::ImplicitSolveForActiveTension()
00038 {
00039
00040
00041
00042 double current_active_tension = mActiveTensionInitialGuess;
00043
00044
00045 double residual = CalcActiveTensionResidual(current_active_tension);
00046
00047
00048
00049 unsigned counter = 0;
00050 std::vector<double> old_residuals(15);
00051 while ((fabs(residual)>mTolerance) && (counter++<15))
00052 {
00053
00054 double h = std::max(fabs(current_active_tension/100),1e-8);
00055
00056 double jac = (CalcActiveTensionResidual(current_active_tension+h) - CalcActiveTensionResidual(current_active_tension))/h;
00057
00058 current_active_tension -= residual/jac;
00059 residual = CalcActiveTensionResidual(current_active_tension);
00060 old_residuals.push_back(residual);
00061 }
00062
00063 if(counter >= 15)
00064 {
00065 #define COVERAGE_IGNORE
00066 LOG(1, "\nWARNING in NhsSystemWithImplicitSolver::ImplicitSolveForActiveTension(), counter="<<counter<<",resids=");
00067 for (unsigned i=0; i<old_residuals.size(); i++)
00068 {
00069 LOG(1,old_residuals[i]);
00070 }
00071 LOG(1,"Final residual = " << residual);
00072 if(residual > 100*mTolerance)
00073 {
00074 LOG(1,"Residual > 100*mTol, throwing exception\n");
00075 EXCEPTION("NhsSystemWithImplicitSolver::ImplicitSolveForActiveTension() failed to converge");
00076 }
00077 #undef COVERAGE_IGNORE
00078 }
00079
00080
00081
00082 mActiveTensionInitialGuess = current_active_tension;
00083
00087 mActiveTensionSolution = current_active_tension;
00088 }
00089
00090 double NhsSystemWithImplicitSolver::CalcActiveTensionResidual(double activeTensionGuess)
00091 {
00092
00093
00094
00095
00096
00097 double new_Ca_Trop = ImplicitSolveForCaTrop(activeTensionGuess);
00098
00099
00100 mTempStoredStateVariables[0] = new_Ca_Trop;
00101
00102
00103 double new_z;
00104 if(!mUseImplicitExplicitSolveForZ)
00105 {
00106 new_z = ImplicitSolveForZ(new_Ca_Trop);
00107 }
00108 else
00109 {
00110 new_z = ImplicitExplicitSolveForZ(new_Ca_Trop);
00111 }
00112
00113
00114 mTempStoredStateVariables[1] = new_z;
00115
00116
00117 double new_T0 = CalculateT0(new_z);
00118
00119
00120
00121 double new_Q = ImplicitSolveForQ();
00122
00123
00124
00125
00126 double new_active_tension = 0;
00127 if(new_Q > 0)
00128 {
00129 new_active_tension = new_T0*(1+(2+mA)*new_Q)/(1+new_Q);
00130 }
00131 else
00132 {
00133 #define COVERAGE_IGNORE // not quite sure how to cover this, of if it is worth it
00134 new_active_tension = new_T0*(1+mA*new_Q)/(1-new_Q);
00135 #undef COVERAGE_IGNORE
00136 }
00137
00138 return new_active_tension - activeTensionGuess;
00139 }
00140
00141
00142
00143
00144
00145 double NhsSystemWithImplicitSolver::ImplicitSolveForCaTrop(double newActiveTension)
00146 {
00147 double old_Ca_trop = mCurrentStateVars[0];
00148
00149 double numer = old_Ca_trop + mDt * mKon * mCalciumI * mCalciumTroponinMax;
00150 double denom = 1 + mDt*mKon*mCalciumI + mDt*mKrefoff*(1-newActiveTension/(mGamma*mTref));
00151
00152 return numer/denom;
00153 }
00154
00155
00156
00157 double NhsSystemWithImplicitSolver::ImplicitSolveForZ(double newCaTrop)
00158 {
00159 double current_z = mCurrentStateVars[1];
00160 double residual = CalcZResidual(current_z, newCaTrop);
00161 unsigned counter = 0;
00162
00163 while ((fabs(residual)>mTolerance) && (counter++<15))
00164 {
00165 double h = std::max(fabs(current_z/100),1e-8);
00166 double jac = (CalcZResidual(current_z + h, newCaTrop) - CalcZResidual(current_z, newCaTrop));
00167 jac/= h;
00168
00169 current_z -= residual/jac;
00170 residual = CalcZResidual(current_z, newCaTrop);
00171 }
00172 assert(counter<15);
00173
00174 return current_z;
00175 }
00176
00177
00178 double NhsSystemWithImplicitSolver::CalcZResidual(double z, double newCaTrop)
00179 {
00180 double ca_trop_to_ca_trop50_ratio_to_n = pow(newCaTrop/mCalciumTrop50, mN);
00181 double dzdt = mAlpha0 * ca_trop_to_ca_trop50_ratio_to_n * (1-z)
00182 - mAlphaR1 * z
00183 - mAlphaR2 * pow(z,mNr) / (pow(z,mNr) + pow(mKZ,mNr));
00184
00185 return z - mCurrentStateVars[1] - mDt*dzdt;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194 double NhsSystemWithImplicitSolver::ImplicitExplicitSolveForZ(double newCaTrop)
00195 {
00196 double ca_trop_to_ca_trop50_ratio_to_n = pow(newCaTrop/mCalciumTrop50, mN);
00197 double old_z = mCurrentStateVars[1];
00198
00199 double numer = old_z + mDt * mAlpha0 * ca_trop_to_ca_trop50_ratio_to_n
00200 - mDt * mAlphaR2 * pow(old_z,mNr) / (pow(old_z,mNr) + pow(mKZ,mNr));
00201 double denom = 1 + mDt * mAlpha0 * ca_trop_to_ca_trop50_ratio_to_n + mAlphaR1 *mDt;
00202
00203 return numer/denom;
00204 }
00205
00206
00207
00208 double NhsSystemWithImplicitSolver::ImplicitSolveForQ()
00209 {
00210 double old_Q1 = mCurrentStateVars[2];
00211 double old_Q2 = mCurrentStateVars[3];
00212 double old_Q3 = mCurrentStateVars[4];
00213
00214 double new_Q1 = (old_Q1 + mDt*mA1*mDLambdaDt)/(1 + mAlpha1*mDt);
00215 double new_Q2 = (old_Q2 + mDt*mA2*mDLambdaDt)/(1 + mAlpha2*mDt);
00216 double new_Q3 = (old_Q3 + mDt*mA3*mDLambdaDt)/(1 + mAlpha3*mDt);
00217
00218 mTempStoredStateVariables[2] = new_Q1;
00219 mTempStoredStateVariables[3] = new_Q2;
00220 mTempStoredStateVariables[4] = new_Q3;
00221
00222 return new_Q1 + new_Q2 + new_Q3;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 NhsSystemWithImplicitSolver::NhsSystemWithImplicitSolver()
00246 : NhsCellularMechanicsOdeSystem()
00247 {
00248 mTempStoredStateVariables.resize(GetNumberOfStateVariables());
00249 mActiveTensionInitialGuess = GetActiveTension();
00250 mUseImplicitExplicitSolveForZ = false;
00251
00252 mActiveTensionSolution = NhsCellularMechanicsOdeSystem::GetActiveTension();
00253 }
00254
00255 void NhsSystemWithImplicitSolver::SetActiveTensionInitialGuess(double activeTensionInitialGuess)
00256 {
00257 mActiveTensionInitialGuess = activeTensionInitialGuess;
00258 }
00259
00260
00261 void NhsSystemWithImplicitSolver::SolveDoNotUpdate(double startTime,
00262 double endTime,
00263 double timestep)
00264 {
00265 assert(startTime < endTime);
00266
00267 mDt = timestep;
00268
00269
00270 mCurrentStateVars = mStateVariables;
00271
00272
00273 TimeStepper stepper(startTime, endTime, timestep);
00274 while ( !stepper.IsTimeAtEnd() )
00275 {
00276 ImplicitSolveForActiveTension();
00277 mCurrentStateVars = mTempStoredStateVariables;
00278
00279 stepper.AdvanceOneTimeStep();
00280 }
00281
00282
00283 }
00284
00285 void NhsSystemWithImplicitSolver::UpdateStateVariables()
00286 {
00287 for(unsigned i=0; i<mStateVariables.size(); i++)
00288 {
00289 mStateVariables[i] = mCurrentStateVars[i];
00290 }
00291 }
00292
00293 void NhsSystemWithImplicitSolver::UseImplicitExplicitSolveForZ(bool useImplicitExplicitSolveForZ)
00294 {
00295 mUseImplicitExplicitSolveForZ = useImplicitExplicitSolveForZ;
00296 }
00297
00298 double NhsSystemWithImplicitSolver::GetActiveTensionAtNextTime()
00299 {
00300 return mActiveTensionSolution;
00301 }
00302