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 00037 #ifndef ABSTRACTBACKWARDEULERCARDIACCELL_HPP_ 00038 #define ABSTRACTBACKWARDEULERCARDIACCELL_HPP_ 00039 00040 #include <cassert> 00041 #include <cmath> 00042 00043 #include "ChasteSerialization.hpp" 00044 #include <boost/serialization/base_object.hpp> 00045 #include "ClassIsAbstract.hpp" 00046 00047 #include "AbstractCardiacCell.hpp" 00048 #include "Exception.hpp" 00049 #include "PetscTools.hpp" 00050 #include "TimeStepper.hpp" 00051 00066 template<unsigned SIZE> 00067 class AbstractBackwardEulerCardiacCell : public AbstractCardiacCell 00068 { 00069 private: 00071 friend class boost::serialization::access; 00078 template<class Archive> 00079 void serialize(Archive & archive, const unsigned int version) 00080 { 00081 // This calls serialize on the base class. 00082 archive & boost::serialization::base_object<AbstractCardiacCell>(*this); 00083 } 00084 public: 00085 00101 AbstractBackwardEulerCardiacCell( 00102 unsigned numberOfStateVariables, 00103 unsigned voltageIndex, 00104 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus); 00105 00107 virtual ~AbstractBackwardEulerCardiacCell(); 00108 00116 virtual void ComputeResidual(double time, const double rCurrentGuess[SIZE], double rResidual[SIZE])=0; 00117 00125 virtual void ComputeJacobian(double time, const double rCurrentGuess[SIZE], double rJacobian[SIZE][SIZE])=0; 00126 00139 OdeSolution Compute(double tStart, double tEnd, double tSamp=0.0); 00140 00150 void ComputeExceptVoltage(double tStart, double tEnd); 00151 00159 void SolveAndUpdateState(double tStart, double tEnd); 00160 00161 private: 00162 #define COVERAGE_IGNORE 00163 00170 void EvaluateYDerivatives(double time, const std::vector<double> &rY, std::vector<double> &rDY) 00171 { 00172 NEVER_REACHED; 00173 } 00174 #undef COVERAGE_IGNORE 00175 00176 protected: 00185 virtual void ComputeOneStepExceptVoltage(double tStart)=0; 00186 00194 virtual void UpdateTransmembranePotential(double time)=0; 00195 }; 00196 00197 00198 /* 00199 * NOTE: Explicit instantiation is not used for this class, because the SIZE 00200 * template parameter could take arbitrary values. 00201 */ 00202 00203 00204 template <unsigned SIZE> 00205 AbstractBackwardEulerCardiacCell<SIZE>::AbstractBackwardEulerCardiacCell( 00206 unsigned numberOfStateVariables, 00207 unsigned voltageIndex, 00208 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus) 00209 : AbstractCardiacCell(boost::shared_ptr<AbstractIvpOdeSolver>(), 00210 numberOfStateVariables, 00211 voltageIndex, 00212 pIntracellularStimulus) 00213 {} 00214 00215 template <unsigned SIZE> 00216 AbstractBackwardEulerCardiacCell<SIZE>::~AbstractBackwardEulerCardiacCell() 00217 {} 00218 00219 template <unsigned SIZE> 00220 OdeSolution AbstractBackwardEulerCardiacCell<SIZE>::Compute(double tStart, double tEnd, double tSamp) 00221 { 00222 // In this method, we iterate over timesteps, doing the following for each: 00223 // - update V using a forward Euler step 00224 // - call ComputeExceptVoltage(t) to update the remaining state variables 00225 // using backward Euler 00226 00227 // Check length of time interval 00228 if (tSamp < mDt) 00229 { 00230 tSamp = mDt; 00231 } 00232 double _n_steps = (tEnd - tStart) / tSamp; 00233 const unsigned n_steps = (unsigned) floor(_n_steps+0.5); 00234 assert(fabs(tStart+n_steps*tSamp - tEnd) < 1e-12); 00235 const unsigned n_small_steps = (unsigned) floor(tSamp/mDt+0.5); 00236 assert(fabs(mDt*n_small_steps - tSamp) < 1e-12); 00237 00238 // Initialise solution store 00239 OdeSolution solutions; 00240 solutions.SetNumberOfTimeSteps(n_steps); 00241 solutions.rGetSolutions().push_back(rGetStateVariables()); 00242 solutions.rGetTimes().push_back(tStart); 00243 solutions.SetOdeSystemInformation(this->mpSystemInfo); 00244 00245 // Loop over time 00246 double curr_time = tStart; 00247 for (unsigned i=0; i<n_steps; i++) 00248 { 00249 for (unsigned j=0; j<n_small_steps; j++) 00250 { 00251 curr_time = tStart + i*tSamp + j*mDt; 00252 00253 // Compute next value of V 00254 UpdateTransmembranePotential(curr_time); 00255 00256 // Compute other state variables 00257 ComputeOneStepExceptVoltage(curr_time); 00258 00259 // check gating variables are still in range 00260 VerifyStateVariables(); 00261 } 00262 00263 // Update solutions 00264 solutions.rGetSolutions().push_back(rGetStateVariables()); 00265 solutions.rGetTimes().push_back(curr_time+mDt); 00266 } 00267 00268 return solutions; 00269 } 00270 00271 template <unsigned SIZE> 00272 void AbstractBackwardEulerCardiacCell<SIZE>::ComputeExceptVoltage(double tStart, double tEnd) 00273 { 00274 // This method iterates over timesteps, calling ComputeExceptVoltage(t) at 00275 // each one, to update all state variables except for V, using backward Euler. 00276 00277 // Check length of time interval 00278 unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5); 00279 assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12); 00280 00281 // Loop over time 00282 double curr_time; 00283 for (unsigned i=0; i<n_steps; i++) 00284 { 00285 curr_time = tStart + i*mDt; 00286 00287 // Compute other state variables 00288 ComputeOneStepExceptVoltage(curr_time); 00289 00290 #ifndef NDEBUG 00291 // Check gating variables are still in range 00292 VerifyStateVariables(); 00293 #endif // NDEBUG 00294 } 00295 } 00296 00297 template<unsigned SIZE> 00298 void AbstractBackwardEulerCardiacCell<SIZE>::SolveAndUpdateState(double tStart, double tEnd) 00299 { 00300 TimeStepper stepper(tStart, tEnd, mDt); 00301 00302 while(!stepper.IsTimeAtEnd()) 00303 { 00304 double time = stepper.GetTime(); 00305 00306 // Compute next value of V 00307 UpdateTransmembranePotential(time); 00308 00309 // Compute other state variables 00310 ComputeOneStepExceptVoltage(time); 00311 00312 // check gating variables are still in range 00313 VerifyStateVariables(); 00314 00315 stepper.AdvanceOneTimeStep(); 00316 } 00317 } 00318 00319 00320 TEMPLATED_CLASS_IS_ABSTRACT_1_UNSIGNED(AbstractBackwardEulerCardiacCell) 00321 00322 #endif /*ABSTRACTBACKWARDEULERCARDIACCELL_HPP_*/