NhsModelWithBackwardSolver.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "NhsModelWithBackwardSolver.hpp"
00030 #include "TimeStepper.hpp"
00031 #include <cmath>
00032 #include "LogFile.hpp"
00033 #include <iostream>
00034 
00035 const double NhsModelWithBackwardSolver::mTolerance = 1e-10;
00036 
00037 double NhsModelWithBackwardSolver::ImplicitSolveForQ()
00038 {
00039     mTemporaryStateVariables[2] = (mTemporaryStateVariables[2] + mDt*mA1*mDLambdaDt)/(1 + mAlpha1*mDt);
00040     mTemporaryStateVariables[3] = (mTemporaryStateVariables[3] + mDt*mA2*mDLambdaDt)/(1 + mAlpha2*mDt);
00041     mTemporaryStateVariables[4] = (mTemporaryStateVariables[4] + mDt*mA3*mDLambdaDt)/(1 + mAlpha3*mDt);
00042 
00043     return mTemporaryStateVariables[2] + mTemporaryStateVariables[3] + mTemporaryStateVariables[4];
00044 }
00045 
00046 void NhsModelWithBackwardSolver::CalculateCaTropAndZDerivatives(double calciumTroponin, double z, double Q,
00047                                                                 double& dCaTrop, double& dz)
00048 {
00049 //As in straight Nhs, we don't cover the exception code
00050 #define COVERAGE_IGNORE
00051     if(calciumTroponin < 0)
00052     {
00053         EXCEPTION("CalciumTrop concentration went negative");
00054     }
00055     if(z<0)
00056     {
00057         EXCEPTION("z went negative");
00058     }
00059     if(z>1)
00060     {
00061         EXCEPTION("z became greater than 1");
00062     }
00063 #undef COVERAGE_IGNORE
00064 
00065     double T0 = CalculateT0(z);
00066 
00067     double Ta;
00068     if(Q>0)
00069     {
00070         Ta = T0*(1+(2+mA)*Q)/(1+Q);
00071     }
00072     else
00073     {
00074         Ta = T0*(1+mA*Q)/(1-Q);
00075     }
00076 
00077     dCaTrop =   mKon * mCalciumI * ( mCalciumTroponinMax - calciumTroponin)
00078              - mKrefoff * (1-Ta/(mGamma*mTref)) * calciumTroponin;
00079 
00080     double ca_trop_to_ca_trop50_ratio_to_n = pow(calciumTroponin/mCalciumTrop50, mN);
00081 
00082     dz =   mAlpha0 * ca_trop_to_ca_trop50_ratio_to_n * (1-z)
00083          - mAlphaR1 * z
00084          - mAlphaR2 * pow(z,mNr) / (pow(z,mNr) + pow(mKZ,mNr));
00085 }
00086 
00087 
00088 
00089 void NhsModelWithBackwardSolver::CalculateBackwardEulerResidual(double calciumTroponin, double z, double Q,
00090                                                                 double& residualComponent1, double& residualComponent2)
00091 {
00092     double dcatrop;
00093     double dz;
00094     CalculateCaTropAndZDerivatives(calciumTroponin,z,Q,dcatrop,dz);
00095 
00096     residualComponent1 = calciumTroponin - mDt*dcatrop - mTemporaryStateVariables[0];
00097     residualComponent2 = z - mDt*dz - mTemporaryStateVariables[1];
00098 }
00099 
00100 
00101 
00102 NhsModelWithBackwardSolver::NhsModelWithBackwardSolver()
00103 {
00104     mTemporaryStateVariables.resize(5);
00105 }
00106 
00107 
00108 
00109 void NhsModelWithBackwardSolver::RunDoNotUpdate(double startTime, double endTime, double timestep)
00110 {
00111     assert(startTime < endTime);
00112 
00113     mDt = timestep;
00114 
00115     mTemporaryStateVariables = mStateVariables;
00116 
00117     // loop in time
00118     TimeStepper stepper(startTime, endTime, timestep);
00119 
00120     while ( !stepper.IsTimeAtEnd() )
00121     {
00123         // Q1,Q2,Q3 using backward euler can solved straightaway
00125         double new_Q = ImplicitSolveForQ();
00126 
00128         // Solve the 2D nonlinear problem for Backward Euler Ca_trop and z
00130 
00131         // see what the residual is
00132         double catrop_guess = mTemporaryStateVariables[0];
00133         double z_guess = mTemporaryStateVariables[1];
00134         double f1,f2; // f=[f1,f2]=residual
00135 
00136         CalculateBackwardEulerResidual(catrop_guess, z_guess, new_Q, f1, f2);
00137         double norm_resid = sqrt(f1*f1+f2*f2);
00138 
00139         // solve using Newton's method, no damping. Stop if num iterations
00140         // reaches 15 (very conservative)
00141         unsigned counter = 0;
00142         while ((norm_resid>mTolerance) && (counter++<15))
00143         {
00144             // numerically approximate the jacobian J
00145             double j11,j12,j21,j22; // J = [j11, j12; j21 j22]
00146             double temp1,temp2;
00147 
00148             double h = std::max(fabs(catrop_guess/100),1e-8);
00149             CalculateBackwardEulerResidual(catrop_guess+h, z_guess, new_Q, temp1, temp2);
00150             j11 = (temp1-f1)/h;
00151             j21 = (temp2-f2)/h;
00152 
00153             h = std::max(fabs(z_guess/100),1e-8);
00154             CalculateBackwardEulerResidual(catrop_guess, z_guess+h, new_Q, temp1, temp2);
00155             j12 = (temp1-f1)/h;
00156             j22 = (temp2-f2)/h;
00157 
00158             // compute u = J^{-1} f (exactly, as a 2D problem)
00159             double one_over_det = 1.0/(j11*j22-j12*j21);
00160             double u1 = one_over_det*(j22*f1  - j12*f2);
00161             double u2 = one_over_det*(-j21*f1 + j11*f2);
00162 
00163             catrop_guess -= u1;
00164             z_guess -= u2;
00165 
00166             CalculateBackwardEulerResidual(catrop_guess, z_guess, new_Q, f1, f2);
00167             norm_resid = sqrt(f1*f1+f2*f2);
00168         }
00169         assert(counter<15); // if this fails, see corresponding code in old NhsModelWithImplicitSolver
00170 
00171         mTemporaryStateVariables[0] = catrop_guess;
00172         mTemporaryStateVariables[1] = z_guess;
00173 
00174         stepper.AdvanceOneTimeStep();
00175     }
00176 }
00177 
00178 double NhsModelWithBackwardSolver::GetNextActiveTension()
00179 {
00180     double T0 = CalculateT0(mTemporaryStateVariables[1]);
00181     double Q = mTemporaryStateVariables[2]+mTemporaryStateVariables[3]+mTemporaryStateVariables[4];
00182 
00183     if(Q>0)
00184     {
00185         return T0*(1+(2+mA)*Q)/(1+Q);
00186     }
00187     else
00188     {
00189         return T0*(1+mA*Q)/(1-Q);
00190     }
00191 }
00192 
00193 void NhsModelWithBackwardSolver::RunAndUpdate(double startTime, double endTime, double timestep)
00194 {
00195     RunDoNotUpdate(startTime, endTime, timestep);
00196     UpdateStateVariables();
00197 }
00198 

Generated by  doxygen 1.6.2