RecursiveArrayTools.jl
RecursiveArrayTools.jl copied to clipboard
Issue with OrdinaryDiffEq.jl when using an ArrayPartition of Arrays of StaticArrays
OrdinaryDiffEq.jl has an issue with ArrayPartitions constructed from nested arrays of StaticArrays. The following MWE
using StaticArrays, StructArrays
using RecursiveArrayTools
using OrdinaryDiffEq
u1 = StructArray{SVector{2, Float64}}(ntuple(x -> x * ones(10), 2))
u2 = deepcopy(u1)
u = ArrayPartition(u1, u2)
function rhs!(du, u, p, t)
du .= u
end
prob = ODEProblem(rhs!, u, (0, 1.0))
sol = solve(prob, Tsit5())
yields the stacktrace
ERROR: MethodError: Cannot `convert` an object of type Float64 to an object of type SVector{2, Float64}
Closest candidates are:
convert(::Type{SA}, ::Tuple) where SA<:StaticArray at ~/.julia/packages/StaticArrays/0T5rI/src/convert.jl:171
convert(::Type{SA}, ::SA) where SA<:StaticArray at ~/.julia/packages/StaticArrays/0T5rI/src/convert.jl:170
convert(::Type{SA}, ::StaticArray{S}) where {SA<:StaticArray, S<:Tuple} at ~/.julia/packages/StaticArrays/0T5rI/src/convert.jl:164
...
Stacktrace:
[1] maybe_convert_elt(#unused#::Type{SVector{2, Float64}}, vals::Float64)
@ StructArrays ~/.julia/packages/StructArrays/rICDm/src/utils.jl:197
[2] setindex!
@ ~/.julia/packages/StructArrays/rICDm/src/structarray.jl:363 [inlined]
[3] macro expansion
@ ./broadcast.jl:961 [inlined]
[4] macro expansion
@ ./simdloop.jl:77 [inlined]
[5] copyto!
@ ./broadcast.jl:960 [inlined]
[6] copyto!
@ ./broadcast.jl:913 [inlined]
[7] f
@ ~/.julia/packages/RecursiveArrayTools/YoTgv/src/array_partition.jl:327 [inlined]
[8] ntuple
@ ./ntuple.jl:49 [inlined]
[9] copyto!
@ ~/.julia/packages/RecursiveArrayTools/YoTgv/src/array_partition.jl:329 [inlined]
[10] materialize!
@ ./broadcast.jl:871 [inlined]
[11] materialize!
@ ./broadcast.jl:868 [inlined]
[12] fast_materialize!
@ ~/.julia/packages/FastBroadcast/fkwMa/src/FastBroadcast.jl:47 [inlined]
[13] ode_determine_initdt(u0::ArrayPartition{Float64, Tuple{StructVector{SVector{2, Float64}, Tuple{Vector{Float64}, ....
I'm not sure but this seems to be related to the fact that eltype
of ArrayPartitions of AbstractArray{<:StaticArray{N,T}}
is T
rather than StaticArray{N,T}
.
Note to self: the issue disappears when specifying an initial dt
and adaptive=false
. If an initial dt
isn't specified, the error is in https://github.com/SciML/OrdinaryDiffEq.jl/blob/b15f3c53601c274a69216ffea242a46561bbe121/src/initdt.jl#L23
@.. broadcast=false sk = abstol+internalnorm(u0,t)*reltol
If adaptive=false
isn't specified, there's a similar error with fast broadcast over compute_residuals
.
Since the eltype
of an ArrayPartition of Arrays of SVector
is Float64
, it triggers https://github.com/SciML/OrdinaryDiffEq.jl/blob/b15f3c53601c274a69216ffea242a46561bbe121/src/initdt.jl#L15 and the broadcast assignment to sk
errors.
However, manually defining an ArrayPartition of StructArray{<:SVector}
with eltype
= SVector
leads to conflicting broadcast rules between ArrayPartition and StructArrays.
Yeah, I think we need to extend the ArrayPartition broadcast overload so that will generate an ArrayPartition{SVector}.
Turns out this is just because the constructor used in the example calls recursive_bottom_eltype
to determine T
. Using the default constructor instead and specifying T
manually fixes things, and broadcasting seems to work fine.
using StaticArrays, RecursiveArrayTools
u1 = [SVector{2, Float64}(1,2) for _ in 1:5]
u2 = zeros(SVector{2, Float64}, (2, 2))
args = (u1, u2)
u = ArrayPartition{eltype(u1), typeof(args)}(args)
du = similar(u)
du .= u
I'm OK to close this if you are.
EDIT: nevermind, this doesn't fix the original issue
So you're saying Arrays of StaticArrays are fine in the differential equation solve? That's what I would have expected since there are tests covering it. I'm not sure what the StructArray is doing in the first example?
Oops, I copied and pasted the wrong example code. StructArrays were just in the MWE for similarity to the full application.
Switching to the other constructor fixed an unrelated issue, so scratch the previous comment.
I'm confused as to what the problem is and whether it's solved 😅
Sorry - to clarify, the problem remains. I solved an unrelated issue recently, and it'd been too long since I looked at this and thought I'd solved it too.