Help with callbacks (to set a variable to a constant value)

Hello! :slight_smile:

I am simulating a complex dynamical system with DifferentialEquations.jl and via callbacks I introduce perturbations of some parameters. I would like to introduce a callback which continuously sets a variable to a constant value (let’s say 2.0) when this constant value is reached. How can I do it?

I tried to use Discrete and Continuous callbacks, but my results are not satisfying:

  • With DiscreteCallback (see first example below), I manage to set the variable to 2.0 only when the callback is called. In all the other time-steps the variable decreases following its derivative (which is not set to zero!).

  • With ContinuousCallback (see second example below), I do not obtain any good result probably because my condition is never met.

I could manipulate the derivative du in the affect! function with DiscreteCallback and I obtain what I want, but I would not like to do that. I would rather preserve the correct physical equation of my model and introduce a callback which defines all the perturbations.
Moreover, with the DiscreteCallback my variable does not hit 2.0 and so the results is not perfect (see third example below).

Problem:

function f(du, u, p, t)
   du[1] = -u[1] * p
end
u0 = [10.0]
p = 1
prob = ODEProblem(f, u0, (0.0, 10.0),p)

Ex. 1 (DiscreteCallback):

condition_d(u, t, integrator) = integrator.u[1] <= 2.0
affect_d!(integrator) = integrator.u[1] = 2.0
cb_d = DiscreteCallback(condition_d, affect_d!)
sol = DifferentialEquations.solve(prob, Tsit5(), callback = cb_d)
plot(sol)
hline!([2.0],line=:dash,color=:red)

Ex. 2 (ContinuousCallback):

condition_c(u, t, integrator) = integrator.u[1]-2.0
affect_c!(integrator) = integrator.u[1] = 2.0
cb_c = ContinuousCallback(condition_c, affect_c!)
sol = DifferentialEquations.solve(prob, Tsit5(), callback = cb_c)
plot(sol)
hline!([2.0],line=:dash,color=:red)

Ex. 3 (DiscreteCallback by changing the derivative):

condition_d(u, t, integrator) = integrator.u[1] <= 2.0
function affect_d!(integrator)
    integrator.u[1] = 2.0
    integrator.p = 0
end
cb_d = DiscreteCallback(condition_d, affect_d!)
sol = DifferentialEquations.solve(prob, Tsit5(), callback = cb_d)
plot(sol)
hline!([2.0],line=:dash,color=:red)

You need to set derivative to 0 in the flow function if the constant is achieved. Otherwise, it will continue to change after the callback.

Yes I believe so. But is there any way that I can access the derivative inside the affect! function? Perhaps via the integrator interface or any other tool…? Something like integrator.du[1] = 0…

If you do that it only affects at the event instance. Later, it will continue to integrate with the flow function. That’s why you need to handle it in the flow function.

Way 3 should be fine, i.e. changing a parameter.