Add backward-difference stiff interpolation for BDF solvers#3046
Merged
ChrisRackauckas merged 12 commits intoSciML:masterfrom Feb 20, 2026
Merged
Add backward-difference stiff interpolation for BDF solvers#3046ChrisRackauckas merged 12 commits intoSciML:masterfrom
ChrisRackauckas merged 12 commits intoSciML:masterfrom
Conversation
Replace the default Hermite (cubic) interpolation fallback with native
Newton backward difference interpolation for BDF solvers. This uses the
formula p(Θ) = y₁ + Σ φⱼ(Θ-1) * k[j] where the backward differences
are computed from the solver's own history points, giving interpolation
accuracy consistent with the solver order rather than limited to cubic.
Follows the same pattern as the Rosenbrock stiff interpolation. Supports
both function values (Val{0}) and first derivatives (Val{1}).
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FBDF/DFBDF: Use direct Lagrange interpolation through past solution values stored in k (same polynomial as calc_Lagrange_interp). The formula avoids barycentric division singularities for ForwardDiff compatibility by using constant integer denominators (m-j). - QNDF: Keep Newton backward difference interpolation through D columns. - DFBDF calck blocks: Store solution values (uprev, u_corrector) in k instead of backward differences, matching FBDF pattern. - Add QNDF/FBDF to ode_dense_tests.jl regression_test suite with empirically verified tolerances. - BDF solvers not added to special_interps.jl because that test compares adaptive vs non-adaptive interpolation consistency, which is inapplicable to multi-step methods whose interpolation data (D matrix, u_history) depends on cumulative integration history. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Author
Update: Lagrange interpolation + Dense testsChanges in this commit:FBDF/DFBDF interpolation switched to direct Lagrange formula:
DFBDF calck blocks updated:
Dense output tests added:
BDF not added to
All existing OrdinaryDiffEqBDF tests pass. |
Redesign FBDF/DFBDF interpolation so that the dense output interpolant and the predictor/corrector use the same non-equidistant Lagrange polynomial through u_history values. All interpolation data (solution values and Θ positions) is stored in integrator.k with layout: k[1..half] = solution values, k[half+1..2*half] = Θ positions where half = max_order + 1. Key changes: - Rewrite _ode_interpolant for FBDF_CACHES to use Lagrange basis functions at non-equidistant Θ positions stored in k, ignoring y₁ - Increase kshortsize from 2*max_order to 2*(max_order+1) to hold k+1 data points needed for order-k interpolation - Update calck blocks to store u_new at Θ=1 plus u_history values - Rebuild k with u_history data at step start for predictor/corrector - Remove calc_Lagrange_interp, calc_Lagrange_interp!, and compute_weights! from bdf_utils.jl (no longer needed) - QNDF unchanged (uses backward differences, not Lagrange) All OrdinaryDiffEqBDF tests pass including DAE event handling. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rtions
Implement second and third derivative interpolation for FBDF/DFBDF
Lagrange polynomials:
- L''_i(Θ) = L_i(Θ) * (S1² - S2)
- L'''_i(Θ) = L_i(Θ) * (S1³ - 3·S1·S2 + 2·S3)
where Sk = Σ_{m≠i} 1/(Θ - θ_m)^k
Higher derivatives properly zero algebraic variables when
differential_vars is provided (mass matrix DAE problems).
Also fix Runic ternary indentation in calck blocks, and update
algebraic_interpolation.jl to expect stiffness-aware interpolation
for FBDF (no longer Hermite).
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nterpolation
The logarithmic derivative formula L'_j(Θ) = L_j(Θ) * Σ 1/(Θ-θ_m) produces
NaN at node points (0*Inf) when Θ equals any θ_m. Replace with the product-rule
form that is numerically stable at all points including nodes:
L'_j(Θ) = Σ_{m≠j} [1/(θ_j-θ_m)] * Π_{l≠j,l≠m} (Θ-θ_l)/(θ_j-θ_l)
Similarly for L''_j and L'''_j (used in Val{2} and Val{3}).
Also update get_du() (without !) to use the interpolation derivative for
stiff interpolation methods, matching the existing behavior in get_du!().
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
On Julia 1.10, [sources] in Project.toml is not supported, so the registered OrdinaryDiffEqBDF (without the new interp_func.jl) is loaded instead of the local one. The FBDF interp_summary therefore returns "3rd order Hermite" rather than our custom stiffness-aware string. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This reverts commit 0afb656.
DiffEqBase v6.204.0 (PR SciML#1273, ModAB bracketing solver) broke ForwardDiff AD through ContinuousCallbacks. The fix landed in v6.205.1. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace non-in-place _ode_interpolant() with _ode_interpolant!() using terk_tmp as a temporary buffer for the corrector loop. This eliminates allocations in perform_step! for both FBDF and DFBDF in-place caches. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies that step! with save_everystep=false produces zero allocations for both FBDF and DFBDF in-place caches after warmup. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ChrisRackauckas
approved these changes
Feb 20, 2026
Julia 1.10 reports 16 bytes of allocation in step! that don't appear on Julia 1.12. Allow this small overhead to avoid false failures on lts. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
836d78a to
9df277c
Compare
Merged
3 tasks
This was referenced Feb 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
p(Θ) = y₁ + Σ φⱼ(Θ-1) * k[j]where backward differences come from the solver's own history points, giving interpolation accuracy consistent with the solver orderVal{0}) and first derivatives (Val{1})has_stiff_interpolationtrait,_ode_interpolantdispatch)Files modified (6)
OrdinaryDiffEqBDF.jl— Added imports and includes for the 3 new filesalg_utils.jl— Addedhas_stiff_interpolationtrait for QNDF, FBDF, DFBDFbdf_caches.jl— Addeddensefield to QNDFCache and FBDFCache for aliasingintegrator.kdae_caches.jl— Addeddensefield to DFBDFCachebdf_perform_step.jl— Modifiedinitialize!(kshortsize = max_order) andperform_step!(store backward differences inintegrator.k) for QNDF and FBDFdae_perform_step.jl— Same for DFBDFFiles created (3)
interp_func.jl—SciMLBase.interp_summaryoverrides for all BDF cache typesbdf_interpolants.jl— Newton backward difference interpolation (Val{0} and Val{1})stiff_addsteps.jl— No-op_ode_addsteps!(backward diffs precomputed inperform_step!)Test plan
saveatwith interpolation works correctly🤖 Generated with Claude Code