How can I disable the event handler in a fixed time interval after an event?

I have checked the document of DifferentialEquations.jl about the Event handler page. It seems that I should set repeat_nudge in a ContinuousCallback. However, it doesn’t work.

Here is an MME:

using OrdinaryDiffEq, StaticArrays

function f(x, p, t)
    SA[x[2], -x[1]]
end

function condition(u, t, integrator)
    u[1] - 1
end

function affect(integ)
    @show integ.t
end

cb = ContinuousCallback(condition, affect, repeat_nudge=0.3)

prob = ODEProblem(f, SA[0.0, 1.001], (0, 2), callback=cb)

sol = solve(prob, Tsit5())

I expected that the length of the time interval between two events is greater than 0.3. However, I got

integ.t = 1.526059239285522
integ.t = 1.6155612263459136

Since repeat_nudge only defines the next sign check, it might be that at 1.526 + 0.3, the first sign check happened, which triggered a root search, finding the next closest zero.

In the concrete case, you could consider using affect_neg! = (integ) -> nothing instead, e.g. only do something when the sign change is upcrossing (affect!) and do nothing for downcrossing sign change.

Thank you for explaining to me how repeat_nudge works. What I want to do is:

  • after an event, disable the event handler in a fixed time;
  • after this fixed time, reinitialize the event handler.

For this concrete example, What I want to do is the following. The event begins with condition<0, and hits 0 at t=1.526 and then the event status becomes condition>0. For a fixed time, see 0.3, the event handler starts work at 1.526+0.3 as its initial status, i.e. even if condition<0 at t=1.526+0.3 and condition crosses zero again, the function affect! won’t trigger.

You maybe can use rootfind = RightRootFind to avoid any backwards steps.
(But I didn’t try.)

I think callbacks should not have an internal state. In that case, it would be more idiomatic to integrate the delay time since the last callback into the state variable of the ODE.

For example, you could add a third variable x[3] with du[x] = -1 which measures how much time after the last callback passed.

using OrdinaryDiffEq

f(du, x, p, t) = du .= (x[2], -x[1], -1.0)

condition(u, t, integrator) = u[3] <= 0.0 ? u[1] - 1 : NaN

function affect(integ)
    @show integ.t
    integ.u[3] = 0.3
end

cb = ContinuousCallback(condition, affect)

prob = ODEProblem(f, [0.0, 1.001, 0.0], (0, 10), callback=cb)

sol = solve(prob, Tsit5())

which gives

integ.t = 1.5260514221058505
integ.t = 7.805140367104949

I haven’t thought of that. It is a working solution!!! I can use an extra parameter, instead of a state, to record the last event time.

1 Like