AbstractBackwardEulerCardiacCell.hpp
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
00031
00032
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
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
00201
00202
00203
00204
00205
00206
00207 template <unsigned SIZE>
00208 AbstractBackwardEulerCardiacCell<SIZE>::AbstractBackwardEulerCardiacCell(
00209 unsigned numberOfStateVariables,
00210 unsigned voltageIndex,
00211 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus)
00212 : AbstractCardiacCell(boost::shared_ptr<AbstractIvpOdeSolver>(),
00213 numberOfStateVariables,
00214 voltageIndex,
00215 pIntracellularStimulus)
00216 {}
00217
00218 template <unsigned SIZE>
00219 AbstractBackwardEulerCardiacCell<SIZE>::~AbstractBackwardEulerCardiacCell()
00220 {}
00221
00222 template <unsigned SIZE>
00223 OdeSolution AbstractBackwardEulerCardiacCell<SIZE>::Compute(double tStart, double tEnd, double tSamp)
00224 {
00225
00226
00227
00228
00229
00230
00231 if (tSamp < mDt)
00232 {
00233 tSamp = mDt;
00234 }
00235 double _n_steps = (tEnd - tStart) / tSamp;
00236 const unsigned n_steps = (unsigned) floor(_n_steps+0.5);
00237 assert(fabs(tStart+n_steps*tSamp - tEnd) < 1e-12);
00238 const unsigned n_small_steps = (unsigned) floor(tSamp/mDt+0.5);
00239 assert(fabs(mDt*n_small_steps - tSamp) < 1e-12);
00240
00241
00242 OdeSolution solutions;
00243 solutions.SetNumberOfTimeSteps(n_steps);
00244 solutions.rGetSolutions().push_back(rGetStateVariables());
00245 solutions.rGetTimes().push_back(tStart);
00246 solutions.SetOdeSystemInformation(this->mpSystemInfo);
00247
00248
00249 double curr_time = tStart;
00250 for (unsigned i=0; i<n_steps; i++)
00251 {
00252 for (unsigned j=0; j<n_small_steps; j++)
00253 {
00254 curr_time = tStart + i*tSamp + j*mDt;
00255
00256
00257 UpdateTransmembranePotential(curr_time);
00258
00259
00260 ComputeOneStepExceptVoltage(curr_time);
00261
00262
00263 VerifyStateVariables();
00264 }
00265
00266
00267 solutions.rGetSolutions().push_back(rGetStateVariables());
00268 solutions.rGetTimes().push_back(curr_time+mDt);
00269 }
00270
00271 return solutions;
00272 }
00273
00274 template <unsigned SIZE>
00275 void AbstractBackwardEulerCardiacCell<SIZE>::ComputeExceptVoltage(double tStart, double tEnd)
00276 {
00277
00278
00279
00280
00281 unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5);
00282 assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12);
00283
00284
00285 double curr_time;
00286 for (unsigned i=0; i<n_steps; i++)
00287 {
00288 curr_time = tStart + i*mDt;
00289
00290
00291 ComputeOneStepExceptVoltage(curr_time);
00292
00293 #ifndef NDEBUG
00294
00295 VerifyStateVariables();
00296 #endif // NDEBUG
00297 }
00298 }
00299
00300 template<unsigned SIZE>
00301 void AbstractBackwardEulerCardiacCell<SIZE>::SolveAndUpdateState(double tStart, double tEnd)
00302 {
00303 TimeStepper stepper(tStart, tEnd, mDt);
00304
00305 while(!stepper.IsTimeAtEnd())
00306 {
00307 double time = stepper.GetTime();
00308
00309
00310 UpdateTransmembranePotential(time);
00311
00312
00313 ComputeOneStepExceptVoltage(time);
00314
00315
00316 VerifyStateVariables();
00317
00318 stepper.AdvanceOneTimeStep();
00319 }
00320 }
00321
00322
00323
00327
00331 template<>
00332 class AbstractBackwardEulerCardiacCell<0u> : public AbstractCardiacCell
00333 {
00334 private:
00336 friend class boost::serialization::access;
00343 template<class Archive>
00344 void serialize(Archive & archive, const unsigned int version)
00345 {
00346
00347 archive & boost::serialization::base_object<AbstractCardiacCell>(*this);
00348 }
00349
00350 public:
00359 AbstractBackwardEulerCardiacCell(unsigned numberOfStateVariables,
00360 unsigned voltageIndex,
00361 boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus)
00362 : AbstractCardiacCell(boost::shared_ptr<AbstractIvpOdeSolver>(),
00363 numberOfStateVariables,
00364 voltageIndex,
00365 pIntracellularStimulus)
00366 {}
00367
00369 virtual ~AbstractBackwardEulerCardiacCell()
00370 {}
00371
00384 OdeSolution Compute(double tStart, double tEnd, double tSamp=0.0)
00385 {
00386
00387
00388
00389
00390
00391
00392 if (tSamp < mDt)
00393 {
00394 tSamp = mDt;
00395 }
00396 double _n_steps = (tEnd - tStart) / tSamp;
00397 const unsigned n_steps = (unsigned) floor(_n_steps+0.5);
00398 assert(fabs(tStart+n_steps*tSamp - tEnd) < 1e-12);
00399 const unsigned n_small_steps = (unsigned) floor(tSamp/mDt+0.5);
00400 assert(fabs(mDt*n_small_steps - tSamp) < 1e-12);
00401
00402
00403 OdeSolution solutions;
00404 solutions.SetNumberOfTimeSteps(n_steps);
00405 solutions.rGetSolutions().push_back(rGetStateVariables());
00406 solutions.rGetTimes().push_back(tStart);
00407 solutions.SetOdeSystemInformation(this->mpSystemInfo);
00408
00409
00410 double curr_time = tStart;
00411 for (unsigned i=0; i<n_steps; i++)
00412 {
00413 for (unsigned j=0; j<n_small_steps; j++)
00414 {
00415 curr_time = tStart + i*tSamp + j*mDt;
00416
00417
00418 UpdateTransmembranePotential(curr_time);
00419
00420
00421 ComputeOneStepExceptVoltage(curr_time);
00422
00423
00424 VerifyStateVariables();
00425 }
00426
00427
00428 solutions.rGetSolutions().push_back(rGetStateVariables());
00429 solutions.rGetTimes().push_back(curr_time+mDt);
00430 }
00431
00432 return solutions;
00433 }
00434
00444 void ComputeExceptVoltage(double tStart, double tEnd)
00445 {
00446
00447
00448
00449
00450 unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5);
00451 assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12);
00452
00453
00454 double curr_time;
00455 for (unsigned i=0; i<n_steps; i++)
00456 {
00457 curr_time = tStart + i*mDt;
00458
00459
00460 ComputeOneStepExceptVoltage(curr_time);
00461
00462 #ifndef NDEBUG
00463
00464 VerifyStateVariables();
00465 #endif // NDEBUG
00466 }
00467 }
00468
00476 void SolveAndUpdateState(double tStart, double tEnd)
00477 {
00478 TimeStepper stepper(tStart, tEnd, mDt);
00479
00480 while(!stepper.IsTimeAtEnd())
00481 {
00482 double time = stepper.GetTime();
00483
00484
00485 UpdateTransmembranePotential(time);
00486
00487
00488 ComputeOneStepExceptVoltage(time);
00489
00490
00491 VerifyStateVariables();
00492
00493 stepper.AdvanceOneTimeStep();
00494 }
00495 }
00496
00497 private:
00498 #define COVERAGE_IGNORE
00499
00506 void EvaluateYDerivatives(double time, const std::vector<double> &rY, std::vector<double> &rDY)
00507 {
00508 NEVER_REACHED;
00509 }
00510 #undef COVERAGE_IGNORE
00511
00512 protected:
00521 virtual void ComputeOneStepExceptVoltage(double tStart)=0;
00522
00530 virtual void UpdateTransmembranePotential(double time)=0;
00531 };
00532
00533
00534
00535 #ifndef NDEBUG
00536 #include "OutputFileHandler.hpp"
00537 #include <boost/foreach.hpp>
00538 template<unsigned SIZE>
00539 void DumpJacobianToFile(double time, const double rCurrentGuess[SIZE], double rJacobian[SIZE][SIZE],
00540 const std::vector<double>& rY)
00541 {
00542 OutputFileHandler handler("DumpJacs", false);
00543 out_stream p_file = handler.OpenOutputFile("J.txt", std::ios::app);
00544 (*p_file) << "At " << time << " " << SIZE << std::endl;
00545 (*p_file) << "rY";
00546 BOOST_FOREACH(double y, rY)
00547 {
00548 (*p_file) << " " << y;
00549 }
00550 (*p_file) << std::endl;
00551 (*p_file) << "rCurrentGuess";
00552 for (unsigned i=0; i<SIZE; i++)
00553 {
00554 (*p_file) << " " << rCurrentGuess[i];
00555 }
00556 (*p_file) << std::endl;
00557 (*p_file) << "rJacobian";
00558 for (unsigned i=0; i<SIZE; i++)
00559 {
00560 for (unsigned j=0; j<SIZE; j++)
00561 {
00562 (*p_file) << " " << rJacobian[i][j];
00563 }
00564 }
00565 (*p_file) << std::endl;
00566 }
00567 #endif
00568
00569
00570
00571 TEMPLATED_CLASS_IS_ABSTRACT_1_UNSIGNED(AbstractBackwardEulerCardiacCell)
00572
00573 #endif