Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include "NhsModelWithBackwardSolver.hpp" 00037 #include <iostream> 00038 #include <cmath> 00039 #include "LogFile.hpp" 00040 #include "Exception.hpp" 00041 #include "TimeStepper.hpp" 00042 00043 const double NhsModelWithBackwardSolver::mTolerance = 1e-10; 00044 00045 double NhsModelWithBackwardSolver::ImplicitSolveForQ() 00046 { 00047 mTemporaryStateVariables[2] = (mTemporaryStateVariables[2] + mDt*mA1*mDLambdaDt)/(1 + mAlpha1*mDt); 00048 mTemporaryStateVariables[3] = (mTemporaryStateVariables[3] + mDt*mA2*mDLambdaDt)/(1 + mAlpha2*mDt); 00049 mTemporaryStateVariables[4] = (mTemporaryStateVariables[4] + mDt*mA3*mDLambdaDt)/(1 + mAlpha3*mDt); 00050 00051 return mTemporaryStateVariables[2] + mTemporaryStateVariables[3] + mTemporaryStateVariables[4]; 00052 } 00053 00054 void NhsModelWithBackwardSolver::CalculateCaTropAndZDerivatives(double calciumTroponin, double z, double Q, 00055 double& dCaTrop, double& dz) 00056 { 00057 //As in straight Nhs, we don't cover the exception code 00058 #define COVERAGE_IGNORE 00059 if(calciumTroponin < 0) 00060 { 00061 EXCEPTION("CalciumTrop concentration went negative"); 00062 } 00063 if(z<0) 00064 { 00065 EXCEPTION("z went negative"); 00066 } 00067 if(z>1) 00068 { 00069 EXCEPTION("z became greater than 1"); 00070 } 00071 #undef COVERAGE_IGNORE 00072 00073 double T0 = CalculateT0(z); 00074 00075 double Ta; 00076 if(Q>0) 00077 { 00078 Ta = T0*(1+(2+mA)*Q)/(1+Q); 00079 } 00080 else 00081 { 00082 Ta = T0*(1+mA*Q)/(1-Q); 00083 } 00084 00085 dCaTrop = mKon * mCalciumI * ( mCalciumTroponinMax - calciumTroponin) 00086 - mKrefoff * (1-Ta/(mGamma*mTref)) * calciumTroponin; 00087 00088 double ca_trop_to_ca_trop50_ratio_to_n = pow(calciumTroponin/mCalciumTrop50, mN); 00089 00090 dz = mAlpha0 * ca_trop_to_ca_trop50_ratio_to_n * (1-z) 00091 - mAlphaR1 * z 00092 - mAlphaR2 * pow(z,mNr) / (pow(z,mNr) + pow(mKZ,mNr)); 00093 } 00094 00095 00096 00097 void NhsModelWithBackwardSolver::CalculateBackwardEulerResidual(double calciumTroponin, double z, double Q, 00098 double& residualComponent1, double& residualComponent2) 00099 { 00100 double dcatrop; 00101 double dz; 00102 CalculateCaTropAndZDerivatives(calciumTroponin,z,Q,dcatrop,dz); 00103 00104 residualComponent1 = calciumTroponin - mDt*dcatrop - mTemporaryStateVariables[0]; 00105 residualComponent2 = z - mDt*dz - mTemporaryStateVariables[1]; 00106 } 00107 00108 00109 00110 NhsModelWithBackwardSolver::NhsModelWithBackwardSolver() 00111 { 00112 mTemporaryStateVariables.resize(5); 00113 } 00114 00115 00116 00117 void NhsModelWithBackwardSolver::RunDoNotUpdate(double startTime, double endTime, double timestep) 00118 { 00119 assert(startTime < endTime); 00120 00121 mDt = timestep; 00122 00123 mTemporaryStateVariables = mStateVariables; 00124 00125 // loop in time 00126 TimeStepper stepper(startTime, endTime, timestep); 00127 00128 while ( !stepper.IsTimeAtEnd() ) 00129 { 00131 // Q1,Q2,Q3 using backward euler can solved straightaway 00133 double new_Q = ImplicitSolveForQ(); 00134 00136 // Solve the 2D nonlinear problem for Backward Euler Ca_trop and z 00138 00139 // see what the residual is 00140 double catrop_guess = mTemporaryStateVariables[0]; 00141 double z_guess = mTemporaryStateVariables[1]; 00142 double f1,f2; // f=[f1,f2]=residual 00143 00144 CalculateBackwardEulerResidual(catrop_guess, z_guess, new_Q, f1, f2); 00145 double norm_resid = sqrt(f1*f1+f2*f2); 00146 00147 // solve using Newton's method, no damping. Stop if num iterations 00148 // reaches 15 (very conservative) 00149 unsigned counter = 0; 00150 while ((norm_resid>mTolerance) && (counter++<15)) 00151 { 00152 // numerically approximate the jacobian J 00153 double j11,j12,j21,j22; // J = [j11, j12; j21 j22] 00154 double temp1,temp2; 00155 00156 double h = std::max(fabs(catrop_guess/100),1e-8); 00157 CalculateBackwardEulerResidual(catrop_guess+h, z_guess, new_Q, temp1, temp2); 00158 j11 = (temp1-f1)/h; 00159 j21 = (temp2-f2)/h; 00160 00161 h = std::max(fabs(z_guess/100),1e-8); 00162 CalculateBackwardEulerResidual(catrop_guess, z_guess+h, new_Q, temp1, temp2); 00163 j12 = (temp1-f1)/h; 00164 j22 = (temp2-f2)/h; 00165 00166 // compute u = J^{-1} f (exactly, as a 2D problem) 00167 double one_over_det = 1.0/(j11*j22-j12*j21); 00168 double u1 = one_over_det*(j22*f1 - j12*f2); 00169 double u2 = one_over_det*(-j21*f1 + j11*f2); 00170 00171 catrop_guess -= u1; 00172 z_guess -= u2; 00173 00174 CalculateBackwardEulerResidual(catrop_guess, z_guess, new_Q, f1, f2); 00175 norm_resid = sqrt(f1*f1+f2*f2); 00176 } 00177 assert(counter<15); // if this fails, see corresponding code in old NhsModelWithImplicitSolver 00178 00179 mTemporaryStateVariables[0] = catrop_guess; 00180 mTemporaryStateVariables[1] = z_guess; 00181 00182 stepper.AdvanceOneTimeStep(); 00183 } 00184 } 00185 00186 double NhsModelWithBackwardSolver::GetNextActiveTension() 00187 { 00188 double T0 = CalculateT0(mTemporaryStateVariables[1]); 00189 double Q = mTemporaryStateVariables[2]+mTemporaryStateVariables[3]+mTemporaryStateVariables[4]; 00190 00191 if(Q>0) 00192 { 00193 return T0*(1+(2+mA)*Q)/(1+Q); 00194 } 00195 else 00196 { 00197 return T0*(1+mA*Q)/(1-Q); 00198 } 00199 } 00200 00201 void NhsModelWithBackwardSolver::RunAndUpdate(double startTime, double endTime, double timestep) 00202 { 00203 RunDoNotUpdate(startTime, endTime, timestep); 00204 UpdateStateVariables(); 00205 } 00206