Optimising allocations and memory use in ODEProblems

Here are a few things to consider regarding when to preallocate, and the possible complications it can lead to.

  1. Getting preallocation right can be a bit tricky. Case in point, your sys2! function still allocates, because p.a * u allocates a new array before it’s stored in p.b. To get rid of the allocation, you could write the function like this, for example:
using LinearAlgebra
function sys2!(du, u, p, t)
    mul!(p.b, p.a, u)
    @. du[1:p.n] = u * (p.r - p.b) 
    return nothing
end

where mul! from the LinearAlgebra standard library multiplies p.a with u without allocating a temporary array.

On a related trickyness note, some ODE solvers in DifferentialEquations.jl will not automatically play nice with preallocation, and you’ll have to use PreallocationTools.jl to get it to work properly.

  1. For small systems, you can use StaticArrays.jl, which don’t allocate and are very fast. The ballpark for when this is good is when an array contains less than about 100 elements (so no bigger than a 10x10 matrix).

  2. The parameter p is probably your best option for putting arrays for temporary allocation. Another option is to write something like:

my_rhs_fun!(du, u, (p, cache), t)
...
end
# Code for setting up the cache goes here
ode_prob = ODEProblem{true}(my_rhs_fun!, u0, t_span, (p, cache))
  1. Depending on your problem, avoiding allocations can save quite a lot of time, but (at least in my experience), it can be quite tricky to figure out when.
1 Like