Repository navigation
Use a stiffness-switching default solver in lsim and check the solver return code - #1082
Merged
Merged
Conversation
… return code The ODE-based lsim for rational continuous-time systems with a function input now uses AutoTsit5(Rosenbrock23()) by default instead of Tsit5(), so that stiff systems are simulated without reaching maxiters. All ODE-based simulation methods (rational, DelayLtiSystem and HammersteinWienerSystem) now check the return code of the solver and throw an error that states the return code, instead of a BoundsError from a solution with fewer time points than requested. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HigNnun4aJKMoWmY7wyULn
|
This is an automated message.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1082 +/- ##
==========================================
+ Coverage 91.73% 91.75% +0.02%
==========================================
Files 42 42
Lines 5865 5871 +6
==========================================
+ Hits 5380 5387 +7
+ Misses 485 484 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
baggepinnen
referenced
this pull request
Oct 13, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HigNnun4aJKMoWmY7wyULn
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.










Part of #1081
Problem
The ODE-based
lsim(sys, u::Function, t)for rational continuous-time systems used the explicit solverTsit5()by default and did not check the return code of the solver. For a stiff system, the solver reachesmaxitersand the method then fails with aBoundsError, because the solution contains fewer time points than requested:The same
BoundsErroroccurs for the diagonal realizationss(diagm([-1.0, -1e6]), [1.0; 1e6;;], [1.0 1.0], 0). The simulation methods forDelayLtiSystemandHammersteinWienerSystemdid not check the return code either, and failed with aBoundsErrorwhen the solver terminated early, e.g.,lsim(delay(1)*tf(1, [1, 1]), (x, t) -> [1.0], 0:0.1:10; maxiters=5)gaveBoundsError: attempt to access 2-element Vector{Tuple{...}} at index [3].Change
AutoTsit5(Rosenbrock23()). It integrates withTsit5and switches toRosenbrock23when stiffness is detected. Both are available from the existing dependencyOrdinaryDiffEq(v6 and v7), so no dependency is added. The keyword argumentalgis retained.check_retcode(sol)throws an error whenSciMLBase.successful_retcode(sol)is false. The error states the time at which the simulation terminated and the return code, and suggests selecting another solver withalgor adjustingabstol,reltolandmaxiters. It is called after the solver in the rational,DelayLtiSystemandHammersteinWienerSystemmethods. The solvers and tolerance defaults of the delay and Hammerstein-Wiener methods are unchanged.lsimdocstring (in ControlSystemsBase) states the default solver and the requirement below.After the change, the reproducer above gives
y[end] = 9.9995478e-7(exact value1e-6*(1 - e^{-10}) ≈ 9.99954600e-7) in 0.2 ms, and an unsuccessful simulation givesEffect on existing users
AutoTsit5uses the sameTsit5steps as long as no stiffness is detected. Forss(tf([1, 2], [1, 0.5, 2, 1]))with inputsin(t)on0:0.01:20, the result is identical toalg = Tsit5()(maximum difference 0.0); the run time is 4.4 ms compared to 3.2 ms withTsit5().Rosenbrock23, give slightly different results within the solver tolerances. Note that with the defaultdtmax = t[2]-t[1], the switch already occurs for a fast pole in -100 anddt = 0.1. In the tested examples the results are closer to the exact solution than before: for a system of state dimension 6 with a step input and nonzerox0, the maximum error with respect to the exact zero-order-hold solution is 3.1e-4 (previously 4.9e-4); for the pole pair -1, -1e3 the error ofy[end]is 1.4e-10 (previously 2.0e-9).Rosenbrock23computes the Jacobian and the time derivative by forward-mode automatic differentiation, so after a switchuis evaluated with arguments of a ForwardDiff dual-number type. Input functions that do not support this, e.g.,(x, t) -> (buf .= -L*x)with a preallocatedFloat64buffer, now throw aMethodErrorfor problems that are detected as stiff (for a fast pole in -100 anddt = 0.1, such a function worked withTsit5). The docstring states this and recommendsalg = Tsit5()in that case. A finite-difference Jacobian (Rosenbrock23(autodiff = AutoFiniteDiff())) would avoid this, but theautodiffkeyword accepts an ADTypes specifier only in recent OrdinaryDiffEq versions (v7 rejectsautodiff = false), so this would require ADTypes as a direct dependency and a higher lower compat bound of OrdinaryDiffEq; finite differences of the time derivative are in addition inaccurate at discontinuities ofusuch as steps.ErrorExceptionthat states the return code instead of aBoundsError.Tests
test/test_timeresp.jl: regression test withss(tf(1, [1, 1e6+1, 1e6])), compared to the exact zero-order-hold simulation (rtol=1e-3), and a test thatalg = Tsit5()withmaxiters = 100throws an error that contains "return code".test/test_delay_timeresp.jl,test/test_nonlinear_timeresp.jl: tests that the delay and Hammerstein-Wiener methods throw an error that contains "return code" whenmaxitersis reached (verified to give aBoundsErrorwithout the check).test/runtests_controlsystems.jl(test_timeresp.jl, test_delay_timeresp.jl, test_nonlinear_timeresp.jl) with OrdinaryDiffEq v7.8.1 and DelayDiffEq v6.4.2 on Julia 1.12:ControlSystems | 1156 passed, 1156 total.Host:
demeter6, Claude Code sessionsession_01HigNnun4aJKMoWmY7wyULn, working directory~/.julia/dev/ControlSystems/.claude/worktrees/agent-afc211630c7f3d2d2🤖 Generated with Claude Code
https://claude.ai/code/session_01HigNnun4aJKMoWmY7wyULn