Skip to content

Commit 522b6fa

Browse files
committed
add tolerances
1 parent 9c45cd2 commit 522b6fa

File tree

2 files changed

+40
-17
lines changed

2 files changed

+40
-17
lines changed

docs/src/steady_state_functionality/steady_state_stability_computation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
After system steady states have been found using [HomotopyContinuation.jl](@ref homotopy_continuation), [NonlinearSolve.jl](@ref nonlinear_solve), or other means, their stability can be computed using Catalyst's `steady_state_stability` function. Systems with conservation laws will automatically have these removed, permitting stability computation on systems with singular Jacobian.
33

44
!!! warn
5-
Catalyst currently computes steady state stabilities using the naive approach of checking whether a system's largest eigenvalue is negative. While more advanced stability computation methods exist (and would be a welcome addition to Catalyst), there is no direct plans to implement these.
5+
Catalyst currently computes steady state stabilities using the naive approach of checking whether a system's largest eigenvalue real part is negative. While more advanced stability computation methods exist (and would be a welcome addition to Catalyst), there is no direct plans to implement these. Furthermore, Catalyst uses a arbitrary tolerance $tol ~ 1.5*10^-7$ to determine whether a computed eigenvalue is far away enough from 0 to be reliably used. This selected threshold, however, have not been subject to further analysis (and can be changed through the `tol` argument).
66

77
## Basic examples
88
Let us consider the following basic example:

src/steady_state_stability.jl

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
### Stability Analysis ###
22

33
"""
4-
stability(u::Vector{T}, rs::ReactionSystem, p; sparse = false,
5-
ss_jac = steady_state_jac(u, rs, p; sparse=sparse))
4+
stability(u::Vector{T}, rs::ReactionSystem, p; tol = 10*sqrt(eps())
5+
sparse = false, ss_jac = steady_state_jac(u, rs, p; sparse=sparse))
66
77
Compute the stability of a steady state (Returned as a `Bool`, with `true` indicating stability).
88
99
Arguments:
10-
- `u`: The steady state for which we want to compute stability.
11-
- `rs`: The `ReactionSystem` model for which we want to compute stability.
12-
- `p`: The parameter set for which we want to compute stability.
13-
- `sparse = false`: If we wish to create a sparse Jacobian for the stability computation.
14-
- `ss_jac = steady_state_jac(u, rs; sparse = sparse)`: It is possible to pre-compute the
15-
Jacobian used for stability computation using `steady_state_jac`. If stability is computed
16-
for many states, precomputing the Jacobian may speed up evaluation.
10+
- `u`: The steady state for which we want to compute stability.
11+
- `rs`: The `ReactionSystem` model for which we want to compute stability.
12+
- `p`: The parameter set for which we want to compute stability.
13+
- `tol = 10*sqrt(eps())`: The tolerance used for determining whether computed eigenvalues real
14+
parts can reliably be considered negative/positive. In practise, a steady state is considered
15+
stable if the corresponding Jacobian's maximum eigenvalue real part is < 0. However, if this maximum
16+
eigenvalue is in the range `-tol< eig < tol`, and error is throw, as we do not deem that stability
17+
can be ensured with enough certainty. The choice `tol = 10*sqrt(eps())` has *not* been subject
18+
to much analysis.
19+
- `sparse = false`: If we wish to create a sparse Jacobian for the stability computation.
20+
- `ss_jac = steady_state_jac(u, rs; sparse = sparse)`: It is possible to pre-compute the
21+
Jacobian used for stability computation using `steady_state_jac`. If stability is computed
22+
for many states, precomputing the Jacobian may speed up evaluation.
1723
1824
Example:
1925
```julia
@@ -28,14 +34,20 @@ steady_state = [2.0]
2834
steady_state_stability(steady_state, rn, p)
2935
3036
Notes:
31-
- The input `u` can (currently) be both a vector of values (like `[1.0, 2.0]`) and a vector map
32-
(like `[X => 1.0, Y => 2.0]`). The reason is that most methods for computing stability only
33-
produces vectors of values. However, if possible, it is recommended to work with values on the
34-
form of maps.
37+
- The input `u` can (currently) be both a vector of values (like `[1.0, 2.0]`) and a vector map
38+
(like `[X => 1.0, Y => 2.0]`). The reason is that most methods for computing stability only
39+
produces vectors of values. However, if possible, it is recommended to work with values on the
40+
form of maps.
41+
- Catalyst currently computes steady state stabilities using the naive approach of checking whether
42+
a system's largest eigenvalue real part is negative. While more advanced stability computation
43+
methods exist (and would be a welcome addition to Catalyst), there is no direct plans to implement
44+
these. Furthermore, Catalyst uses a arbitrary tolerance tol ~ 1.5*10^-7 to determine whether a
45+
computed eigenvalue is far away enough from 0 to be reliably used. This selected threshold,
46+
however, have not been subject to further analysis (and can be changed through the `tol` argument).
3547
```
3648
"""
37-
function steady_state_stability(u::Vector, rs::ReactionSystem, ps; sparse = false,
38-
ss_jac = steady_state_jac(rs; u0 = u, sparse = sparse))
49+
function steady_state_stability(u::Vector, rs::ReactionSystem, ps; tol = 10*sqrt(eps(ss_val_type(u))),
50+
sparse = false, ss_jac = steady_state_jac(rs; u0 = u, sparse = sparse))
3951
# Warning checks.
4052
if !is_autonomous(rs)
4153
error("Attempting to compute stability for a non-autonomous system (e.g. where some rate depend on $(rs.iv)). This is not possible.")
@@ -53,9 +65,20 @@ function steady_state_stability(u::Vector, rs::ReactionSystem, ps; sparse = fals
5365
J = zeros(length(u), length(u))
5466
ss_jac = remake(ss_jac; u0 = u, p = ps)
5567
ss_jac.f.jac(J, ss_jac.u0, ss_jac.p, Inf)
56-
return maximum(real(ev) for ev in (eigvals(J))) < 0
68+
max_eig = maximum(real(ev) for ev in (eigvals(J)))
69+
if abs(max_eig) < tol
70+
error("The system Jacobian's maximum eigenvalue at the steady state is within the tolerance range (abs($max_eig) < $tol). Hence, stability could not be reliably determined. If you still wish to compute the stability, reduce the `tol` argument.")
71+
end
72+
return max_eig < 0
5773
end
5874

75+
# Used to determine the type of the steady states values, which is then used to set the tolerance's
76+
# type.
77+
ss_val_type(u::Vector{T}) where {T} = T
78+
ss_val_type(u::Vector{Pair{S,T}}) where {S,T} = T
79+
ss_val_type(u::Dict{S,T}) where {S,T} = T
80+
81+
5982
"""
6083
steady_state_jac(rs::ReactionSystem; u0 = [], sparse = false)
6184

0 commit comments

Comments
 (0)