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

diffeq
differentiation
#1

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,

0 Likes

#2

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

#3

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

0 Likes

#4

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

0 Likes

#5

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)
0 Likes

#6

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

0 Likes

#7

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

0 Likes

#8

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).

0 Likes