Open goretkin opened 5 years ago
I see, I think this is because the first callback is called not via the tstop
mechanism, but in a special-purpose way?
I was trying to see a way to have only one place where the callback is called, which would involve having a tstop at t_span[1]
(e.g. 0), but this skips the call to loopfooter!
, where the callbacks are handled.
This kind of fixes the issue for me, except now the initial condition is repeated twice in the solution.
diff --git a/DiffEqCallbacks/src/iterative_and_periodic.jl b/DiffEqCallbacks/src/iterative_and_periodic.jl
index 4a3ada5..b547276 100644
--- a/src/iterative_and_periodic.jl
+++ b/src/iterative_and_periodic.jl
@@ -84,7 +84,7 @@ function PeriodicCallback(f, Δt::Number; initialize = DiffEqBase.INITIALIZE_DEF
initialize(c, u, t, integrator)
if initial_affect
tnext[] = t
- affect!(integrator)
+ add_tstop!(integrator, tnext[])
else
tnext[] = t + Δt
add_tstop!(integrator, tnext[])
diff --git a/src/solve.jl b/src/solve.jl
index 84565cba..5f54695b 100644
--- a/src/solve.jl
+++ b/src/solve.jl
@@ -364,6 +364,7 @@ end
function DiffEqBase.solve!(integrator::ODEIntegrator)
@inbounds while !isempty(integrator.opts.tstops)
+ steps_performed_until_tstop = 0
while integrator.tdir * integrator.t < top(integrator.opts.tstops)
loopheader!(integrator)
if check_error!(integrator) != :Success
@@ -374,8 +375,12 @@ function DiffEqBase.solve!(integrator::ODEIntegrator)
if isempty(integrator.opts.tstops)
break
end
+ steps_performed_until_tstop += 1
end
handle_tstop!(integrator)
+ if steps_performed_until_tstop == 0
+ handle_callbacks!(integrator) # TODO really only need to handle discrete
+ end
end
postamble!(integrator)
The solve!
change shouldn't be needed. Initialization isn't the same as calling the callback. Initialization of many callbacks is very different than the affect!
. PeriodicCallback
should just call the affect at the start.
What's the issue here?
Right, so PeriodicCallback
does appear to call affect!
at tspan[1]
, and I was expecting the solution to have the values immediately before (the initial condition) and immediately after the callback.
But that doesn't appear to be the case.
To highlight what was buried in my initial message:
solution.t[2] = 0.0009999000099990003
where I expected solution.t[2] = 0.0
Interesting. Thanks, I'll have to look into it. I have an awfully crazy month coming up, so feel free to ping me sometime early November to remind me about this.
I incidentally stumbled upon this or very similar issue, or it's just my poor understanding of callbacks. I'm using a PresetTimeCallback
to modify the solution at times including t=0
. I noticed that at this particular time point the callback is definitely called, but it has no effect on the integrator, unless I include u_modified!(integrator, true)
in the function. At all the other times, the callback works as expected without this line. Is this intended behaviour? After all, I can apply my modification to u0
before calling the solver, but I thought it would be more consistent this way.
unless I include u_modified!(integrator, true) in the function. At all the other times, the callback works as expected without this line. Is this intended behaviour?
That's not intended, and it points exactly to what the bug probably is. Thanks!
I expected the first two steps in the solution to be immediately before and immediately after the first callback event, but it seems like the callback event after is not saved.
They are saved for subsequent events, however. Is this the intended behavior?
The callback is definitely called at
t_span[1]
, from what I can tell.output: