Fix GPUVern7 adaptive continuous callback interpolation issue#413
Merged
ChrisRackauckas merged 2 commits intoSciML:masterfrom Feb 23, 2026
Merged
Conversation
The Vern7 dense output interpolant polynomial deviates from the RK step solution at Θ ≈ 1 in Float32 arithmetic (error ~0.006 for dt ≈ 3). This creates an inconsistency between event detection (uses RK solution at the step endpoint) and root finding (uses the interpolant at interior points), causing poor root-finding accuracy when callbacks fire near the step endpoint. Add a residual-based fallback in find_callback_time: when the root finder converges to a point with larger residual than the endpoint condition, snap to the step endpoint so _change_t_via_interpolation! uses integrator.u directly. This fixes the adaptive GPUVern7 continuous callback error from ~0.005 to ~0.003 (below the 5e-3 test threshold), resolving issue SciML#412. However, the fix exposes a latent bug in CallbackSet handling: the nudge mechanism in handle_callbacks! only prevents re-detection for the callback matching event_last_time, so duplicate ContinuousCallbacks in a CallbackSet can re-detect events. Mark those tests as @test_broken. Closes SciML#412 Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Rewrite the Vern7 dense output interpolant from the original form u(Θ) = y₀ + dt * Σ bᵢ(Θ)*kᵢ to the (1-Θ)-factored form u(Θ) = y₀ + Θ*step_sum + Θ*(Θ-1)*dt * Σ qᵢ(Θ)*kᵢ where step_sum is recomputed from tableau step weights and the qᵢ are tail-sum polynomials obtained by synthetic division of (bᵢ/Θ - wᵢ) by (Θ-1). This guarantees exact floating-point endpoints: at Θ=0 the Θ factor gives zero, at Θ=1 the (Θ-1) factor kills the correction. The step_sum is reconstructed from the tableau weights (b1*k1 + b4*k4 + ... + b9*k9) rather than reading integ.u, avoiding state-dependency issues during callback handling. This proper fix eliminates the need for the residual-snap workaround in find_callback_time (removed). Test improvements: 4 previously broken GPUVern7 continuous callback tests now pass (15 pass, 1 broken vs 11 pass, 5 broken). Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Author
Update: Restructured Vern7 interpolant with (1-Θ) factorsPer the feedback about using to: where:
Key insightThe step advancement Results
|
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
find_callback_time: when root finder converges poorly (residual > endpoint condition), snap to step endpointCallbackSet(cb, cb)tests as@test_broken— the fix exposes a latent bug where the nudge mechanism only prevents re-detection for one callback in duplicate CallbackSetsDetails
The
get_conditionfunction usesintegrator.u(the RK step solution) when evaluating at exactlyintegrator.t, but uses the dense output interpolant at interior points. For Vern7 in Float32, the high-degree polynomial evaluation accumulates significant rounding error near Θ = 1. This means:The fix detects this case (residual larger than endpoint condition) and falls back to the step endpoint, where
_change_t_via_interpolation!uses the accurate RK solution directly.Test plan
Closes #412
🤖 Generated with Claude Code