Skip to content

Commit f5b92ab

Browse files
authored
Merge pull request #1222 from SciML/remove_rates_only_bundling
Throw error when bundling reactions where only the rates differe
2 parents 3842113 + 11cee31 commit f5b92ab

File tree

8 files changed

+87
-34
lines changed

8 files changed

+87
-34
lines changed

HISTORY.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@
7676
functions (as a parameter) in a model. For more details on how to use these,
7777
please read:
7878
https://docs.sciml.ai/Catalyst/stable/model_creation/functional_parameters/.
79+
- We have introduced a restriction on bundling of reactions in the DSL. Now,
80+
bundling is not permitted if multiple rates are provided but only one set each
81+
of substrates/products. E.g. this model:
82+
```julia
83+
@reaction_network begin
84+
(k1,k2), X --> Y
85+
end
86+
```
87+
will now throw an error. The reason that users attempting to write bi-directional
88+
reactions but typing `-->` instead of `<-->` would get a wrong model. We decided that
89+
this kind of bundling was unlikely to be used, and throwing errors for people who
90+
made the typo was more important.
91+
92+
If you use this type of bundling and it indeed is useful to you, please raise and issue
93+
and we will see if we can sort something out.
7994
- Scoped species/variables/parameters are now treated similar to the latest MTK
8095
releases ( 9.49).
8196
- A tutorial on making interactive plot displays using Makie has been added.

docs/src/faqs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ conserved constant(s), `Γ`, are updated. As an example consider the following
339339
using Catalyst, NonlinearSolve
340340
rn = @reaction_network begin
341341
(k₁,k₂), X₁ <--> X₂
342-
(k₃,k₄), X₁ + X₂ --> 2X₃
342+
(k₃,k₄), X₁ + X₂ <--> 2X₃
343343
end
344344
u0 = [:X₁ => 1.0, :X₂ => 2.0, :X₃ => 3.0]
345345
ps = [:k₁ => 0.1, :k₂ => 0.2, :k₃ => 0.3, :k₄ => 0.4]

