Skip to content

Commit 1763db7

Browse files
Disable J reuse for CompositeAlgorithm; lower max_jac_age to 20
CompositeAlgorithm (AutoTsit5/Rosenbrock23, AutoVern8/Rosenbrock23, etc.) already computes a fresh Jacobian every step via do_newJW because rapid stiff↔nonstiff transitions make reuse counterproductive. The reuse logic was overriding this, causing excessive step rejections that exhausted the maxiters budget on the stiffness_detection_test. Also lower default max_jac_age from 50 to 20 accepted steps for more conservative reuse that better handles problems with rapidly changing Jacobians. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5b711c4 commit 1763db7

3 files changed

Lines changed: 15 additions & 6 deletions

File tree

lib/OrdinaryDiffEqDifferentiation/src/derivative_utils.jl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ CVODE-inspired Jacobian reuse:
1717
- Always recompute on first iteration
1818
- Recompute after step rejection (EEst > 1), since the old J wasn't good enough
1919
- Recompute when gamma ratio changes too much: |dtgamma/last_dtgamma - 1| > 0.3
20-
- Recompute every `max_jac_age` accepted steps (default 50)
20+
- Recompute every `max_jac_age` accepted steps (default 20)
2121
- Recompute when u_modified (callback modification)
2222
- Otherwise reuse J but rebuild W from the cached J and current dtgamma.
2323
The Jacobian evaluation (finite-diff / AD) is the expensive part; W
2424
construction and LU factorization are comparatively cheap.
2525
2626
Returns `nothing` (delegate to `do_newJW`) for strict Rosenbrock methods,
27-
linear problems, and mass-matrix (DAE) problems where stale Jacobians
28-
cause order reduction.
27+
linear problems, mass-matrix (DAE) problems where stale Jacobians cause
28+
order reduction, and CompositeAlgorithm where rapid stiff↔nonstiff
29+
transitions make reuse counterproductive.
2930
"""
3031
function _rosenbrock_jac_reuse_decision(integrator, cache, dtgamma)
3132
alg = OrdinaryDiffEqCore.unwrap_alg(integrator, true)
@@ -55,6 +56,14 @@ function _rosenbrock_jac_reuse_decision(integrator, cache, dtgamma)
5556
return nothing
5657
end
5758

59+
# CompositeAlgorithm: delegate to do_newJW, which always recomputes J
60+
# for Rosenbrock methods in composite context (the Jacobian may be stale
61+
# from a different algorithm, and rapid stiff↔nonstiff transitions make
62+
# reuse counterproductive due to increased step rejections).
63+
if integrator.alg isa CompositeAlgorithm
64+
return nothing
65+
end
66+
5867
# First iteration: always compute J and W.
5968
if integrator.iter <= 1
6069
return (true, true)

lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_caches.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Jacobian recomputations when conditions allow it.
1212
Fields:
1313
- `last_dtgamma`: The dtgamma value from the last Jacobian computation
1414
- `steps_since_jac`: Number of accepted steps since last Jacobian update
15-
- `max_jac_age`: Maximum number of accepted steps between Jacobian updates (default 50)
15+
- `max_jac_age`: Maximum number of accepted steps between Jacobian updates (default 20)
1616
- `cached_J`: Cached Jacobian for OOP reuse (type-erased for flexibility)
1717
- `cached_dT`: Cached time derivative for OOP reuse
1818
- `cached_W`: Cached factorized W for OOP reuse (LU factorization is expensive)
@@ -32,7 +32,7 @@ mutable struct JacReuseState{T}
3232
end
3333

3434
function JacReuseState(dtgamma::T) where {T}
35-
return JacReuseState{T}(dtgamma, dtgamma, 0, 50, nothing, nothing, nothing, 0, 0)
35+
return JacReuseState{T}(dtgamma, dtgamma, 0, 20, nothing, nothing, nothing, 0, 0)
3636
end
3737

3838
# Fake values since non-FSAL

lib/OrdinaryDiffEqRosenbrock/test/jacobian_reuse_test.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ strict_rosenbrock = [
120120
@test jr.last_dtgamma == 0.0
121121
@test jr.pending_dtgamma == 0.0
122122
@test jr.last_naccept == 0
123-
@test jr.max_jac_age == 50
123+
@test jr.max_jac_age == 20
124124
@test jr.cached_J === nothing
125125
@test jr.cached_dT === nothing
126126
@test jr.cached_W === nothing

0 commit comments

Comments
 (0)