Hi everyone, I’ve only recently started using Julia and I was wondering if it’s possible to access the values obtained at earlier times by a solver in a callback function.
For example, I’m trying to identify maxima (as a function of time) in the solution of a simple oscillator and store them in a vector, but I don’t know how/if it’s possible to access the values of u
at previous times to compare them to the value at the current time. I’ve written out the logic I’m trying to achieve in the code below, but I don’t know how to define u_prev
or u_prev2
in the condition function. I want for the affect! function to store the current time when u_prev
is a local maximum.
using DifferentialEquations, Plots
function condition(u, t, integrator)
# u_prev = ? # Value of u[1] at the previous time
# u_prev2 = ? # Value of u[1] at the time before the previous time
u_curr = u[1]
if (u_curr < u_prev) && (u_prev2 < u_prev)
return 0
else
return 1
end
end
function affect!(integrator)
push!(peaks, integrator.t) # Store current time in peaks vector
end
cb = ContinuousCallback(condition, affect!)
# Initialise problem
u0 = ones(2)
p = (2.0, 1.0)
peaks = zeros(0)
function f!(du,u,p,t)
a, b = p
du[1] = a * u[2]
du[2] = -b * u[1]
end
prob = ODEProblem(f!, u0, (0.0, 50.0), p)
sol = solve(prob, Tsit5(), maxiters = 1e3, callback = cb, abstol=1e-6, reltol=1e-5)
I was thinking that I might be able to access previous values of u
through the integrator
, but I haven’t been able to figure this out. Similarly, when I try to display the value of integrator.du
, only the word “nothing” is outputted.
Any help would be greatly appreciated, and thank you in advance for your help!
1 Like
Since u'(t) = 0 and u''(t) < 0 at the maxima, you can write a continuous callback which evaluates those terms, and saves the current state at time t, I think? Your condition instead seems to be trying to find maxima discretely from u_{n-1}, u_n, and u_{n+1}, which is (afaik!) not something the callback interface can do. If you really want to do that, then I would not run it online (with the ODE solve) but analyze the solution array after it is complete.
I think that a continuous callback function that calculates when u_1'(t)=0 and u_1''(t)<0 would be ideal, but I haven’t been able to find out how to evaluate the derivatives of u(t) within a callback function. I don’t know how/if it’s possible to explicitly pass the derivatives to the callback function, and I don’t think they’re accessible through the integrator
.
Do you know how I can access u_1'(t) and u_1''(t) within the callback function?
integrator(t,Val{i})
for the i
th derivative.
Thanks for the help!
After testing, I’ve found that I can store the times of maxima in u[1]
using the functions:
condition(u, t, integrator) = integrator(t, Val{1})[1]
function affect!(integrator)
if (integrator(integrator.t, Val{2})[1] < 0.0)
push!(peaks, integrator.t) # Store current time in peaks vector
end
end
cb = ContinuousCallback(condition, affect!)
I’ve used the time stored in the integrator
(integrator.t
) in the affect!
function since t
is not passed to it explicitly, but do you know exactly what time this will correspond to? Ideally I would want the time at which the condition is satisfied, but I wanted to check whether integrator.t
would reference the time at the end of the current interval in this case (as I would expect it to if I displayed it from the condition
function).
Also, when using these functions in my original code two values of time are outputted to the peaks
vector for each maxima in u[1]
. These times are very similar (for example 0.6755106670700617
and 0.6755108454503309
for the first maxima). Is this due to floating point errors in the observed derivatives over short time intervals?