docs/src/model_creation/dsl_basics.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,15 @@ end
188188
```
189189
However, like for the above model, bundling reactions too zealously can reduce (rather than improve) a model's readability.
190190

191+
The one exception to reaction bundling is that we do not permit the user to provide multiple rates but only set one set each for the substrates and products. I.e.
192+
```julia
193+
rn = @reaction_network begin
194+
(k1,k2), X --> Y
195+
end
196+
```
197+
is not permitted (due to this notation's similarity to a bidirectional reaction). However, if multiples are provided for substrates and/or products, like `(k1,k2), (X1,X2) --> Y`, then bundling works.
198+
199+
191200
## [Non-constant reaction rates](@id dsl_description_nonconstant_rates)
192201
So far we have assumed that all reaction rates are constant (being either a number of a parameter). Non-constant rates that depend on one (or several) species are also possible. More generally, the rate can be any valid expression of parameters and species.
193202

src/dsl.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,13 @@ function get_reactions(exprs::Vector{Expr})
365365
# Reads core reaction information.
366366
arrow, rate, reaction, metadata = read_reaction_line(line)
367367

368+
# Currently, reaction bundling where rates (but neither substrates nor products) are
369+
# bundled, is disabled. See discussion in https://github.com/SciML/Catalyst.jl/issues/1219.
370+
if !in(arrow, double_arrows) && Meta.isexpr(rate, :tuple) &&
371+
!Meta.isexpr(reaction.args[2], :tuple) && !Meta.isexpr(reaction.args[3], :tuple)
372+
error("Bundling of reactions with multiple rates but singular substrates and product sets is disallowed. This error is potentially due to a bidirectional (`<-->`) reaction being incorrectly typed as `-->`.")
373+
end
374+
368375
# Checks which type of line is used, and calls `push_reactions!` on the processed line.
369376
if in(arrow, double_arrows)
370377
(typeof(rate) != Expr || rate.head != :tuple) &&

test/dsl/dsl_basic_model_construction.jl

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ let
179179
different_arrow_8 = @reaction_network begin
180180
p, 2X1 <
181181
k1, X2 X1
182-
(k2, k3), X3 X2
182+
(k2, k3), X3 (X2,X2)
183183
d, ∅ X3
184184
end
185185
push!(identical_networks_1, reaction_networks_standard[8] => different_arrow_8)
@@ -298,10 +298,11 @@ let
298298

299299
no_parameters_10 = @reaction_network begin
300300
0.01, ∅ X1
301-
(3.1, 3.2), X1 X2
302-
(0.0, 2.1), X2 X3
303-
(901.0, 63.5), X3 X4
304-
(7, 8), X4 X5
301+
(3.1, 3.2), (X1,X1) X2
302+
(0.0, 2.1), X2 (X3,X3)
303+
(901.0, 63.5), (X3,X3) (X4,X4)
304+
7, X4 X5
305+
8, X4 X5
305306
1.0, X5
306307
end
307308
push!(identical_networks_3, reaction_networks_standard[10] => no_parameters_10)
@@ -591,3 +592,20 @@ let
591592
d, X 0
592593
end
593594
end
595+
596+
# Tests that bundling, but where the rate only have been given multiple alternatives, errors.
597+
# Checks for two, more than two, and for functional rates. Uses different arrow types and directions.
598+
let
599+
@test_throws Exception @eval @reaction_network begin
600+
(k1,k2), X --> 0
601+
end
602+
@test_throws Exception @eval @reaction_network begin
603+
(k1,k2,k3), X 0
604+
end
605+
@test_throws Exception @eval @reaction_network begin
606+
(k1,k1), X => Y
607+
end
608+
@test_throws Exception @eval @reaction_network begin
609+
(mm(X,v1,K1),mm(X,v2,K2)), 0 <-- 0
610+
end
611+
end

test/dsl/dsl_options.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ let
316316
@parameters p1=1.0 p2=2.0 k1=4.0 k2=5.0 v=8.0 K=9.0 n=3 d=10.0
317317
@species X(t)=4.0 Y(t)=3.0 X2Y(t)=2.0 Z(t)=1.0
318318
(p1,p2), 0 --> (X,Y)
319-
(k1,k2), 2X + Y --> X2Y
319+
k1, 2X + Y --> X2Y
320+
k2, 2X + Y --> X2Y
320321
hill(X2Y,v,K,n), 0 --> Z
321322
d, (X,Y,X2Y,Z) --> 0
322323
end
@@ -327,7 +328,8 @@ let
327328
@parameters p1=1.0 p2 k1=4.0 k2 v=8.0 K n=3 d
328329
@species X(t)=4.0 Y(t) X2Y(t) Z(t)=1.0
329330
(p1,p2), 0 --> (X,Y)
330-
(k1,k2), 2X + Y --> X2Y
331+
k1, 2X + Y --> X2Y
332+
k2, 2X + Y --> X2Y
331333
hill(X2Y,v,K,n), 0 --> Z
332334
d, (X,Y,X2Y,Z) --> 0
333335
end
@@ -339,7 +341,8 @@ let
339341
@parameters p1 p2 k1 k2 v K n d
340342
@species X(t) Y(t) X2Y(t) Z(t)
341343
(p1,p2), 0 --> (X,Y)
342-
(k1,k2), 2X + Y --> X2Y
344+
k1, 2X + Y --> X2Y
345+
k2, 2X + Y --> X2Y
343346
hill(X2Y,v,K,n), 0 --> Z
344347
d, (X,Y,X2Y,Z) --> 0
345348
end

test/network_analysis/network_properties.jl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ let
7676
(k₁, k₂), E + S1 <--> ES1
7777
(k₃, k₄), E + S2 <--> ES2
7878
(k₅, k₆), S2 + ES1 <--> ES1S2
79-
(k₆, k₇), ES1S2 --> S1 + ES2
79+
(k₆, k₇), ES1S2 <--> S1 + ES2
8080
k₈, ES1S2 --> E+P
8181
(k₉, k₁₀), S1 <--> 0
8282
(k₁₀, k₁₁), 0 <--> S2
@@ -148,18 +148,18 @@ let
148148
@test length(slcs) == 3
149149
@test length(tslcs) == 2
150150
@test issubset([[1,2], [3,4,5], [6,7]], slcs)
151-
@test issubset([[3,4,5], [6,7]], tslcs)
151+
@test issubset([[3,4,5], [6,7]], tslcs)
152152
end
153153

154-
# b) Makes the D + E --> G reaction irreversible. Thus, (D+E) becomes a non-terminal linkage class. Checks whether correctly identifies both (A, B+C) and (D+E) as non-terminal
154+
# b) Makes the D + E --> G reaction irreversible. Thus, (D+E) becomes a non-terminal linkage class. Checks whether correctly identifies both (A, B+C) and (D+E) as non-terminal
155155
let
156156
rn = @reaction_network begin
157157
(k1, k2), A <--> B + C
158158
k3, B + C --> D
159159
k4, D --> E
160160
(k5, k6), E <--> 2F
161161
k7, 2F --> D
162-
(k8, k9), D + E --> G
162+
k8, D + E --> G
163163
end
164164

165165
rcs, D = reactioncomplexes(rn)
@@ -168,10 +168,10 @@ let
168168
@test length(slcs) == 4
169169
@test length(tslcs) == 2
170170
@test issubset([[1,2], [3,4,5], [6], [7]], slcs)
171-
@test issubset([[3,4,5], [7]], tslcs)
171+
@test issubset([[3,4,5], [7]], tslcs)
172172
end
173173

174-
# From a), makes the B + C <--> D reaction reversible. Thus, the non-terminal (A, B+C) linkage class gets absorbed into the terminal (A, B+C, D, E, 2F) linkage class, and the terminal linkage classes and strong linkage classes coincide.
174+
# From a), makes the B + C <--> D reaction reversible. Thus, the non-terminal (A, B+C) linkage class gets absorbed into the terminal (A, B+C, D, E, 2F) linkage class, and the terminal linkage classes and strong linkage classes coincide.
175175
let
176176
rn = @reaction_network begin
177177
(k1, k2), A <--> B + C
@@ -188,13 +188,13 @@ let
188188
@test length(slcs) == 2
189189
@test length(tslcs) == 2
190190
@test issubset([[1,2,3,4,5], [6,7]], slcs)
191-
@test issubset([[1,2,3,4,5], [6,7]], tslcs)
191+
@test issubset([[1,2,3,4,5], [6,7]], tslcs)
192192
end
193193

194194
# Simple test for strong and terminal linkage classes
195195
let
196196
rn = @reaction_network begin
197-
(k1, k2), A <--> 2B
197+
(k1, k2), A <--> 2B
198198
k3, A --> C + D
199199
(k4, k5), C + D <--> E
200200
k6, 2B --> F
@@ -209,7 +209,7 @@ let
209209
@test length(slcs) == 3
210210
@test length(tslcs) == 2
211211
@test issubset([[1,2], [3,4], [5,6,7]], slcs)
212-
@test issubset([[3,4], [5,6,7]], tslcs)
212+
@test issubset([[3,4], [5,6,7]], tslcs)
213213
end
214214

215215
# Cycle Test: Open Reaction Network
@@ -261,7 +261,7 @@ let
261261
k2, C + D --> E + F
262262
k3, C + D --> 2G + H
263263
k4, 2G + H --> 3I
264-
k5, E + F --> J
264+
k5, E + F --> J
265265
k6, 3I --> K
266266
end
267267

@@ -273,7 +273,7 @@ end
273273

274274
### Other Network Properties Tests ###
275275

276-
# Tests outgoing complexes matrices (1).
276+
# Tests outgoing complexes matrices (1).
277277
# Checks using dense and sparse representation.
278278
let
279279
# Declares network.
@@ -283,7 +283,7 @@ let
283283
k3, X1 --> X2
284284
k4, X1 + X2 --> X2
285285
end
286-
286+
287287
# Compares to manually computed matrix.
288288
cmplx_out_mat = [
289289
-1 0 0 0 -1;
@@ -368,17 +368,17 @@ let
368368
MAPK.KKPP * MAPK.KKPase,
369369
MAPK.KKPP * MAPK.K,
370370
MAPK.KKPPK,
371-
MAPK.KKPP * MAPK.KP,
371+
MAPK.KKPP * MAPK.KP,
372372
MAPK.KPKKPP,
373373
MAPK.KPP * MAPK.KKPP,
374374
MAPK.KP * MAPK.KPase,
375-
MAPK.KPKPase,
376-
MAPK.KKPPKPase,
375+
MAPK.KPKPase,
376+
MAPK.KKPPKPase,
377377
MAPK.K * MAPK.KPase,
378378
MAPK.KPP * MAPK.KPase,
379379
]
380380
@test isequal(Φ, truevec)
381-
381+
382382
K = Catalyst.fluxmat(MAPK)
383383
# Construct flux matrix from incidence matrix
384384
mat = Matrix{Any}(zeros(30, 26))
@@ -391,12 +391,12 @@ let
391391
@test isequal(K, mat)
392392
@test isequal(K[1, 1], MAPK.k₁)
393393
@test all(==(0), K[1, 2:end])
394-
@test isequal(K[2, 2], MAPK.k₂)
394+
@test isequal(K[2, 2], MAPK.k₂)
395395
@test all(==(0), vcat(K[2,1], K[2,3:end]))
396396
@test isequal(K[3, 2], MAPK.k₃)
397397
@test all(==(0), vcat(K[3,1], K[3,3:end]))
398398
@test count(k -> !isequal(k, 0), K) == length(reactions(MAPK))
399-
399+
400400
A_k = Catalyst.laplacianmat(MAPK)
401401
@test all(col -> sum(col) == 0, eachcol(A_k))
402402

@@ -415,7 +415,7 @@ let
415415
ratetup = Tuple(ratevec)
416416

417417
@test Catalyst.fluxmat(MAPK, ratemap) == Catalyst.fluxmat(MAPK, ratevec) == Catalyst.fluxmat(MAPK, ratetup)
418-
418+
419419
K = Catalyst.fluxmat(MAPK, ratemap)
420420
A_k = Catalyst.laplacianmat(MAPK, ratemap)
421421
@test all(col -> sum(col) == 0, eachcol(A_k))
@@ -428,7 +428,7 @@ let
428428
@test all(iszero, simplify(numeqs - Y*A_k*Φ))
429429
end
430430

431-
# Test handling for weird complexes and combinatoric rate laws.
431+
# Test handling for weird complexes and combinatoric rate laws.
432432
let
433433
rn = @reaction_network begin
434434
k1, 2X + Y + 3Z -->

test/test_networks.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ end
6464
reaction_networks_standard[8] = @reaction_network rns8 begin
6565
p, ∅ 2X1
6666
k1, X1 X2
67-
(k2, k3), X2 X3
67+
k2, X2 X3
68+
k3, X2 X3
6869
d, X3
6970
end
7071

@@ -78,10 +79,10 @@ end
7879

7980
reaction_networks_standard[10] = @reaction_network rns10 begin
8081
p, ∅ X1
81-
(k1, k2), X1 X2
82-
(k3, k4), X2 X3
83-
(k5, k6), X3 X4
84-
(k7, k8), X4 X5
82+
(k1, k2), (X1,X1) X2
83+
(k3, k4), (X2,X2) X3
84+
(k5, k6), (X3,X3) X4
85+
(k7, k8), (X4,X4) X5
8586
d, X5
8687
end
8788

0 commit comments

Comments
 (0)