3D monodomain example using CVODE for ODE solution#
This tutorial is based on Monodomain 3D Example except this time we will
use CVODE solvers. To highlight the changes needed to run with CVODE we omit the usual
explanations of the rest of the code - see Monodomain 3D Example for these.
First include the headers
Chaste actually has two ways of using CVODE for solution of cardiac action potential model ODEs:
via a CvodeAdaptor solver - this would work on the usual cell model as in the previous tutorial.
via an AbstractCvodeCell instead of an AbstractCardiacCell - this class uses native CVODE vectors and is preferred.
NB: recent improvements (available from release 2021.1) mean that
an analytic jacobian is automatically made available to CVODE via the
native AbstractCvodeCell, and this will provide a speed up of between 5-30% (depending on the size of
the ODE system).
So here we do the #include to import the native CVODE version of the cell model.
then include the rest of the headers as usual
Since CVODE is an optional extra dependency for Chaste - albeit now
one that is highly recommended - see the [wiki:InstallGuides/InstallGuide InstallGuide].
We guard any code that relies upon it with the following #ifdef.
This CHASTE_CVODE flag is set automatically by cmake during the build process.
The major changes required to run with CVODE cells are in the cell factory.
The following method definition changes to return an AbstractCvodeCell
instead of an AbstractCardiacCell.
Purely in order to maintain a consistent interface,
an AbstractCvodeCell expects an AbstractIvpOdeSolver in its
constructor, but it is not used (CVODE is instead). So an empty
pointer can be passed.
We then create a ’native’ CVODE cell - each cell has its own solver embedded within it.
Each cell needs its own solver because CVODE saves information about the solver state
between runs to perform its adaptive scheme.
NB: this will use more memory than the standard approach of sharing one solver
object between all of the action potential models on a processor.
We can also set the tolerances of the ODE solver (in this case,
the method is just setting them to the same as the default, but is shown for completeness).
If you ever get a state variable going out of range with CVODE, then tighten these tolerances .
(but we haven’t had that problem with these settings -
that are better than anything but a ridiculously small Forward Euler step).
The rest of the test is almost identical to the non-CVODE cell case (just note the #ifdef tag).
Note - when using CVODE in cardiac tissue simulations the ODE timestep
should be set to the same as the PDE timestep.
CVODE will take as many adaptive internal timesteps as it requires each time
it is called, so we should just call it once per PDE timestep - i.e. set the
ODE and PDE timesteps to be the same.
NB: CVODE will only give you a big speedup when the ODE/PDE timestep is larger than
a typical Forward Euler timestep would be for that model. But it doesn’t
seem to be any slower than Forward Euler, even at this PDE resolution.
A convergence analysis should be performed to ensure that the PDE is being solved
accurately before reducing the step just to get faster ODE solution!
The rest of the code is unchanged.
NB: CVODE almost certainly gives a more accurate ODE solution than
Forward Euler, so this result has been tweaked from previous tutorial (34.9032mV previously).
Here we add a visual warning in case CVODE is not installed and/or set up.
If you want to make sure CVODE is run in your own tests you could add in
the TS_ASSERT(false); line.
Since CVODE is still optional for Chaste we allow the test to pass without it,
but note that if this is the case, then the test is not doing anything!