Hi,
I encountered something weird when I was trying to solve a system of ODEs in two equivalent (if I don’t miss something very basic) ways.
Here is two ODE, that should be mathematically the same
C = -0.01+2im
function complex_func(du::Vector{ComplexF64}, u::Vector{ComplexF64}, p, t::Float64)
du[1] = C*u[1]
end
function real_func(du::Vector{Float64},u::Vector{Float64},p,t::Float64)
du[1] = real(C)*u[1]-imag(C)*u[2]
du[2] = imag(C)*u[1]+real(C)*u[2]
end
Solving them should be identical. But to my surprise there is a difference between the solution that the solver (Tsit5
) gives me. The difference is indeed small ~1e-7
for tspan = (0.0, 1.0)
but I expected the model to be solved internally the same.
I want to emphasize that I don’t care that they differ from the exact solution (which is easy to calculate), I care about the difference between each other.
julia> exact = u0c[1]exp(C*tf); abs(exact) # this just for understanding the scale
0.8935496450117586
julia> abs(sol_r[end][1] + 1im*sol_r[end][2] - exact[1]) / abs(exact)
2.00716203862083e-6 # great precision for me, I don't about this.
julia> abs((sol_r[end][1] + 1im*sol_r[end][2] - sol_c[end][1])/(sol_r[end][1] + 1im*sol_r[end][2] + sol_c[end][1]))
9.5661426125702e-8 # but why is that? shouldn't they just be the same?
Now, 1e-7
is not a big deal for me, but I have a different ODEs to solve that may be affected by that.
In my work I have two equivalent ways and the difference of the solution is about 60%
When I decrease dtmax
the two ways converge to each other but it’s still weird for me.
Thanks!
More code for details
using DifferentialEquations
C = -0.01+2im
function complex_func(du::Vector{ComplexF64}, u::Vector{ComplexF64}, p, t::Float64)
du[1] = C*u[1]
end
function real_func(du::Vector{Float64},u::Vector{Float64},p,t::Float64)
du[1] = real(C)*u[1]-imag(C)*u[2]
du[2] = imag(C)*u[1]+real(C)*u[2]
end
u_r = rand(2)
u_c = u_r[1]+1im*u_r[2]
du_c = [0.0im]
complex_func(du_c, [u_c], 0.0, 0.0)
du_r = [0.0, 0.0]
real_func(du_r, u_r, 0.0, 0.0)
du_r[1] + 1im*du_r[2] == du_c[1]
tf = 1.0
tspan = (0.0, tf)
u0r = rand(2)
u0c = [u0r[1]+1im*u0r[2]]
prob_c = ODEProblem(complex_func, u0c, tspan)
prob_r = ODEProblem(real_func, u0r, tspan)
integrator_c = init(prob_c, Tsit5(), abstol = 1e-10)
integrator_r = init(prob_r, Tsit5(), abstol = 1e-10)
sol_c = solve!(integrator_c)
sol_r = solve!(integrator_r)
sol_r[end][1] + 1im*sol_r[end][2] - sol_c[end][1]
(sol_r[end][1] + 1im*sol_r[end][2] - sol_c[end][1])/(sol_r[end][1] + 1im*sol_r[end][2] + sol_c[end][1])
exact = u0c[1]exp(C*tf)
# =#
exact = u0c[1]exp(C*tf); abs(exact)
abs(sol_r[end][1] + 1im*sol_r[end][2] - exact[1]) / abs(exact)
abs((sol_r[end][1] + 1im*sol_r[end][2] - sol_c[end][1])/(sol_r[end][1] + 1im*sol_r[end][2] + sol_c[end][1]))