Skip to content

Commit e8c3e6b

Browse files
authored
Merge pull request #513 from isaacsas/networkproperties-tweaks
Networkproperties tweaks
2 parents 56c93aa + 0b7c9de commit e8c3e6b

File tree

9 files changed

+201
-73
lines changed

9 files changed

+201
-73
lines changed

docs/src/api/catalyst_api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ Below we list the remainder of the Catalyst API accessor functions mentioned
146146
above.
147147

148148
## Basic System Properties
149-
See [Symbolic Reaction Systems](@ref) for examples and [ModelingToolkit and
149+
See [Programmatic Construction of Symbolic Reaction Systems](@ref) for examples and [ModelingToolkit and
150150
Catalyst Accessor Functions](@ref) for more details on the basic accessor
151151
functions.
152152

@@ -196,10 +196,13 @@ merge!(network1::ReactionSystem, network2::ReactionSystem)
196196
```@docs
197197
conservationlaws
198198
conservedquantities
199+
conservedequations
200+
conservationlaw_constants
199201
ReactionComplexElement
200202
ReactionComplex
201203
reactioncomplexmap
202204
reactioncomplexes
205+
incidencemat
203206
complexstoichmat
204207
complexoutgoingmat
205208
incidencematgraph

docs/src/tutorials/dsl.md

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ network models using Catalyst's domain specific language (DSL). Examples showing
44
how to both construct and solve ODE, SDE, and jump models are provided in [Basic
55
Chemical Reaction Network Examples](@ref). To learn more about the symbolic
66
[`ReactionSystem`](@ref)s generated by the DSL, and how to use them directly, see
7-
the tutorial on [Symbolic Reaction Systems](@ref).
7+
the tutorial on [Programmatic Construction of Symbolic Reaction Systems](@ref).
88

99
## Basic syntax
1010

@@ -21,8 +21,8 @@ The basic syntax is:
2121

2222
```julia
2323
rn = @reaction_network begin
24-
2.0, X + Y --> XY
25-
1.0, XY --> Z1 + Z2
24+
2.0, X + Y --> XY
25+
1.0, XY --> Z1 + Z2
2626
end
2727
```
2828

@@ -56,15 +56,15 @@ u0 = [X => 1.0, Y => 1.0, XY => 1.0, Z1 => 1.0, Z2 => 1.0]
5656
```
5757
Alternatively, we can create a mapping use Julia `Symbol`s for each variable, and then convert them to a mapping involving symbolic variables like
5858
```julia
59-
u0 = symmap_to_varmap(rn, [:X => 1.0, :Y => 1.0, :XY => 1.0, :Z1 => 1.0, :Z2 => 1.0])
59+
u0 = symmap_to_varmap(rn, [:X => 1.0, :Y => 1.0, :XY => 1.0, :Z1 => 1.0, :Z2 => 1.0])
6060
```
6161
Given the mapping, we can then create an `ODEProblem` from our symbolic `ODESystem`
6262
```julia
6363
oprob = ODEProblem(osys, u0, tspan, [])
6464
```
6565

6666
Catalyst provides a shortcut to avoid having to explicitly `convert` to an
67-
`ODESystem` and/or use `symmap_to_varmap`, allowing direct construction
67+
`ODESystem` and/or use `symmap_to_varmap`, allowing direct construction
6868
of the `ODEProblem` like
6969
```julia
7070
u0 = [:X => 1.0, :Y => 1.0, :XY => 1.0, :Z1 => 1.0, :Z2 => 1.0]
@@ -143,10 +143,10 @@ arrows can also be used to write the reaction in the opposite direction. For
143143
example, these reactions are equivalent:
144144
```julia
145145
rn = @reaction_network begin
146-
1.0, X + Y --> XY
147-
1.0, X + Y XY
148-
1.0, XY X + Y
149-
1.0, XY <-- X + Y
146+
1.0, X + Y --> XY
147+
1.0, X + Y XY
148+
1.0, XY X + Y
149+
1.0, XY <-- X + Y
150150
end
151151
```
152152

@@ -156,25 +156,25 @@ used to designate a reversible reaction. For example, these two models are
156156
equivalent:
157157
```julia
158158
rn = @reaction_network begin
159-
2.0, X + Y --> XY
160-
2.0, X + Y <-- XY
159+
2.0, X + Y --> XY
160+
2.0, X + Y <-- XY
161161
end
162162
rn = @reaction_network begin
163-
(2.0,2.0), X + Y <--> XY
163+
(2.0,2.0), X + Y <--> XY
164164
end
165165
```
166166
If the reaction rates in the backward and forward directions are different, they
167167
can be designated in the following way:
168168
```julia
169169
rn = @reaction_network begin
170-
(2.0,1.0) X + Y <--> XY
170+
(2.0,1.0) X + Y <--> XY
171171
end
172172
```
173173
which is identical to
174174
```julia
175175
rn = @reaction_network begin
176-
2.0, X + Y --> XY
177-
1.0, X + Y <-- XY
176+
2.0, X + Y --> XY
177+
1.0, X + Y <-- XY
178178
end
179179
```
180180

@@ -185,43 +185,43 @@ they must all be of identical length. These pairs of reaction networks are all
185185
identical:
186186
```julia
187187
rn1 = @reaction_network begin
188-
1.0, S --> (P1,P2)
188+
1.0, S --> (P1,P2)
189189
end
190190
rn2 = @reaction_network begin
191-
1.0, S --> P1
191+
1.0, S --> P1
192192
1.0, S --> P2
193193
end
194194
```
195195
```julia
196196
rn1 = @reaction_network begin
197-
(1.0,2.0), (S1,S2) --> P
197+
(1.0,2.0), (S1,S2) --> P
198198
end
199199
rn2 = @reaction_network begin
200-
1.0, S1 --> P
200+
1.0, S1 --> P
201201
2.0, S2 --> P
202202
end
203203
```
204204
```julia
205205
rn1 = @reaction_network begin
206-
(1.0,2.0,3.0), (S1,S2,S3) (P1,P2,P3)
206+
(1.0,2.0,3.0), (S1,S2,S3) (P1,P2,P3)
207207
end
208208
rn2 = @reaction_network begin
209209
1.0, S1 --> P1
210-
2.0, S2 --> P2
211-
3.0, S3 --> P3
210+
2.0, S2 --> P2
211+
3.0, S3 --> P3
212212
end
213213
```
214214
This can also be combined with bi-directional arrows, in which case separate
215215
tuples can be provided for the backward and forward reaction rates.
216216
These reaction networks are identical
217217
```julia
218218
rn1 = @reaction_network begin
219-
(1.0,(1.0,2.0)), S <--> (P1,P2)
219+
(1.0,(1.0,2.0)), S <--> (P1,P2)
220220
end
221221
rn2 = @reaction_network begin
222222
1.0, S --> P1
223223
1.0, S --> P2
224-
1.0, P1 --> S
224+
1.0, P1 --> S
225225
2.0, P2 --> S
226226
end
227227
```
@@ -307,8 +307,8 @@ end v K
307307

308308
Please see the API [Rate Laws](@ref) section for more details.
309309

310-
## Interpolation of Julia Variables
311-
The DSL allows Julia variables to be interpolated for the network name, within rate constant expressions, or for species within the reaction. For example,
310+
## Interpolation of Julia Variables
311+
The DSL allows Julia variables to be interpolated for the network name, within rate constant expressions, or for species within the reaction. For example,
312312
```julia
313313
@parameters k
314314
@variables t, A(t)
@@ -329,7 +329,7 @@ States (3):
329329
Parameters (1):
330330
k
331331
```
332-
with
332+
with
333333
```julia
334334
reactions(rn)
335335
```

docs/src/tutorials/generating_reactions_programmatically.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generating ReactionSystems Programmatically
1+
# Smoluchowski Coagulation Equation
22
This tutorial shows how to programmatically construct a [`ReactionSystem`](@ref) corresponding to the chemistry underlying the [Smoluchowski coagulation model](https://en.wikipedia.org/wiki/Smoluchowski_coagulation_equation) using [ModelingToolkit](https://mtk.sciml.ai/stable/)/[Catalyst](https://catalyst.sciml.ai/dev/). A jump process version of the model is then constructed from the [`ReactionSystem`](@ref), and compared to the model's analytical solution obtained by the [method of Scott](https://journals.ametsoc.org/view/journals/atsc/25/1/1520-0469_1968_025_0054_asocdc_2_0_co_2.xml) (see also [3](https://doi.org/10.1006/jcph.2002.7017)).
33

44
The Smoluchowski coagulation equation describes a system of reactions in which monomers may collide to form dimers, monomers and dimers may collide to form trimers, and so on. This models a variety of chemical/physical processes, including polymerization and flocculation.
@@ -9,7 +9,7 @@ using ModelingToolkit, Catalyst, LinearAlgebra
99
using DiffEqBase, DiffEqJump
1010
using Plots, SpecialFunctions
1111
```
12-
Suppose the maximum cluster size is `N`. We assume an initial concentration of monomers, `Nₒ`, and let `uₒ` denote the initial number of monomers in the system. We have `nr` total reactions, and label by `V` the bulk volume of the system (which plays an important role in the calculation of rate laws since we have bimolecular reactions). Our basic parameters are then
12+
Suppose the maximum cluster size is `N`. We assume an initial concentration of monomers, `Nₒ`, and let `uₒ` denote the initial number of monomers in the system. We have `nr` total reactions, and label by `V` the bulk volume of the system (which plays an important role in the calculation of rate laws since we have bimolecular reactions). Our basic parameters are then
1313
```julia
1414
## Parameter
1515
N = 10 # maximum cluster size
@@ -23,7 +23,7 @@ n = integ(N/2)
2323
nr = N%2 == 0 ? (n*(n + 1) - n) : (n*(n + 1)) # No. of forward reactions
2424
```
2525
The [Smoluchowski coagulation equation](https://en.wikipedia.org/wiki/Smoluchowski_coagulation_equation) Wikipedia page illustrates the set of possible reactions that can occur. We can easily enumerate the `pair`s of multimer reactants that can combine when allowing a maximal cluster size of `N` monomers. We initialize the volumes of the reactant multimers as `volᵢ` and `volⱼ`
26-
26+
2727
```julia
2828
# possible pairs of reactant multimers
2929
pair = []
@@ -46,44 +46,44 @@ if i==1
4646
kv = @. B*(volᵢ + volⱼ)/V # dividing by volume as its a bi-molecular reaction chain
4747
elseif i==2
4848
C = 1.84e-04 # cm³ s⁻¹
49-
kv = fill(C/V, nr)
49+
kv = fill(C/V, nr)
5050
end
5151
```
5252
We'll store the reaction rates in `pars` as `Pair`s, and set the initial condition that only monomers are present at ``t=0`` in `u₀map`.
5353
```julia
5454
# state variables are X, pars stores rate parameters for each rx
55-
@parameters t
55+
@parameters t
5656
@variables k[1:nr] X[1:N](t)
5757
pars = Pair.(collect(k), kv)
5858

5959
# time-span
6060
if i == 1
61-
tspan = (0. ,2000.)
61+
tspan = (0. ,2000.)
6262
elseif i == 2
6363
tspan = (0. ,350.)
6464
end
6565

6666
# initial condition of monomers
6767
u₀ = zeros(Int64, N)
68-
u₀[1] = uₒ
68+
u₀[1] = uₒ
6969
u₀map = Pair.(collect(X), u₀) # map variable to its initial value
7070
```
7171
Here we generate the reactions programmatically. We systematically create Catalyst `Reaction`s for each possible reaction shown in the figure on [Wikipedia](https://en.wikipedia.org/wiki/Smoluchowski_coagulation_equation). When `vᵢ[n] == vⱼ[n]`, we set the stoichiometric coefficient of the reactant multimer to two.
7272
```julia
7373
# vector to store the Reactions in
74-
rx = []
74+
rx = []
7575
for n = 1:nr
7676
# for clusters of the same size, double the rate
77-
if (vᵢ[n] == vⱼ[n])
77+
if (vᵢ[n] == vⱼ[n])
7878
push!(rx, Reaction(k[n], [X[vᵢ[n]]], [X[sum_vᵢvⱼ[n]]], [2], [1]))
7979
else
80-
push!(rx, Reaction(k[n], [X[vᵢ[n]], X[vⱼ[n]]], [X[sum_vᵢvⱼ[n]]],
80+
push!(rx, Reaction(k[n], [X[vᵢ[n]], X[vⱼ[n]]], [X[sum_vᵢvⱼ[n]]],
8181
[1, 1], [1]))
8282
end
8383
end
8484
@named rs = ReactionSystem(rx, t, collect(X), collect(k))
8585
```
86-
We now convert the [`ReactionSystem`](@ref) into a `ModelingToolkit.JumpSystem`, and solve it using Gillespie's direct method. For details on other possible solvers (SSAs), see the [DifferentialEquations.jl](https://diffeq.sciml.ai/latest/types/jump_types/) documentation
86+
We now convert the [`ReactionSystem`](@ref) into a `ModelingToolkit.JumpSystem`, and solve it using Gillespie's direct method. For details on other possible solvers (SSAs), see the [DifferentialEquations.jl](https://diffeq.sciml.ai/latest/types/jump_types/) documentation
8787
```julia
8888
# solving the system
8989
jumpsys = convert(JumpSystem, rs)
@@ -102,7 +102,7 @@ v_res = [1;2;3]
102102
t = jsol.t
103103
sol = zeros(length(v_res), length(t))
104104
if i == 1
105-
ϕ = @. 1 - exp(-B*Nₒ*Vₒ*t)
105+
ϕ = @. 1 - exp(-B*Nₒ*Vₒ*t)
106106
for j in v_res
107107
sol[j,:] = @. Nₒ*(1 - ϕ)*(((j*ϕ)^(j-1))/gamma(j+1))*exp(-j*ϕ)
108108
end
@@ -122,7 +122,7 @@ scatter!(ϕ, jsol(t)[2,:]/uₒ, label="X2 (dimers)", markercolor=:orange)
122122
plot!(ϕ, sol[2,:]/Nₒ, line = (:dot,4,:orange), label="Analytical sol--X2")
123123

124124
scatter!(ϕ, jsol(t)[3,:]/uₒ, label="X3 (trimers)", markercolor=:purple)
125-
plot!(ϕ, sol[3,:]/Nₒ, line = (:dot,4,:purple), label="Analytical sol--X3",
125+
plot!(ϕ, sol[3,:]/Nₒ, line = (:dot,4,:purple), label="Analytical sol--X3",
126126
ylabel = "Normalized Concentration")
127127
```
128128
For the **additive kernel** we find

docs/src/tutorials/reaction_systems.md

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Symbolic Reaction Systems
1+
# Programmatic Construction of Symbolic Reaction Systems
22
While the DSL provides a simple interface for creating `ReactionSystem`s, it can
33
often be convenient to build or augment a [`ReactionSystem`](@ref)
44
programmatically. In this tutorial we show how to build the repressilator model
@@ -15,8 +15,8 @@ and then define symbolic variables for each parameter and species in the system
1515
(the latter corresponding to a `variable` or `state` in ModelingToolkit
1616
terminology)
1717
```julia
18-
@parameters α, K, n, δ, γ, β, μ;
19-
@variables t, m₁(t), m₂(t), m₃(t), P₁(t), P₂(t), P₃(t);
18+
@parameters α K n δ γ β μ
19+
@variables t m₁(t) m₂(t) m₃(t) P₁(t) P₂(t) P₃(t)
2020
```
2121
```@setup ex
2222
@parameters α, K, n, δ, γ, β, μ;
@@ -35,7 +35,7 @@ rxs = [Reaction(hillr(P₃,α,K,n), nothing, [m₁]),
3535
Reaction(δ, [m₂], nothing),
3636
Reaction(γ, nothing, [m₂]),
3737
Reaction(δ, [m₃], nothing),
38-
Reaction(γ, nothing, [m₃]),
38+
Reaction(γ, nothing, [m₃]),
3939
Reaction(β, [m₁], [m₁,P₁]),
4040
Reaction(β, [m₂], [m₂,P₂]),
4141
Reaction(β, [m₃], [m₃,P₃]),
@@ -52,7 +52,7 @@ rxs = [Reaction(hillr(P₃,α,K,n), nothing, [m₁]),
5252
Reaction(δ, [m₂], nothing),
5353
Reaction(γ, nothing, [m₂]),
5454
Reaction(δ, [m₃], nothing),
55-
Reaction(γ, nothing, [m₃]),
55+
Reaction(γ, nothing, [m₃]),
5656
Reaction(β, [m₁], [m₁,P₁]),
5757
Reaction(β, [m₂], [m₂,P₂]),
5858
Reaction(β, [m₃], [m₃,P₃]),
@@ -135,11 +135,63 @@ rx = Reaction(α+β*t*A, [A], [B])
135135
[See the FAQs](@ref user_functions) for info on using general user-specified
136136
functions for the rate constant.
137137

138+
## `@reaction` macro for constructing `Reaction`s
139+
In some cases one wants to build reactions incrementally, as in the
140+
repressilator example, but it would be nice to still have a short hand as in the
141+
[`@reaction_network`](@ref) DSL. In this case one can construct individual
142+
reactions using the [`@reaction`](@ref) macro.
143+
144+
For example, the repressilator reactions could also have been constructed like
145+
```julia
146+
@variables t P₁(t) P₂(t) P₃(t)
147+
rxs = [(@reaction hillr($P₃,α,K,n), ∅ --> m₁),
148+
(@reaction hillr($P₁,α,K,n), ∅ --> m₂),
149+
(@reaction hillr($P₂,α,K,n), ∅ --> m₃),
150+
(@reaction δ, m₁ --> ∅),
151+
(@reaction γ, ∅ --> m₁),
152+
(@reaction δ, m₂ --> ∅),
153+
(@reaction γ, ∅ --> m₂),
154+
(@reaction δ, m₃ --> ∅),
155+
(@reaction γ, ∅ --> m₃),
156+
(@reaction β, m₁ --> m₁ + P₁),
157+
(@reaction β, m₂ --> m₂ + P₂),
158+
(@reaction β, m₃ --> m₃ + P₃),
159+
(@reaction μ, P₁ --> ∅),
160+
(@reaction μ, P₂ --> ∅),
161+
(@reaction μ, P₃ --> ∅)]
162+
@named repressilator = ReactionSystem(rxs, t)
163+
```
164+
Note, there are a few differences when using the `@reaction` macro to specify
165+
one reaction versus using the full `@reaction_network` macro to create a
166+
`ReactionSystem`. First, only one reaction (i.e. a single forward arrow type)
167+
can be used, i.e. reversible arrows like `<-->` will not work (since they define
168+
more than one reaction). Second, the `@reaction` macro must try to infer which
169+
symbols are species versus parameters, and uses the heuristic that anything
170+
appearing in the rate expression is a parameter. Coefficients in the reaction
171+
part are also inferred as parameters, while rightmost symbols (i.e. substrates
172+
and products) are inferred as species. As such, the following are equivalent
173+
```julia
174+
rx = @reaction hillr(P,α,K,n), A --> B
175+
```
176+
is equivalent to
177+
```julia
178+
@parameters P α K n
179+
@variables t A(t) B(t)
180+
rx = Reaction(hillr(P,α,K,n), [A], [B])
181+
```
182+
Here `(P,α,K,n)` are parameters and `(A,B)` are species.
183+
184+
This behavior is the reason that in the repressilator example above we
185+
pre-declared `(P₁(t),P₂(t),P₃(t))` as variables, and then used them via
186+
interpolating their values into the rate law expressions using `$` in the macro.
187+
This ensured they were properly treated as species and not parameters. See the
188+
[`@reaction`](@ref) macro docstring for more information.
189+
138190
## Basic Querying of `ReactionSystems`
139191

140192
The [Catalyst.jl API](@ref) provides a large variety of functionality for
141193
querying properties of a reaction network. Here we go over a few of the most
142-
useful basic functions. Given the `repressillator` defined above we have that
194+
useful basic functions. Given the `repressillator` defined above we have that
143195
```@example ex
144196
species(repressilator)
145197
```
@@ -206,4 +258,3 @@ rx1.netstoich
206258

207259
See the [Catalyst.jl API](@ref) for much more detail on the various querying and
208260
analysis functions provided by Catalyst.
209-

0 commit comments

Comments
 (0)