AbstractBackwardEulerCardiacCell.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 
00201 /*
00202  * NOTE: Explicit instantiation is not used for this class, because the SIZE
00203  * template parameter could take arbitrary values.
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     // In this method, we iterate over timesteps, doing the following for each:
00226     //   - update V using a forward Euler step
00227     //   - call ComputeExceptVoltage(t) to update the remaining state variables
00228     //     using backward Euler
00229 
00230     // Check length of time interval
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     // Initialise solution store
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     // Loop over time
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             // Compute next value of V
00257             UpdateTransmembranePotential(curr_time);
00258 
00259             // Compute other state variables
00260             ComputeOneStepExceptVoltage(curr_time);
00261 
00262             // check gating variables are still in range
00263             VerifyStateVariables();
00264         }
00265 
00266         // Update solutions
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     // This method iterates over timesteps, calling ComputeExceptVoltage(t) at
00278     // each one, to update all state variables except for V, using backward Euler.
00279 
00280     // Check length of time interval
00281     unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5);
00282     assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12);
00283 
00284     // Loop over time
00285     double curr_time;
00286     for (unsigned i=0; i<n_steps; i++)
00287     {
00288         curr_time = tStart + i*mDt;
00289 
00290         // Compute other state variables
00291         ComputeOneStepExceptVoltage(curr_time);
00292 
00293 #ifndef NDEBUG
00294         // Check gating variables are still in range
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         // Compute next value of V
00310         UpdateTransmembranePotential(time);
00311 
00312         // Compute other state variables
00313         ComputeOneStepExceptVoltage(time);
00314 
00315         // check gating variables are still in range
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         // This calls serialize on the base class.
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         // In this method, we iterate over timesteps, doing the following for each:
00387         //   - update V using a forward Euler step
00388         //   - call ComputeExceptVoltage(t) to update the remaining state variables
00389         //     using backward Euler
00390 
00391         // Check length of time interval
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         // Initialise solution store
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         // Loop over time
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                 // Compute next value of V
00418                 UpdateTransmembranePotential(curr_time);
00419 
00420                 // Compute other state variables
00421                 ComputeOneStepExceptVoltage(curr_time);
00422 
00423                 // check gating variables are still in range
00424                 VerifyStateVariables();
00425             }
00426 
00427             // Update solutions
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         // This method iterates over timesteps, calling ComputeExceptVoltage(t) at
00447         // each one, to update all state variables except for V, using backward Euler.
00448 
00449         // Check length of time interval
00450         unsigned n_steps = (unsigned)((tEnd - tStart) / mDt + 0.5);
00451         assert(fabs(tStart + n_steps*mDt - tEnd) < 1e-12);
00452 
00453         // Loop over time
00454         double curr_time;
00455         for (unsigned i=0; i<n_steps; i++)
00456         {
00457             curr_time = tStart + i*mDt;
00458 
00459             // Compute other state variables
00460             ComputeOneStepExceptVoltage(curr_time);
00461 
00462 #ifndef NDEBUG
00463             // Check gating variables are still in range
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             // Compute next value of V
00485             UpdateTransmembranePotential(time);
00486 
00487             // Compute other state variables
00488             ComputeOneStepExceptVoltage(time);
00489 
00490             // check gating variables are still in range
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 // Debugging
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 /*ABSTRACTBACKWARDEULERCARDIACCELL_HPP_*/

Generated by  doxygen 1.6.2