-
-
Notifications
You must be signed in to change notification settings - Fork 79
Open
Labels
Description
@ChrisRackauckas this is to just have an issue recording what we discussed by Slack.
When a callable tstop evaluates to include tspan[1], the SDE solver returns DtLessThanMin at t=0.0. The equivalent ODE setup handles this correctly.
The root cause is that StochasticDiffEq calls modify_dt_for_tstops! during __init (after evaluating callable tstops), which sets dt=0 when the first tstop equals the current time. OrdinaryDiffEqCore does not call modify_dt_for_tstops! at init time — it uses initialize_tstops with a strict tdir_t0 < tdir_t filter that excludes tstops at t0, avoiding this issue entirely.
MWE:
using OrdinaryDiffEqTsit5, StochasticDiffEq, SciMLBase
# Callable tstop that returns times including tspan[1]
tstops_callable = (p, tspan) -> [tspan[1], 1.0, 2.0]
# --- ODE: works fine ---
ode_f(u, p, t) = -0.1 * u
oprob = ODEProblem(ode_f, [1.0], (0.0, 3.0))
oprob = remake(oprob; kwargs = (; tstops = tstops_callable))
sol_ode = solve(oprob, Tsit5())
println("ODE: retcode = $(sol_ode.retcode)") # Success
# --- SDE with t0 in tstops: fails ---
sde_f(u, p, t) = -0.1 * u
sde_g(u, p, t) = 0.01 * u
sprob = SDEProblem(sde_f, sde_g, [1.0], (0.0, 3.0))
sprob = remake(sprob; kwargs = (; tstops = tstops_callable))
sol_sde = solve(sprob, SOSRI())
println("SDE (with t0): retcode = $(sol_sde.retcode)") # DtLessThanMin
# --- SDE without t0 in tstops: works fine ---
tstops_no_t0 = (p, tspan) -> [1.0, 2.0]
sprob2 = remake(sprob; kwargs = (; tstops = tstops_no_t0))
sol_sde2 = solve(sprob2, SOSRI())
println("SDE (without t0): retcode = $(sol_sde2.retcode)") # SuccessReactions are currently unavailable