• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SciML / Catalyst.jl / 11168007292

03 Oct 2024 06:57PM UTC coverage: 91.23% (-1.3%) from 92.527%
11168007292

push

github

web-flow
Merge pull request #1070 from SciML/fix_tests

Fix broken tests

3589 of 3934 relevant lines covered (91.23%)

172220.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/ext/CatalystStructuralIdentifiabilityExtension/structural_identifiability_extension.jl
1
### Structural Identifiability ODE Creation ###
2

3
# For a reaction system, list of measured quantities and known parameters, generate a StructuralIdentifiability compatible ODE.
4
"""
5
make_si_ode(rs::ReactionSystem; measured_quantities=observed(rs), known_p = [], ignore_no_measured_warn=false)
6

7
Creates a reaction rate equation ODE system of the form used within the StructuralIdentifiability.jl package. The output system is compatible with all StructuralIdentifiability functions.
8

9
Arguments:
10
- `rs::ReactionSystem`; The reaction system we wish to convert to an ODE.
11
- `measured_quantities=[]`: The quantities of the system we can measure. May either be equations (e.g. `x1 + x2`), or single species (e.g. the symbolic `x`, `rs.x`, or the symbol `:x`).
12
- `known_p = []`: List of parameters for which their values are assumed to be known.
13
- `ignore_no_measured_warn = false`: If set to `true`, no warning is provided when the `measured_quantities` vector is empty.
14
- `remove_conserved = true`: Whether to eliminate conservation laws when computing the ode (this can reduce runtime of identifiability analysis significantly).
15

16
Example:
17
```julia
18
using Catalyst, StructuralIdentifiability
19
rs = @reaction_network begin
20
    (p,d), 0 <--> X
21
end
22
make_si_ode(rs; measured_quantities = [:X], known_p = [:p])
23
```
24

25
Notes:
26
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
27
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
28
"""
29
function Catalyst.make_si_ode(rs::ReactionSystem; measured_quantities = [], known_p = [],
×
30
        ignore_no_measured_warn = false, remove_conserved = true)
31
    # Creates a MTK ODESystem, and a list of measured quantities (there are equations).
32
    # Gives these to SI to create an SI ode model of its preferred form.
33
    osys, conseqs, _, _ = make_osys(rs; remove_conserved)
×
34
    measured_quantities = make_measured_quantities(rs, measured_quantities, known_p,
×
35
        conseqs; ignore_no_measured_warn)
36
    return SI.mtk_to_si(osys, measured_quantities)[1]
×
37
end
38

39
### Structural Identifiability Wrappers ###
40

41
"""
42
assess_local_identifiability(rs::ReactionSystem, args...; measured_quantities = [], known_p = [], remove_conserved = true, ignore_no_measured_warn=false, kwargs...)
43

44
Applies StructuralIdentifiability.jl's `assess_local_identifiability` function to the reaction rate equation ODE model for the given Catalyst `ReactionSystem`. Automatically converts the `ReactionSystem` to an appropriate `ODESystem` and computes structural identifiability,
45

46
Arguments:
47
- `rs::ReactionSystem`; The reaction system for which we wish to compute structural identifiability of the associated reaction rate equation ODE model.
48
- `measured_quantities=[]`: The quantities of the system we can measure. May either be equations (e.g. `x1 + x2`), or single species (e.g. the symbolic `x`, `rs.s`, or the symbol `:x`).
49
- `known_p = []`: List of parameters which values are known.
50
- `ignore_no_measured_warn = false`: If set to `true`, no warning is provided when the `measured_quantities` vector is empty.
51
- `remove_conserved = true`: Whether to eliminate conservation laws when computing the ode (this can reduce runtime of identifiability analysis significantly).
52

53
Example:
54
```julia
55
using Catalyst, StructuralIdentifiability
56
rs = @reaction_network begin
57
    (p,d), 0 <--> X
58
end
59
assess_local_identifiability(rs; measured_quantities = [:X], known_p = [:p])
60
```
61

62
Notes:
63
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
64
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
65
"""
66
function SI.assess_local_identifiability(rs::ReactionSystem, args...;
×
67
        measured_quantities = [], known_p = [], funcs_to_check = Vector(),
68
        remove_conserved = true, ignore_no_measured_warn = false, kwargs...)
69
    # Creates a ODESystem, list of measured quantities, and functions to check, of SI's preferred form.
70
    osys, conseqs, consconsts, vars = make_osys(rs; remove_conserved)
×
71
    measured_quantities = make_measured_quantities(rs, measured_quantities, known_p,
×
72
        conseqs; ignore_no_measured_warn)
73
    funcs_to_check = make_ftc(funcs_to_check, conseqs, vars)
×
74

75
    # Computes identifiability and converts it to a easy to read form.
