There is a nice blog post here on using DE.jl with different number types.

In Julia v1.9 the following MWE errors:

using DifferentialEquations
function some_arbitrary_function!(du,u,p,τ)
du = u/100
nothing #function returns nothing
end
NF = Float32 # Number format
u = NF[0.0, 100.0, π/2.0, 0.0] #Initial conditions e.g. t, r θ, ϕ
params = NF[0.1, 3.5f-7] #Some arbitrary parameters, unused in this example, just a placeholder
tspan = (zero(NF),NF(1e3)) #integrate from t=0 to t = 1000
ode_prob = ODEProblem(some_arbitrary_function!,u,tspan,params)
ode_solution = solve(ode_prob,DifferentialEquations.RK4())

with a No matching function wrapper was found!. However if we change the end of tspan to a Float64:

tspan = (zero(NF),Float64(1e3))

then everything works ok. This seems like it could be related to this question. The MWE does work on Julia v1.7.

Is this expected behaviour? What is the workaround / best practice?

Open an issue. More specifically, the promotion rules missed the case where tspan is Float32 but state is Float64. Making both Float32 or both Float64 works, and having Float32 state with Float64 time correctly errors, though this is a combination that technically could work.

Oh, looks like you found a bug in the Float32 time handling in RK4. Fixed in:

The residual adaptivity points were calculated via σ₁ = 1 / 2 - sqrt(3) / 6 but should be in the type of t, i.e. σ₁ = convert(typeof(t), 1 // 2) - sqrt(convert(typeof(t),3)) / 6. That fixes it and tests a bunch more RKs for this.

(As a side note, I wouldn’t recommend RK4 for most things which aren’t DDEs which need residual controls, and even for that I would recommend the OwrenZen methods, but that’s a bit of a side note and this’ll get fixed anyways).