In an effort to make my code more easily extensible, I started using more structs containing the important arrays/data as parameters for my simulations, instead of the individual arrays.
Initially my old code looked like this:
using LoopVectorization
function simulate(h::HOI_ecosystem, dt::Real=1/mean(h.R)/10000)
# do some stuff before
for timestep in 1:10^7
update_n!(h, dt)
end
# do some stuff after
end
function update_n!(A::Matrix{Float64}, n::Vector{<:Real},
m::Matrix{<:Real}, R::Vector{<:Real}, d::Vector{<:Real}, dt::Float64)
N = length(n)
@avx for i = 1:N
dni = R[i] + d[i]*n[i]
for j = 1:N
dni += A[i,j]*m[i,j]*n[j]
end
n[i] = n[i]*(1+dni*dt)
end
return n
end
Running this code many times during my simulation takes around 0.7 seconds, with 361 k allocations, 17MiB.
Then I grouped all the vectors and matrices into a struct. Now my code looks as follows:
First I have the struct single_HOI_ecosystem
struct single_HOI_ecosystem <: one_HOI_ecosystem
N::Int
n::Vector{<:Real}
m::Matrix{Float64}
A::Matrix{Float64}
R::Vector{<:Real}
d::Vector{<:Real}
end
And a function that does calculations:
using LoopVectorization
function simulate(h::HOI_ecosystem, dt::Real=1/mean(h.R)/10000)
# do some stuff before
for timestep in 1:10^7
update_n!(h, dt)
end
# do some stuff after
end
function update_n!(h::HOI_ecosystem, dt::Real=1/mean(h.R)/10000)
N = length(h.n)
n = h.n
m = h.m
A = h.A
R = h.R
d = h.d
@avx for i = 1:N
dni = R[i] + d[i]*n[i]
for j = 1:N
dni += A[i,j]*m[i,j]*n[j]
end
n[i] = n[i]*(1+dni*dt)
end
return n
end
This is running around 6 times slower than my old code. Using it in exactly the same way as before gives a runtime of around 5 seconds, 11.35 M allocations and 252.93 MiB. The stuff before and after hasn’t changed (and doesn’t take up much time).
The reason why I want to put it in structs is because I have a few very similar functions with slightly different patterns that can easiliy be put together using structs.