76
    out = SI.assess_local_identifiability(osys, args...; measured_quantities,
×
77
        funcs_to_check, kwargs...)
78
    return make_output(out, funcs_to_check, consconsts)
×
79
end
80

81
"""
82
assess_identifiability(rs::ReactionSystem, args...; measured_quantities = [], known_p = [], remove_conserved = true, ignore_no_measured_warn=false, kwargs...)
83

84
Applies StructuralIdentifiability.jl's `assess_identifiability` function to a Catalyst `ReactionSystem`. Internally it is converted ot a `ODESystem`, for which structural identifiability is computed.
85

86
Arguments:
87
- `rs::ReactionSystem`; The reaction system we wish to compute structural identifiability for.
88
- `measured_quantities=[]`: The quantities of the system we can measure. May either be equations (e.g. `x1 + x2`), or single species (e.g. the symbolic `x`, `rs.s`, or the symbol `:x`).
89
- `known_p = []`: List of parameters which values are known.
90
- `ignore_no_measured_warn = false`: If set to `true`, no warning is provided when the `measured_quantities` vector is empty.
91
- `remove_conserved = true`: Whether to eliminate conservation laws when computing the ode (this can reduce runtime of identifiability analysis significantly).
92

93
Example:
94
```julia
95
using Catalyst, StructuralIdentifiability
96
rs = @reaction_network begin
97
    (p,d), 0 <--> X
98
end
99
assess_identifiability(rs; measured_quantities = [:X], known_p = [:p])
100
```
101

102
Notes:
103
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
104
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
105
"""
106
function SI.assess_identifiability(rs::ReactionSystem, args...;
×
107
        measured_quantities = [], known_p = [], funcs_to_check = Vector(),
108
        remove_conserved = true, ignore_no_measured_warn = false, kwargs...)
109
    # Creates a ODESystem, list of measured quantities, and functions to check, of SI's preferred form.
110
    osys, conseqs, consconsts, vars = make_osys(rs; remove_conserved)
×
111
    measured_quantities = make_measured_quantities(rs, measured_quantities, known_p,
×
112
        conseqs; ignore_no_measured_warn)
113
    funcs_to_check = make_ftc(funcs_to_check, conseqs, vars)
×
114

115
    # Computes identifiability and converts it to a easy to read form.
116
    out = SI.assess_identifiability(osys, args...; measured_quantities,
×
117
        funcs_to_check, kwargs...)
118
    return make_output(out, funcs_to_check, consconsts)
×
119
end
120

121
"""
122
find_identifiable_functions(rs::ReactionSystem, args...; measured_quantities = [], known_p = [], remove_conserved = true, ignore_no_measured_warn=false, kwargs...)
123

124
Applies StructuralIdentifiability.jl's `find_identifiable_functions` function to a Catalyst `ReactionSystem`. Internally it is converted ot a `ODESystem`, for which structurally identifiable functions are computed.
125

126
Arguments:
127
- `rs::ReactionSystem`; The reaction system we wish to compute structural identifiability for.
128
- `measured_quantities=[]`: The quantities of the system we can measure. May either be equations (e.g. `x1 + x2`), or single species (e.g. the symbolic `x`, `rs.s`, or the symbol `:x`).
129
- `known_p = []`: List of parameters which values are known.
130
- `ignore_no_measured_warn = false`: If set to `true`, no warning is provided when the `measured_quantities` vector is empty.
131
- `remove_conserved = true`: Whether to eliminate conservation laws when computing the ode (this can reduce runtime of identifiability analysis significantly).
132

133
Example:
134
```julia
135
using Catalyst, StructuralIdentifiability
136
rs = @reaction_network begin
137
    (p,d), 0 <--> X
138
end
139
find_identifiable_functions(rs; measured_quantities = [:X], known_p = [:p])
140
```
141

142
Notes:
143
- This function is part of the StructuralIdentifiability.jl extension. StructuralIdentifiability.jl must be imported to access it.
144
- `measured_quantities` and `known_p` input may also be symbolic (e.g. measured_quantities = [rs.X])
145
"""
146
function SI.find_identifiable_functions(rs::ReactionSystem, args...;
×
147
        measured_quantities = [], known_p = [], remove_conserved = true,
148
        ignore_no_measured_warn = false, kwargs...)
149
    # Creates a ODESystem, and list of measured quantities, of SI's preferred form.
150
    osys, conseqs, consconsts, _ = make_osys(rs; remove_conserved)
×
151
    measured_quantities = make_measured_quantities(rs, measured_quantities, known_p,
×
152
        conseqs; ignore_no_measured_warn)
153

154
    # Computes identifiable functions and converts it to a easy to read form.
155
    out = SI.find_identifiable_functions(osys, args...; measured_quantities, kwargs...)
×
156
    return vector_subs(out, consconsts)
