@@ -6,9 +6,12 @@ Defines the length of a Runge-Kutta method to be the number of stages.
6
6
Base. length (tab:: ODERKTableau ) = tab. stages
7
7
8
8
"""
9
- `stability_region(z,tab::ODERKTableau)`
9
+ `stability_region(z, tab::ODERKTableau; embedded = false )`
10
10
11
11
Calculates 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).
12
15
13
16
```math
14
17
r(z) = 1 + z bᵀ(I - zA)⁻¹ e
@@ -24,14 +27,49 @@ function stability_region(z, tab::ODERKTableau; embedded = false)
24
27
end
25
28
26
29
"""
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)`
28
65
29
66
Calculates the length of the stability region in the real axis.
30
67
See also [`imaginary_stability_interval`](@ref).
31
68
"""
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... )
33
71
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
35
73
end
36
74
sol = nlsolve (residual!, [initial_guess]; kw... )
37
75
sol. zero[1 ]
@@ -55,6 +93,24 @@ function imaginary_stability_interval(tab::ODERKTableau;
55
93
sol. zero[1 ]
56
94
end
57
95
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
+
58
114
function RootedTrees. residual_order_condition (tab:: ODERKTableau , order:: Int ,
59
115
reducer = nothing , mapper = x -> x^ 2 ;
60
116
embedded = false )
0 commit comments