DifferentialEquations.jl icon indicating copy to clipboard operation
DifferentialEquations.jl copied to clipboard

Multiple callbacks result in apparent solver hang

Open klaff opened this issue 5 years ago • 4 comments

MWE:

using DifferentialEquations

function usode!(du,u,p,t)
    C1 = 1.63e-9
    RS = 790.0
    C2 = 3.3e-9
    C0 = 0.3e-9
    L1 = 1e-3
    L2 = 82e-3
    CM = 4e-12
    LM = 8.0
    RM = 7500.0
    VC1, VC2, VC0, VCM, IL1, IL2, ILM, Vp = u
    fv, VAmag = p
    VA = VAmag*sinpi(2*Vp)
    du[1] = 1/C1*IL1
    du[2] = -1/C2*IL1
    du[3] = 1/C0*(IL1-IL2-ILM)
    du[4] = 1/CM*ILM
    du[5] = 1/L1*(VA-VC1-VC0-VC2-IL1*RS)
    du[6] = 1/L2*VC0
    du[7] = 1/LM*(VC0-VCM-ILM*RM)
    du[8] = fv
end

mutable struct Controller
    f::Float64
end
function(c::Controller)(integrator)
    integrator.p[1] = c.f
    if c.f < 30000.0
        c.f += 15.0
    end
    println(join([integrator.t, c.f, integrator.p[3], integrator.p[4]], ", "))
end

condVzero(u,t,integrator) = integrator.p[2]*sinpi(2*u[8])-u[1] # Vmod
function affectVzero!(integrator)
    integrator.p[3]=integrator.t
end
cbVz = ContinuousCallback(condVzero, affectVzero!, nothing)
condIzero(u,t,integrator) = u[5]
function affectIzero!(integrator)
    integrator.p[4]=integrator.t
end
cbIz = ContinuousCallback(condIzero, affectIzero!, nothing)

function sim()
    p = [0.0, 100.0, 0.0, 0.0]
    cb1 = PeriodicCallback(Controller(27000.0),0.005)
    cbs = CallbackSet(cb1,cbVz,cbIz)
    #cbs = CallbackSet(cb1,cbVz)
    #cbs = CallbackSet(cb1,cbIz)
    u0 = [0.0,0.0,0.0,0.0, 0.0,0.0,0.0, 0.0]
    tspan = [0.0, 0.5]
    prob = ODEProblem(usode!,u0,tspan,p)
    @time sol = solve(prob,Tsit5(), callback=cbs, reltol=1e-8, abstol=1e-8, dense=false, maxiters=10_000_000)
    sol
end

sol = sim()

Looking at function sim, there are three lines that begin with cbs = CallbackSet. If I run as is, it stalls after 0.2 s (simulation time in print statements) and eventually dies wanting larger maxiters… If I instead use either of the commented cbs = lines, each only having one of the two ContinuousCallbacks, then it succeeds.

klaff avatar May 06 '20 00:05 klaff

Substituting Trapezoid() for Tsit5() gives an interesting error message rather than failing silently:

0.20500000000000002, 27630.0, 0.20498183392116934, 0.20498234571777418
┌ Warning: dt <= dtmin. Aborting. There is either an error in your model specification or the true solution is unstable.
└ @ DiffEqBase C:\Users\klaff\.julia\packages\DiffEqBase\XoVg5\src\integrator_interface.jl:343

The println output indicates that there were several very closely spaced callbacks just prior to the failure. I suspect the closely spaced callbacks are significant because I see a similar pattern in a non-NWE version.

klaff avatar May 06 '20 02:05 klaff

Using VectorContinuousCallback instead of two separate ContinuousCallbacks as follows appears to work:

using DifferentialEquations

function usode!(du,u,p,t)
    C1 = 1.63e-9
    RS = 790.0
    C2 = 3.3e-9
    C0 = 0.3e-9
    L1 = 1e-3
    L2 = 82e-3
    CM = 4e-12
    LM = 8.0
    RM = 7500.0
    VC1, VC2, VC0, VCM, IL1, IL2, ILM, Vp = u
    fv, VAmag = p
    VA = VAmag*sinpi(2*Vp)
    du[1] = 1/C1*IL1
    du[2] = -1/C2*IL1
    du[3] = 1/C0*(IL1-IL2-ILM)
    du[4] = 1/CM*ILM
    du[5] = 1/L1*(VA-VC1-VC0-VC2-IL1*RS)
    du[6] = 1/L2*VC0
    du[7] = 1/LM*(VC0-VCM-ILM*RM)
    du[8] = fv
end

mutable struct Controller
    f::Float64
end
function(c::Controller)(integrator)
    integrator.p[1] = c.f
    if c.f < 30000.0
        c.f += 15.0
    end
    println(join([integrator.t, c.f, integrator.p[3], integrator.p[4]], ", "))
end

condVzero(u,t,integrator) = integrator.p[2]*sinpi(2*u[8])-u[1] # Vmod
function affectVzero!(integrator)
    integrator.p[3]=integrator.t
end
cbVz = ContinuousCallback(condVzero, affectVzero!, nothing)
condIzero(u,t,integrator) = u[5]
function affectIzero!(integrator)
    integrator.p[4]=integrator.t
end
cbIz = ContinuousCallback(condIzero, affectIzero!, nothing)

function condition(out,u,t,integrator)
    out[1] =  integrator.p[2]*sinpi(2*u[8])-u[1]
    out[2] =  u[5]
end
function affect!(integrator, idx)
    if idx == 1
        integrator.p[3]=integrator.t
    elseif idx ==2
        integrator.p[4]=integrator.t
    end
end
vccb = VectorContinuousCallback(condition,affect!,2)

function sim()
    p = [0.0, 100.0, 0.0, 0.0]
    cb1 = PeriodicCallback(Controller(27000.0),0.005)
    #cbs = CallbackSet(cb1,cbVz,cbIz)
    cbs = CallbackSet(cb1,vccb)
    #cbs = CallbackSet(cb1,cbVz)
    #cbs = CallbackSet(cb1,cbIz)
    u0 = [0.0,0.0,0.0,0.0, 0.0,0.0,0.0, 0.0]
    tspan = [0.0, 0.5]
    prob = ODEProblem(usode!,u0,tspan,p)
    @time sol = solve(prob,Tsit5(), callback=cbs, reltol=1e-8, abstol=1e-8, dense=false, maxiters=10_000_000)
    sol
end

sol = sim()

klaff avatar May 06 '20 05:05 klaff

Nice that it worked for you, but still we need to fix that, I am busy till Tuesday, I will get back to the issue once I am free.

kanav99 avatar May 07 '20 04:05 kanav99

Nice that it worked for you, but still we need to fix that, I am busy till Tuesday, I will get back to the issue once I am free.

I try to leave breadcrumbs in case someone else has the same issue and also let you know I'm not dead in the water so you can prioritize appropriately.

As a note of appreciation - this is an amazing library - I'm beating on it pretty hard and in the process showing coworkers what is possible. Thanks!

klaff avatar May 07 '20 13:05 klaff