-
Notifications
You must be signed in to change notification settings - Fork 38
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