Closed
Description
I'm trying to simulate interacting particle systems. The state vector has dimension '2N' or '3N'.
It seems beneficial to use an Array of StaticArrays for the 2D/3D points.
HybridArrays.jl would be super nice here, since it avoids a Vector of SVectors
and is still very fast. (timings are in the code below; notice that access is exactly as for a 2xN Array!).
Issues:
- HybridArrays does not work with all methods (for example not with
Rosenbrock23()
,Rosenbrock23(autodiff=false)
). - Missing plot recipe (should be easy to implement)
I can try to work on the integration if wanted. Of course, hints are very welcome :D
I think HybridArrays could be an alternative to an Array of StaticArrays and without problems like #47 and SciML/LabelledArrays.jl#68.
using HybridArrays, StaticArrays
using DifferentialEquations, BenchmarkTools, Random
N = 50
Dim = 2
# just some random dynamics to show speed benefit of static arrays
function f_ode(du, u, p, t)
N = size(u,2)
du[:] .= 0.
for i = 1:N
for j = 1:i-1
v = u[:,i] - u[:,j]
dist_squared = sum( x -> x^2, v)
du[:,i] -= v * dist_squared
du[:,j] += v * dist_squared
end
end
end
# same as f_ode but for vector of svectors
function f_ode_vec_svec(du, u, p, t)
N = size(u,1)
du[:] .-= du[:] #(sorry, I don't know how to zero a vector of svectors fast.)
for i = 1:N
for j = 1:i-1
v = u[i] - u[j]
dist_squared = sum( x -> x^2, v)
du[i] -= v * dist_squared
du[j] += v * dist_squared
end
end
end
Random.seed!(1)
z0 = rand(Dim,N)
z0_hybrid = HybridArray{Tuple{Dim,StaticArrays.Dynamic()}}(z0)
Random.seed!(1)
z0_vec_svec = rand(SVector{Dim,Float64},N)
prob = ODEProblem(f_ode, z0, (0., 10.))
prob_hybrid = ODEProblem(f_ode, z0_hybrid, (0., 10.))
prob_vec_svec = ODEProblem(f_ode_vec_svec, z0_vec_svec, (0., 10.))
sol = @btime solve(prob, Euler(), dt=0.01) seconds=2
# 682.401 ms (33153208 allocations: 1.65 GiB)
sol_hybrid = @btime solve(prob_hybrid, Euler(), dt=0.01) seconds=2
# 7.337 ms (14070 allocations: 3.04 MiB)
sol_vec_svec = @btime solve(prob_vec_svec, Euler(), dt=0.01) seconds=2
# 5.019 ms (20074 allocations: 4.78 MiB)
sol2 = solve(prob, Rosenbrock23())
# works
sol2_hybrid = solve(prob_hybrid, Rosenbrock23())
# MethodError: copyto!(::DiffEqBase.DiffEqBC{Array{Float64,2}}, ::Base.Broadcast.Broadcasted{HybridArrays.HybridArrayStyle{2},Tuple{Base.OneTo{Int64},Base.OneTo{Int64}},typeof(muladd),Tuple{Base.Broadcast.Broadcasted{HybridArrays.HybridArrayStyle{2},Nothing,typeof(DiffEqBase.ODE_DEFAULT_NORM),Tuple{HybridArray{Tuple{2,StaticArrays.Dynamic()},Float64,2,2,Array{Float64,2}},Float64}},Float64,Float64}})
# is ambiguous.
sol2_vec_svec = solve(prob_vec_svec, Rosenbrock23())
# ArgumentError: Cannot create a dual over scalar type SArray{Tuple{2},Float64,1,2}.
# If the type behaves as a scalar, define FowardDiff.can_dual.
using Plots
plot( sol[1,1,:], sol[2,1,:])
plot( sol_hybrid[1,1,:], sol_hybrid[2,1,:])
plot( getindex.(sol_vec_svec[1,:],1) , getindex.(sol_vec_svec[1,:],2))
# plots look all the same
plot( sol )
# works
plot( sol_hybrid )
# MethodError: no method matching u_n(...)
# Note: Here a ::CartesianIndex{2} does not match the expected ::Int64
plot( sol_vec_svec )
# MethodError: no method matching one(::Type{SArray{Tuple{2},Float64,1,2}})
I can provide full error messages if needed.
Metadata
Metadata
Assignees
Labels
No labels