xolotl is designed to be as fast as possible. In our testing, it is the fastest simulator out there, and these tips will help you make your simulations run as fast as possible.
We will use a single compartment bursting neuron and show what parameters increase or decrease speed of simulation. You can create this bursting neuron model using:
We will measure speed as the ratio of the simulated time to the real time taken. Let's run our simulations for 20 seconds:
x.t_end = 20e3;
We ran these numbers on a 2013 Apple MacBook, which is far from the fastest computer out there. Your experience may vary.
Here's a one-liner that measures the speed of integration of this model:
tic; x.integrate; t = toc; (x.t_end*1e-3)/t ans = 59.8476
Out of the box, our model is running around
60X real-time. Let's see what we can do to speed this up.
Strategies to increase speed¶
The simplest way to make your simulation run faster is to increase the
sim_dt. Speed should be linear with
sim_dt, as shown in this plot:
Remember that the accuracy of the simulation decreases with increasing
Many channels in xolotl can construct look-up tables (
LUTs) for some functions. This can dramatically speed up your code, at the cost of accuracy.
x.approx_channels = 1; tic; x.integrate; t = toc; (x.t_end*1e-3)/t ans = 132.3989
Here, using approximations made the simulation run twice as fast.
Use simple solvers¶
The ODEs in this model can be solved using two different methods:
- The exponential Euler method, as described in the textbook by Dayan & Abbott
- The Runge-Kutta 4 method, which is general-purpose multi-step method
We see that the exponential Euler solver is more than 2 times faster than the Runge-Kutta solver for the same time step.
x.approx_channels = 0; x.solver_order = 0; tic; x.integrate; t = toc; (x.t_end*1e-3)/t ans = 60.4497 x.approx_channels = 0; x.solver_order = 4; tic; x.integrate; t = toc; (x.t_end*1e-3)/t ans = 24.7365
Use the simplest version of the model¶
There are multiple versions of many components in xolotl. For example, there are temperature-sensitive versions of the channels we used here. If you don't need a feature, don't use it.
Don't create outputs¶
Skipping outputs technically makes the simulation run faster, but this effect is negligible.
tic; [V, Ca, I] = x.integrate; t = toc; (x.t_end*1e-3)/t ans = 58.7266
closed_loop can make things go a little faster, though in most cases this effect is negligible. When
cpplab.deserialize is not called, so that's where the savings comes from.
x.closed_loop = false; tic; V = x.integrate; t = toc; (x.t_end*1e-3)/t ans = 61.5055
Combining these tips together, we can get some insanely fast speeds, at the cost of accuracy. You should inspect your model outputs and decide where the tradeoff between speed and quality lies for you.
% slow but very accurate x.approx_channels = 0; x.solver_order = 4; x.sim_dt = .05; x.dt = .1; tic; V1 = x.integrate; t = toc; (x.t_end*1e-3)/t % fast but less accurate x.approx_channels = 1; x.solver_order = 0; x.sim_dt = .1; x.dt = .1; tic; V2 = x.integrate; t = toc; (x.t_end*1e-3)/t
The slow-but-accurate simulation ran at
22X while the fast simulation ran at around
340X, or around fifteen times faster
Let's compare the outputs of the two simulations:
We see that the two traces are slightly different, but the overall features are the same.