×
157
end
158

159
### Helper Functions ###
160

161
# From a reaction system, creates the corresponding MTK-style ODESystem for SI application
162
# Also compute the, later needed, conservation law equations and list of system symbols (unknowns and parameters).
163
function make_osys(rs::ReactionSystem; remove_conserved = true)
×
164
    # Creates the ODESystem corresponding to the ReactionSystem (expanding functions and flattening it).
165
    # Creates a list of the systems all symbols (unknowns and parameters).
166
    if !ModelingToolkit.iscomplete(rs)
×
167
        error("Identifiability should only be computed for complete systems. A ReactionSystem can be marked as complete using the `complete` function.")
×
168
    end
169
    rs = complete(Catalyst.expand_registered_functions(flatten(rs)))
×
170
    osys = complete(convert(ODESystem, rs; remove_conserved, remove_conserved_warn = false))
×
171
    vars = [unknowns(rs); parameters(rs)]
×
172

173
    # Computes equations for system conservation laws.
174
    # If there are no conserved equations, the `conseqs` variable must still have the `Vector{Pair{Any, Any}}` type.
175
    if remove_conserved
×
176
        conseqs = [ceq.lhs => ceq.rhs for ceq in conservedequations(rs)]
×
177
        consconsts = [cconst.lhs => cconst.rhs for cconst in conservationlaw_constants(rs)]
×
178
        isempty(conseqs) && (conseqs = Vector{Pair{Any, Any}}[])
×
179
        isempty(consconsts) && (consconsts = Vector{Pair{Any, Any}}[])
×
180
    else
181
        conseqs = Vector{Pair{Any, Any}}[]
×
182
        consconsts = Vector{Pair{Any, Any}}[]
×
183
    end
184

185
    return osys, conseqs, consconsts, vars
×
186
end
187

188
# Creates a list of measured quantities of a form that SI can read.
189
# Each measured quantity must have a form like:
190
# `obs_var ~ X` # (Here, `obs_var` is a variable, and X is whatever we can measure).
191
function make_measured_quantities(rs::ReactionSystem, measured_quantities::Vector{T},
×
192
        known_p::Vector{S}, conseqs; ignore_no_measured_warn = false) where {T, S}
193
    # Warning if the user didn't give any measured quantities.
194
    if !ignore_no_measured_warn && isempty(measured_quantities)
×
195
        @warn "No measured quantity provided to the `measured_quantities` argument, any further identifiability analysis will likely fail. You can disable this warning by setting `ignore_no_measured_warn = true`."
×
196
    end
197

198
    # Appends the known parameters to the measured_quantities vector. Converts any Symbols to symbolics.
199
    mqiterator = Iterators.flatten((measured_quantities, known_p))
×
200
    mqs = [(q isa Symbol) ? Catalyst._symbol_to_var(rs, q) : q for q in mqiterator]
×
201
    mqs = vector_subs(mqs, conseqs)
×
202

203
    # Creates one internal observation variable for each measured quantity (`___internal_observables`).
204
    # Creates a vector of equations, setting each measured quantity equal to one observation variable.
205
    @variables (___internal_observables(Catalyst.get_iv(rs)))[1:length(mqs)]
×
206
    return Equation[(q isa Equation) ? q : (___internal_observables[i] ~ q)
×
207
                    for (i, q) in enumerate(mqs)]
208
end
209

210
# Creates the functions that we wish to check for identifiability.
211
# If no `funcs_to_check` are given, defaults to checking identifiability for all unknowns and parameters.
212
# Also, for conserved equations, replaces these in (creating a system without conserved quantities).
213
# E.g. for `X1 <--> X2`, replaces `X2` with `Γ[1] - X2`.
214
# Removing conserved quantities makes SI's algorithms much more performant.
215
function make_ftc(funcs_to_check, conseqs, vars)
×
216
    isempty(funcs_to_check) && (funcs_to_check = vars)
×
217
    return vector_subs(funcs_to_check, conseqs)
×
218
end
219

220
# Processes the outputs to a better form.
221
# Replaces conservation law equations back in the output (so that e.g. Γ are not displayed).
222
# Sorts the output according to their input order (defaults to the `[unknowns; parameters]` order).
223
function make_output(out, funcs_to_check, consconsts)
×
224
    funcs_to_check = vector_subs(funcs_to_check, consconsts)
×
225
    out = OrderedDict(zip(vector_subs(keys(out), consconsts), values(out)))
×
226
    sortdict = Dict(ftc => i for (i, ftc) in enumerate(funcs_to_check))
×
227
    return sort!(out; by = x -> sortdict[x])
×
228
end
229

230
# For a vector of expressions and a conservation law, substitutes the law into every equation.
231
vector_subs(eqs, subs) = [substitute(eq, subs) for eq in eqs]
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc