@@ -6,9 +6,12 @@ Defines the length of a Runge-Kutta method to be the number of stages.
66Base. length (tab:: ODERKTableau ) = tab. stages
77
88"""
9- `stability_region(z,tab::ODERKTableau)`
9+ `stability_region(z, tab::ODERKTableau; embedded = false )`
1010
1111Calculates the stability function from the tableau at `z`. Stable if <1.
12+ If `embedded = true`, the stability function is calculated for the embedded
13+ method. Otherwise, the stability function is calculated for the main method
14+ (default).
1215
1316```math
1417r(z) = 1 + z bᵀ(I - zA)⁻¹ e
@@ -24,14 +27,49 @@ function stability_region(z, tab::ODERKTableau; embedded = false)
2427end
2528
2629"""
27- `stability_region(tab::ODERKTableau; initial_guess=-3.0)`
30+ stability_region(z, alg::AbstractODEAlgorithm)
31+
32+ Calculates the stability function from the algorithm `alg` at `z`.
33+ The stability region of a possible embedded method cannot be calculated
34+ using this method.
35+
36+ If you use an implicit method, you may run into convergence issues when
37+ the value of `z` is outside of the stability region, e.g.,
38+
39+ ```julia-repl
40+ julia> typemin(Float64)
41+ -Inf
42+
43+ julia> stability_region(typemin(Float64), ImplicitEuler())
44+ ┌ Warning: Newton steps could not converge and algorithm is not adaptive. Use a lower dt.
45+
46+ julia> nextfloat(typemin(Float64))
47+ -1.7976931348623157e308
48+
49+ julia> stability_region(nextfloat(typemin(Float64)), ImplicitEuler())
50+ 0.0
51+ ```
52+ """
53+ function stability_region (z, alg:: AbstractODEAlgorithm )
54+ u0 = one (z)
55+ tspan = (zero (real (z)), one (real (z)))
56+ ode = ODEProblem {false} ((u, p, t) -> z * u, u0, tspan)
57+ integrator = init (ode, alg; adaptive = false , dt = 1 )
58+ step! (integrator)
59+ return integrator. u[end ]
60+ end
61+
62+ """
63+ `stability_region(tab_or_alg::Union{ODERKTableau, AbstractODEAlgorithm};
64+ initial_guess=-3.0)`
2865
2966Calculates the length of the stability region in the real axis.
3067See also [`imaginary_stability_interval`](@ref).
3168"""
32- function stability_region (tab:: ODERKTableau ; initial_guess = - 3.0 , kw... )
69+ function stability_region (tab_or_alg:: Union{ODERKTableau, AbstractODEAlgorithm} ;
70+ initial_guess = - 3.0 , kw... )
3371 residual! = function (resid, x)
34- resid[1 ] = abs (stability_region (x[1 ], tab )) - 1
72+ resid[1 ] = abs (stability_region (x[1 ], tab_or_alg )) - 1
3573 end
3674 sol = nlsolve (residual!, [initial_guess]; kw... )
3775 sol. zero[1 ]
@@ -55,6 +93,24 @@ function imaginary_stability_interval(tab::ODERKTableau;
5593 sol. zero[1 ]
5694end
5795
96+ """
97+ imaginary_stability_interval(alg::ODERKTableau;
98+ initial_guess = 20.0)
99+
100+ Calculates the length of the imaginary stability interval, i.e.,
101+ the size of the stability region on the imaginary axis.
102+ See also [`stability_region`](@ref).
103+ """
104+ function imaginary_stability_interval (alg:: AbstractODEAlgorithm ;
105+ initial_guess = 20.0 ,
106+ kw... )
107+ residual! = function (resid, x)
108+ resid[1 ] = abs (stability_region (im * x[1 ], alg)) - 1
109+ end
110+ sol = nlsolve (residual!, [initial_guess]; kw... )
111+ sol. zero[1 ]
112+ end
113+
58114function RootedTrees. residual_order_condition (tab:: ODERKTableau , order:: Int ,
59115 reducer = nothing , mapper = x -> x^ 2 ;
60116 embedded = false )
0 commit comments