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
00029
00030 #ifndef ABSTRACTBACKWARDEULERCARDIACCELL_HPP_
00031 #define ABSTRACTBACKWARDEULERCARDIACCELL_HPP_
00032
00033 #include <cassert>
00034 #include <cmath>
00035
00036 #include "ChasteSerialization.hpp"
00037 #include <boost/serialization/base_object.hpp>
00038 #include "ClassIsAbstract.hpp"
00039
00040 #include "AbstractCardiacCell.hpp"
00041 #include "Exception.hpp"
00042 #include "PetscTools.hpp"
00043 #include "TimeStepper.hpp"
00044
00059 template<unsigned SIZE>
00060 class AbstractBackwardEulerCardiacCell : public AbstractCardiacCell
00061 {
00062 private:
00064 friend class boost::serialization::access;
00071 template<class Archive>
00072 void serialize(Archive & archive, const unsigned int version)
00073 {
00074
00075 archive & boost::serialization::base_object<AbstractCardiacCell>(*this);
00076 }
00077 public:
00078
00094 AbstractBackwardEulerCardiacCell(
00095 unsigned numberOfStateVariables,
00096 unsigned voltageIndex,
00097 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus);
00098
00100 virtual ~AbstractBackwardEulerCardiacCell();
00101
00109 virtual void ComputeResidual(double time, const double rCurrentGuess[SIZE], double rResidual[SIZE])=0;
00110
00118 virtual void ComputeJacobian(double time, const double rCurrentGuess[SIZE], double rJacobian[SIZE][SIZE])=0;
00119
00132 OdeSolution Compute(double tStart, double tEnd, double tSamp=0.0);
00133
00143 void ComputeExceptVoltage(double tStart, double tEnd);
00144
00152 void SolveAndUpdateState(double tStart, double tEnd);
00153
00154 private:
00155 #define COVERAGE_IGNORE
00156
00163 void EvaluateYDerivatives(double time, const std::vector<double> &rY, std::vector<double> &rDY)
00164 {
00165 NEVER_REACHED;
00166 }
00167 #undef COVERAGE_IGNORE
00168
00169 protected:
00178 virtual void ComputeOneStepExceptVoltage(double tStart)=0;
00179
00187 virtual void UpdateTransmembranePotential(double time)=0;
00188 };
00189
00190
00191
00192
00193
00194
00195
00196
00197 template <unsigned SIZE>
00198 AbstractBackwardEulerCardiacCell<SIZE>::AbstractBackwardEulerCardiacCell(
00199 unsigned numberOfStateVariables,
00200 unsigned voltageIndex,
00201 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus)
00202 : AbstractCardiacCell(boost::shared_ptr<AbstractIvpOdeSolver>(),
00203 numberOfStateVariables,
00204 voltageIndex,
00205 pIntracellularStimulus)
00206 {}
00207
00208 template <unsigned SIZE>
00209 AbstractBackwardEulerCardiacCell<SIZE>::~AbstractBackwardEulerCardiacCell()
00210 {}
00211
00212 template <unsigned SIZE>
00213 OdeSolution AbstractBackwardEulerCardiacCell<SIZE>::Compute(double tStart, double tEnd, double tSamp)
00214 {
00215
00216
00217
00218
00219
00220
00221 if (tSamp < mDt)
00222 {
00223 tSamp = mDt;
00224 }
00225 double _n_steps = (tEnd - tStart) / tSamp;
00226 const unsigned n_steps = (unsigned) floor(_n_steps+0.5);
00227 assert(fabs(tStart+n_steps*tSamp - tEnd) < 1e-12);
00228 const unsigned n_small_steps = (unsigned) floor(tSamp/mDt+0.5);
00229 assert(fabs(mDt*n_small_steps - tSamp) < 1e-12);
00230
00231
00232 OdeSolution solutions;
00233 solutions.SetNumberOfTimeSteps(n_steps);
00234 solutions.rGetSolutions().push_back(rGetStateVariables());
00235 solutions.rGetTimes().push_back(tStart);
00236 solutions.SetOdeSystemInformation(this->mpSystemInfo);
00237
00238
00239 double curr_time = tStart;
00240 for (unsigned i=0; i<n_steps; i++)
00241 {
00242 for (unsigned j=0; j<n_small_steps; j++)
00243 {
00244 curr_time = tStart + i*tSamp + j*mDt;
00245
00246
00247 UpdateTransmembranePotential(curr_time);
00248
00249
00250 ComputeOneStepExceptVoltage(curr_time);
00251
00252
00253 VerifyStateVariables();
00254 }
00255
00256
00257 solutions.rGetSolutions().push_back(rGetStateVariables());
00258 solutions.rGetTimes().push_back(curr_time+mDt);
00259 }
00260
00261 return solutions;
00262 }
00263
00264 template <unsigned SIZE>
00265 void AbstractBackwardEulerCardiacCell<SIZE>::ComputeExceptVoltage(double tStart, double tEnd)
00266 {
00267
00268
00269
00270
00271 unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5);
00272 assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12);
00273
00274
00275 double curr_time;
00276 for (unsigned i=0; i<n_steps; i++)
00277 {
00278 curr_time = tStart + i*mDt;
00279
00280
00281 ComputeOneStepExceptVoltage(curr_time);
00282
00283 #ifndef NDEBUG
00284
00285 VerifyStateVariables();
00286 #endif // NDEBUG
00287 }
00288 }
00289
00290 template<unsigned SIZE>
00291 void AbstractBackwardEulerCardiacCell<SIZE>::SolveAndUpdateState(double tStart, double tEnd)
00292 {
00293 TimeStepper stepper(tStart, tEnd, mDt);
00294
00295 while(!stepper.IsTimeAtEnd())
00296 {
00297 double time = stepper.GetTime();
00298
00299
00300 UpdateTransmembranePotential(time);
00301
00302
00303 ComputeOneStepExceptVoltage(time);
00304
00305
00306 VerifyStateVariables();
00307
00308 stepper.AdvanceOneTimeStep();
00309 }
00310 }
00311
00312
00313 TEMPLATED_CLASS_IS_ABSTRACT_1_UNSIGNED(AbstractBackwardEulerCardiacCell)
00314
00315 #endif