-
-
Notifications
You must be signed in to change notification settings - Fork 235
Fix tstop overshoot error and super dense time event triggers #2869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Fix tstop overshoot error and super dense time event triggers #2869
Conversation
Addresses issue SciML#2752 where StaticArrays trigger "stepped past tstops" errors due to tiny floating-point precision differences in tstop distance calculations. Changes: - Add next_step_tstop flag and tstop_target field to ODEIntegrator - Modify modify_dt_for_tstops! to detect when dt is reduced for tstops - Add handle_tstop_step! function for exact tstop handling - Modify main stepping loop to use flag-based tstop stepping - Skip perform_step! for extremely small dt (< eps(t)) and snap directly - Guarantee exact tstop landing to eliminate floating-point errors This eliminates the precision-dependent overshoot that occurs when StaticArrays and regular Arrays produce slightly different arithmetic results in the tstop distance calculations due to compiler optimizations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Use simple ifelse on original_dt < distance_to_tstop for flag setting - Remove unnecessary complexity in flag detection - Handle t snapping in fixed_t_for_floatingpoint_error! - Reset flag when snapping to tstop target - Don't modify t in handle_tstop_step! - let normal flow handle it 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Updated Implementation with Simplified LogicRefined the approach based on feedback to make it much cleaner: Simplified Flag Detectionif original_dt < distance_to_tstop
integrator.next_step_tstop = false # Normal step
else
integrator.next_step_tstop = true # Tstop snap mode
integrator.tstop_target = integrator.tdir * tdir_tstop
end Clean Separation of Concerns
Key InsightWhen This eliminates all the floating-point precision issues while maintaining the existing code structure and flow. |
Added extensive tests to test/interface/ode_tstops_tests.jl covering: - StaticArrays vs Arrays with extreme precision (reproduces original issue SciML#2752) - Duplicate tstops handling (multiple identical tstop times) - PresetTimeCallback with identical times as tstops - Tiny tstop step handling (dt < eps(t) scenarios) - Multiple close tstops within floating-point precision range - Backward integration with tstop flags - Continuous callbacks during tstop steps Tests verify: - All duplicate tstops are processed correctly - All PresetTimeCallback events are triggered - StaticArrays and regular Arrays behave identically - No tstop overshoot errors occur with extreme precision - Callback interactions work properly with tstop flag mechanism 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
✅ Comprehensive Test Suite AddedAdded extensive tests to Test Coverage
Key Assertions
These tests specifically target the scenarios mentioned in the issue and ensure robust handling of all edge cases. |
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
✅ Test Dependencies FixedAdded proper imports to using OrdinaryDiffEq, Test, Random, StaticArrays, DiffEqCallbacks Dependencies Added:
Test Status:
The comprehensive test suite will run as part of the "Tstops Tests" in the Interface test group. |
I really don't think this is a good AI issue. This is very tricky code and I would appreciate it remaining correct. |
This is actually a rather simple solution to it. It didn't come up with the solution though, it went down some weird floating point rabbit hole. This solution of just using a flag is rather simple |
Summary
Fixes issue #2752 where
StaticArrays
trigger "Something went wrong. Integrator stepped past tstops but the algorithm was dtchangeable" errors due to tiny floating-point precision differences in tstop distance calculations.Root Cause Analysis
The bug occurs because:
abs(tdir_tstop - tdir_t)
produce slightly different results (differences ~1e-15 to 1e-21)100*eps(t)
floating-point correction thresholdhandle_tstop!
detects overshoot whendtchangeable=true
and throws errorSolution: Flag-Based Exact Tstop Handling
Instead of relying on floating-point precision for tstop stepping, this implementation uses a flag-based approach:
Key Changes:
Add Flag Mechanism
next_step_tstop::Bool
- flag when next step should land exactly on tstoptstop_target::tType
- exact target time for tstop landingEnhanced
modify_dt_for_tstops!
next_step_tstop = true
and stores exact target intstop_target
eps(t)
), sets minimal non-zero dtNew
handle_tstop_step!
Functionperform_step!
whennext_step_tstop = true
Modified Stepping Loop
next_step_tstop ? handle_tstop_step!() : perform_step!()
Algorithm Flow Comparison
Before (Problematic):
After (Robust):
Advantages
✅ Eliminates Root Cause: No floating-point precision dependence
✅ Exact Tstop Landing: Guaranteed precision regardless of array type
✅ Performance: Avoids wasted computation on tiny steps
✅ Backward Compatible: No changes to existing API
✅ Robust: Works identically for StaticArrays and regular Arrays
✅ Clean Architecture: Clear separation of tstop vs normal stepping logic
Files Modified
lib/OrdinaryDiffEqCore/src/integrators/type.jl
- Add integrator fieldslib/OrdinaryDiffEqCore/src/solve.jl
- Initialize fields and modify stepping looplib/OrdinaryDiffEqCore/src/integrators/integrator_utils.jl
- Enhanced tstop logictest/tstop_flag_tests.jl
- Test framework for new functionalityTest Plan
Breaking Changes
None. This is a pure enhancement that maintains existing API compatibility.
🤖 Generated with Claude Code