Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
dab8efd
Rename to legacy controller
termi-official Jan 5, 2026
4dc16b6
Introduce caches and new controller types.
termi-official Jan 5, 2026
b4d0f13
Fix precompilation errors
termi-official Jan 5, 2026
2d860de
[skip ci] typo
termi-official Oct 26, 2025
50f2939
Fix some issues with recirpocals in the new implementation
termi-official Jan 5, 2026
1d55f5b
ifelse -> max
termi-official Oct 27, 2025
88bbf7d
Reverse removing reciprocals
termi-official Jan 5, 2026
0f6ebb0
Add new PIDController to los storage methods
termi-official Jan 5, 2026
884a0cd
Update BDF module
termi-official Jan 5, 2026
c32b956
Update Nordsieck methods
termi-official Jan 5, 2026
a6d62a4
Fix low storage sublib
termi-official Jan 5, 2026
eebf437
Recover behavior of Extrapolation solver in new interface
termi-official Jan 5, 2026
f601e24
Change name of legacy controllers back and add New suffix to the cont…
termi-official Jan 5, 2026
803f4bf
Update Extrapolation alg controller
termi-official Jan 15, 2026
4dab816
Add composite algorithm controller
termi-official Oct 27, 2025
4da2871
Docstrings
termi-official Oct 27, 2025
a52693e
Fix default algorithm
termi-official Jan 5, 2026
2d0d24b
Use existing variables to trick downstream packages
termi-official Jan 5, 2026
92094c5
Fix composite algorithm choice
termi-official Oct 27, 2025
18b0851
Missing dispatch
termi-official Oct 27, 2025
2054388
Fix Verner JET
termi-official Jan 5, 2026
64e3f98
Remove unused variables from PID code
termi-official Jan 5, 2026
89db4b1
Step 1: Make sure atmp is present when it should be.
termi-official Jan 5, 2026
db7f782
Remove some trailing unpacks
termi-official Jan 5, 2026
20d6d9b
Prototype for using NonlinearSolve in IDSolve as the first step towar…
termi-official Jan 5, 2026
d235636
Bump CI after DiffEqBase release
ChrisRackauckas Dec 29, 2025
2b5e7c2
Switch from JuliaFormatter to Runic.jl for code formatting
termi-official Jan 5, 2026
3fa966f
Update IDSolve to the new interface
termi-official Jan 5, 2026
37a1457
Rebase oopsie
termi-official Jan 5, 2026
99ae267
Try to fix predictive controller
termi-official Jan 5, 2026
937c909
Fix function map type.
termi-official Jan 5, 2026
ccfa756
Fix function map type attempt 2.
termi-official Jan 5, 2026
bad91ea
[skip ci] Runic.
termi-official Jan 5, 2026
bd99c5d
Roll out deduction logic for the controller data type
termi-official Jan 5, 2026
2cc5518
Runic
termi-official Jan 5, 2026
fca323a
Add dispatch for composite controllers when DummyControllers are present
termi-official Jan 5, 2026
7623f24
Missing reinit for new caches
termi-official Jan 5, 2026
051870e
Runic
termi-official Jan 5, 2026
ccc215d
Next attempt on making composite controllers work
termi-official Jan 5, 2026
f54bc08
Again an attempt on making composite controllers work
termi-official Jan 6, 2026
12538c0
Fix faulty q for zero errors in the new PI controller implementation
termi-official Jan 6, 2026
8d043fa
Runic
termi-official Jan 6, 2026
892e45f
Typo
termi-official Jan 6, 2026
5061a20
Try to improve the deduction of the contoller data types
termi-official Jan 15, 2026
df057f1
Next attempt on fixing default alg
termi-official Jan 6, 2026
2508e3b
Improve data type guess for controller
termi-official Jan 6, 2026
f49efc0
Fix faulty dispatches
termi-official Jan 6, 2026
3dd7f09
Mark predictive controller implementation legacy
termi-official Jan 6, 2026
fcd6eed
Enforce that composite algorithms use the full old data types to ensu…
termi-official Jan 6, 2026
8f92e9d
Try to ensure that the types are matching in the controller and error…
termi-official Jan 6, 2026
d549ffe
Fix EEst type
termi-official Jan 14, 2026
83e6bfd
Fix umodified_test reliance on the last integration step for both int…
termi-official Jan 14, 2026
6117464
Use oneunit for EEst determination
termi-official Jan 14, 2026
99b2246
Typo in PID
termi-official Jan 14, 2026
2660d9a
Fix tests which pick up the wrong lib version in non-lts tests
termi-official Jan 23, 2026
c6b065e
Fix FIRK differentiability
termi-official Jan 23, 2026
282e2e2
Improve non-breaking update path.
termi-official Jan 25, 2026
de26cb8
Reinit on test only on correct version
termi-official Jan 25, 2026
8eee508
Add default controller call for IDS back
termi-official Jan 25, 2026
7a4a55c
Fix IDS controller type
termi-official Jan 26, 2026
3edb2c9
Fix default controller for pre Core 3.3 fallback on Extrapolation.
termi-official Jan 26, 2026
75d4474
Fix dispatch for AitkenNeville
termi-official Jan 26, 2026
b209ee6
Bump core version
termi-official Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/ImplicitDiscreteSolve/src/ImplicitDiscreteSolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ module ImplicitDiscreteSolve
using SciMLBase
using NonlinearSolveBase
using NonlinearSolveFirstOrder
using ConcreteStructs
using SymbolicIndexingInterface: parameter_symbols
import OrdinaryDiffEqCore: OrdinaryDiffEqAlgorithm, alg_cache, OrdinaryDiffEqMutableCache,
OrdinaryDiffEqConstantCache, get_fsalfirstlast, isfsal,
initialize!, perform_step!, isdiscretecache, isdiscretealg,
alg_order, beta2_default, beta1_default, dt_required,
_initialize_dae!, DefaultInit, BrownFullBasicInit, OverrideInit,
@muladd, @.., _unwrap_val, OrdinaryDiffEqCore, isadaptive
@muladd, @.., _unwrap_val, OrdinaryDiffEqCore, isadaptive,
AbstractController

