Callback: Switch between dynamic models and time step depending on the region

Hello everyone,

I would like to solve an ODE in DifferentialEquations.jl where the right-hand side and the time step depend on the region where is located the particle.
The function DiscreteCallBack seems to be adequate for my problem.
But I don’t know how to change the right hand of the ODEProblem in the function affect!
From http://docs.juliadiffeq.org/latest/basics/integrator.html,
integrator.f should be the function being solved

Here a simplified example of what I am trying to do:
We have a particle whose dynamic is governed by a first function f1. When u[1]<0.0, we want to switch to a second dynamic f2 and change the time step

using OrdinaryDiffEq

# Model for the first region u[1=]>0
function f1(du,u,p,t)
  du[1] = u[2]
  du[2] = -p
end
# Model for the second region u[2]<0
function f2(du,u,p,t)
  du[1] = -2*u[2]
  du[2] = 0.5*p
end

 function condition(u,t,integrator) # Switch model if u[1]<0.0
  u[1]<0.0
end
function affect!(integrator)
  integrator.f = f2
  set_proposed_dt!(integrator,0.01)
end
cb = DiscreteCallback(condition,affect!)

u0 = [50.0,0.0]
tspan = (0.0,15.0)
p = 9.8
prob = ODEProblem(f1,u0,tspan,p)

sol = solve(prob,RK4(), dt = 0.1, callback=cb)

Thank you for your help,

You can make those both one function with a boolean that chooses which model to use. Then that boolean can be changed in the callback.

1 Like

Thank you again @ChrisRackauckas for your help.
Since my system will be switching back and forth between the two regions. Is there a way to define a affect_neg! for DiscreteCallBack, when the condition switches from True to False, and affect! will be used when the condition switches from False to True

Just check if the parameter is true or false in integrator.p.

I am not sure that I understand.

In the following example, my boolean p remains true once the callback has been activated and the solution have been in the negative region( where condition is true) and returned to the positive region ( where condition is false). Also the time step stays fixed to 0.5 for the rest of the simulation, and doesn’t return to 0.1 as I would expect in the region positive( where condition is false)

using DifferentialEquations
using OrdinaryDiffEq

# Model for the first region u[1=]>0
function f(du,u,p,t)
    print(p)
    if p == false
  du[1] = -2.0
    else
  du[1] = 1.0
    end
end
p = false

function condition(u,t,integrator) # Switch model if u[1]<0.0
  u[1]<0.0
end
function affect!(integrator)
  integrator.p = true
  integrator.dtcache = 0.5
end

cb = DiscreteCallback(condition,affect!,save_positions=(false,true))

u0 = [1.0]
tspan = (0.0,5.0)
prob = ODEProblem(f,u0,tspan,p)

sol = solve(prob,RK4(), dt = 0.1,adaptive = false, callback=cb)

Yes, and to switch back you can check if integrator.p and flip it.

Wait, why are you using a DiscreteCallback here instead of a Continuous callback?

I got it works, thank you. There was some conditions for the switch of regions which were hard to express using ContinuousCallBack. I had to switch the model at multiple of a time scale, which is easier to express with a boolean condition like ( mod(t, Tscale) =0).