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