@static if Base.pkgversion(OrdinaryDiffEqCore) >= v"3.3"
@eval begin
import OrdinaryDiffEqCore: AbstractControllerCache
end
end

using Reexport
@reexport using SciMLBase
Expand Down
22 changes: 0 additions & 22 deletions lib/ImplicitDiscreteSolve/src/alg_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,3 @@ dt_required(alg::IDSolve) = false
isdiscretealg(alg::IDSolve) = true

isadaptive(alg::IDSolve) = true

# @concrete struct ConvergenceRateTracing
# inner_tracing
# end

# @concrete struct ConvergenceRateTraceTrick
# incrementL2norms
# residualL2norms
# trace_wrapper
# end

# function NonlinearSolveBase.init_nonlinearsolve_trace(
# prob, alg::IDSolve, u, fu, J, δu;
# trace_level::ConvergenceRateTracing, kwargs... # This kind of dispatch does not work. Need to figure out a different way.
# )
# inner_trace = NonlinearSolveBase.init_nonlinearsolve_trace(
# prob, alg, u, fu, J, δu;
# trace_level.inner_tracing, kwargs...
# )

# return ConvergenceRateTraceTrick(eltype(δu)[], eltype(fu)[], inner_trace)
# end
173 changes: 125 additions & 48 deletions lib/ImplicitDiscreteSolve/src/controller.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,67 +25,144 @@ The baseline algorithm has been derived in Peter Deuflhard's book "Newton Method
Nonlinear Problems" in Section 5.1.3 (Adaptive pathfollowing algorithms). Please note
that some implementation details deviate from the original algorithm.
"""
Base.@kwdef struct KantorovichTypeController <: OrdinaryDiffEqCore.AbstractController
Θmin::Float64
Base.@kwdef struct KantorovichTypeController{T} <: AbstractController
Θmin::T
p::Int64
Θreject::Float64 = 0.95
Θbar::Float64 = 0.5
γ::Float64 = 0.95
qmin::Float64 = 1 / 5
qmax::Float64 = 5.0
Θreject::T = 0.95
Θbar::T = 0.5
γ::T = 0.95
qmin::T = 1 / 5
qmax::T = 5.0
strict::Bool = true
end

function OrdinaryDiffEqCore.default_controller(
alg::IDSolve, cache::IDSolveCache, _1, _2, _3
)
return KantorovichTypeController(; Θmin = 1 // 8, p = 1)
end
@static if Base.pkgversion(OrdinaryDiffEqCore) >= v"3.3"
@eval begin
mutable struct KantorovichTypeControllerCache{T} <: AbstractControllerCache
controller::KantorovichTypeController{T}
# Proposed scaling factor for the time step length
q::T
end

function OrdinaryDiffEqCore.stepsize_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve
)
@inline g(x) = √(1 + 4x) - 1
function OrdinaryDiffEqCore.default_controller_v7(
QT, alg::IDSolve,
)
return KantorovichTypeController{QT}(; Θmin = QT(1 // 8), p = 1)
end

# Adapt dt with a priori estimate (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, γ, Θmin, qmin, qmax, p) = controller
function OrdinaryDiffEqCore.setup_controller_cache(alg, atmp, controller::KantorovichTypeController{T}) where {T}
return KantorovichTypeControllerCache(
controller,
T(1),
)
end

Θ₀ = length(Θks) > 0 ? max(first(Θks), Θmin) : Θmin
q = clamp(γ * (g(Θbar) / (g(Θ₀)))^(1 / p), qmin, qmax)
function OrdinaryDiffEqCore.stepsize_controller!(
integrator, cache::KantorovichTypeControllerCache, alg::IDSolve
)
(; controller) = cache
@inline g(x) = √(1 + 4x) - 1

return q
end
# Adapt dt with a priori estimate (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, γ, Θmin, qmin, qmax, p) = controller

function OrdinaryDiffEqCore.step_accept_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve, q
)
return q * integrator.dt
end
Θ₀ = length(Θks) > 0 ? max(first(Θks), Θmin) : Θmin
cache.q = clamp(γ * (g(Θbar) / (g(Θ₀)))^(1 / p), qmin, qmax)

return cache.q
end

function OrdinaryDiffEqCore.step_accept_controller!(
integrator, cache::KantorovichTypeControllerCache, alg::IDSolve, q
)
@assert q ≈ cache.q "Controller cache went out of sync with time stepping logic."
return cache.q * integrator.dt
end

function OrdinaryDiffEqCore.step_reject_controller!(
integrator, cache::KantorovichTypeControllerCache, alg::IDSolve
)
(; controller) = cache
@inline g(x) = √(1 + 4x) - 1

function OrdinaryDiffEqCore.step_reject_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve
)
@inline g(x) = √(1 + 4x) - 1

# Shorten dt according to (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, Θreject, γ, Θmin, qmin, qmax, p) = controller
for Θk in Θks
if Θk > Θreject
q = clamp(γ * (g(Θbar) / g(Θk))^(1 / p), qmin, qmax)
integrator.dt = q * integrator.dt
# Shorten dt according to (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, Θreject, γ, Θmin, qmin, qmax, p) = controller
for Θk in Θks
if Θk > Θreject
q = clamp(γ * (g(Θbar) / g(Θk))^(1 / p), qmin, qmax)
integrator.dt = q * integrator.dt
return
end
end
return
end

function OrdinaryDiffEqCore.accept_step_controller(integrator, cache::KantorovichTypeControllerCache)
(; controller) = cache
(; Θks) = integrator.cache
if controller.strict
return all(controller.Θreject .< Θks)
else
return true
end
end
end
return
end
else
@eval begin
function OrdinaryDiffEqCore.default_controller(
alg::IDSolve, cache::IDSolveCache, _1, _2, _3
)
return KantorovichTypeController(; Θmin = float(1 // 8), p = 1)
end

function OrdinaryDiffEqCore.stepsize_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve
)
@inline g(x) = √(1 + 4x) - 1

# Adapt dt with a priori estimate (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, γ, Θmin, qmin, qmax, p) = controller

Θ₀ = length(Θks) > 0 ? max(first(Θks), Θmin) : Θmin
q = clamp(γ * (g(Θbar) / (g(Θ₀)))^(1 / p), qmin, qmax)

function OrdinaryDiffEqCore.accept_step_controller(integrator, controller::KantorovichTypeController)
(; Θks) = integrator.cache
if controller.strict
return all(controller.Θreject .< Θks)
else
return true
return q
end

function OrdinaryDiffEqCore.step_accept_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve, q
)
return q * integrator.dt
end

function OrdinaryDiffEqCore.step_reject_controller!(
integrator, controller::KantorovichTypeController, alg::IDSolve
)
@inline g(x) = √(1 + 4x) - 1

# Shorten dt according to (Eq. 5.24)
(; Θks) = integrator.cache
(; Θbar, Θreject, γ, Θmin, qmin, qmax, p) = controller
for Θk in Θks
if Θk > Θreject
q = clamp(γ * (g(Θbar) / g(Θk))^(1 / p), qmin, qmax)
integrator.dt = q * integrator.dt
return
end
end
return
end

function OrdinaryDiffEqCore.accept_step_controller(integrator, controller::KantorovichTypeController)
(; Θks) = integrator.cache
if controller.strict
return all(controller.Θreject .< Θks)
else
return true
end
end
end
end
3 changes: 2 additions & 1 deletion lib/OrdinaryDiffEqBDF/src/OrdinaryDiffEqBDF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!,
trivial_limiter!,
issplit, qsteady_min_default, qsteady_max_default,
get_current_alg_order, get_current_adaptive_order,
default_controller, stepsize_controller!,
default_controller_v7,
legacy_default_controller, stepsize_controller!,
step_accept_controller!,
step_reject_controller!, post_newton_controller!,
u_modified!, DAEAlgorithm, _unwrap_val, DummyController,
Expand Down
58 changes: 44 additions & 14 deletions lib/OrdinaryDiffEqBDF/src/controllers.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
function default_controller(alg::Union{QNDF, FBDF}, args...)
function legacy_default_controller(alg::Union{QNDF, FBDF}, args...)
return DummyController()
end

function default_controller_v7(QT, alg::Union{QNDF, FBDF}, args...)
return DummyController()
end

Expand All @@ -9,7 +13,11 @@ stepsize_controller!(integrator, alg::QNDF) = nothing
# Implementation of an Adaptive BDF2 Formula and Comparison with the MATLAB Ode15s paper
# E. Alberdi Celaya, J. J. Anza Aguirrezabala, and P. Chatzipantelidis

function step_accept_controller!(integrator, alg::QNDF{max_order}, q) where {max_order}
function step_accept_controller!(integrator, alg::QNDF, q)
return step_accept_controller!(integrator, integrator.cache, alg, q)
end

function step_accept_controller!(integrator, cache::Union{QNDFCache, QNDFConstantCache}, alg::QNDF{max_order}, q) where {max_order}
#step is accepted, reset count of consecutive failed steps
integrator.cache.consfailcnt = 0
integrator.cache.nconsteps += 1
Expand Down Expand Up @@ -250,15 +258,22 @@ end

function stepsize_controller!(
integrator,
alg::FBDF
)
return stepsize_controller!(integrator, integrator.cache, alg)
end

function stepsize_controller!(
integrator,
cache::Union{FBDFCache, FBDFConstantCache},
alg::FBDF{max_order}
) where {
max_order,
}
(; cache) = integrator
cache.prev_order = cache.order
k, terk = choose_order!(alg, integrator, cache, Val(max_order))
if k != cache.order
integrator.cache.nconsteps = 0
cache.nconsteps = 0
cache.order = k
end
if iszero(terk)
Expand All @@ -270,16 +285,20 @@ function stepsize_controller!(
return q
end

function step_accept_controller!(integrator, alg::FBDF, q)
return step_accept_controller!(integrator, integrator.cache, alg, q)
end

function step_accept_controller!(
integrator, alg::FBDF{max_order},
integrator, cache::Union{FBDFCache, FBDFConstantCache}, alg::FBDF{max_order},
q
) where {max_order}
integrator.cache.consfailcnt = 0
cache.consfailcnt = 0
if q <= integrator.opts.qsteady_max && q >= integrator.opts.qsteady_min
q = one(q)
end
integrator.cache.nconsteps += 1
integrator.cache.iters_from_event += 1
cache.nconsteps += 1
cache.iters_from_event += 1
return integrator.dt / q
end

Expand Down Expand Up @@ -396,15 +415,22 @@ end

function stepsize_controller!(
integrator,
alg::DFBDF
)
return stepsize_controller!(integrator, integrator.cache, alg)
end

function stepsize_controller!(
integrator,
cache::Union{DFBDFCache, DFBDFConstantCache},
alg::DFBDF{max_order}
) where {
max_order,
}
(; cache) = integrator
cache.prev_order = cache.order
k, terk = choose_order!(alg, integrator, cache, Val(max_order))
if k != cache.order
integrator.cache.nconsteps = 0
cache.nconsteps = 0
cache.order = k
end
if iszero(terk)
Expand All @@ -416,15 +442,19 @@ function stepsize_controller!(
return q
end

function step_accept_controller!(integrator, alg::DFBDF, q)
return step_accept_controller!(integrator, integrator.cache, alg, q)
end

function step_accept_controller!(
integrator, alg::DFBDF{max_order},
integrator, cache::Union{DFBDFCache, DFBDFConstantCache}, alg::DFBDF{max_order},
q
) where {max_order}
integrator.cache.consfailcnt = 0
cache.consfailcnt = 0
if q <= integrator.opts.qsteady_max && q >= integrator.opts.qsteady_min
q = one(q)
end
integrator.cache.nconsteps += 1
integrator.cache.iters_from_event += 1
cache.nconsteps += 1
cache.iters_from_event += 1
return integrator.dt / q
end
2 changes: 1 addition & 1 deletion lib/OrdinaryDiffEqCore/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "OrdinaryDiffEqCore"
uuid = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
authors = ["ParamThakkar123 <[email protected]>"]
version = "3.2.0"
version = "3.3.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChrisRackauckas Just that this does not go unnoticed, I need to bump the version to make the CI work. See below for more details.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's kind of funky and doesn't seem to work so well... instead just make an OrdinaryDiffEqCore v4?


[deps]
SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
Expand Down
Loading
Loading