Skip to content

Commit a568ded

Browse files
authored
Merge pull request #765 from SciML/update_basic_examples
[v14 ready] Change basic model examples to library of basic models
2 parents 41d88d2 + ed091cd commit a568ded

File tree

4 files changed

+589
-89
lines changed

4 files changed

+589
-89
lines changed

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
88
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
99
HomotopyContinuation = "f213a82b-91d6-5c5d-acf7-10f1c761b327"
10+
JumpProcesses = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5"
1011
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
1112
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
1213
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"

docs/src/model_creation/dsl_description.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
This tutorial describes the syntax for building chemical reaction
33
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
5-
Chemical Reaction Network Examples](@ref basic_CRN_examples). To learn more about the symbolic
5+
Chemical Reaction Network Examples](@ref basic_CRN_library). To learn more about the symbolic
66
[`ReactionSystem`](@ref)s generated by the DSL, and how to use them directly, see
77
the tutorial on [Programmatic Construction of Symbolic Reaction Systems](@ref programmatic_CRN_construction).
88

@@ -80,8 +80,7 @@ u0 = [:X => 1.0, :Y => 1.0, :XY => 1.0, :Z1 => 1.0, :Z2 => 1.0]
8080
oprob = ODEProblem(rn, u0, tspan, [])
8181
```
8282

83-
For more detailed examples, see the [Basic Chemical Reaction Network
84-
Examples](@ref basic_CRN_examples).
83+
For more detailed examples, see the example implementations in the [Library of Basic Chemical Reaction Network Models](@ref basic_CRN_library) section.
8584

8685
## Defining parameters and species
8786
Numeric parameter values do not need to be set when the model is created, i.e.
Lines changed: 239 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,274 @@
1-
# [Basic Chemical Reaction Network Examples](@id basic_CRN_examples)
1+
# [Library of Basic Chemical Reaction Network Models](@id basic_CRN_library)
2+
Below we will present various simple and established chemical reaction network (CRN) models. Each model is given some brief background, implemented using the `@reaction_network` DSL, and basic simulations are performed.
23

3-
## Example: Birth-death process
4-
5-
```@example bcrn1
6-
using Catalyst, DifferentialEquations, Plots
4+
## Birth-death process
5+
The birth-death process is one of the simplest possible CRN models. It consists of a single component ($X$) which is both produced and degraded at linear rates:
6+
```@example crn_library_birth_death
7+
using Catalyst
8+
bd_process = @reaction_network begin
9+
(p,d), ∅ <--> X
10+
end
11+
```
12+
Next we define simulation conditions. Note that the initial condition is integer-valued (required to perform jump simulations).
13+
```@example crn_library_birth_death
14+
u0 = [:X => 1]
15+
tspan = (0.0, 10.0)
16+
ps = [:p => 1, :d => 0.2]
17+
```
18+
We can now simulate our model using all three interpretations. First we perform a reaction rate equation-based ODE simulation:
19+
```@example crn_library_birth_death
20+
using OrdinaryDiffEq
21+
oprob = ODEProblem(bd_process, u0, tspan, ps)
22+
osol = solve(oprob, Tsit5())
23+
nothing # hide
24+
```
25+
Next, a chemical Langevin equation-based SDE simulation:
26+
```@example crn_library_birth_death
27+
using StochasticDiffEq
28+
sprob = SDEProblem(bd_process, u0, tspan, ps)
29+
ssol = solve(sprob, ImplicitEM())
30+
nothing # hide
31+
```
32+
Next, a stochastic chemical kinetics-based jump simulation:
33+
```@example crn_library_birth_death
34+
using JumpProcesses
35+
dprob = DiscreteProblem(bd_process, u0, tspan, ps)
36+
jprob = JumpProblem(bd_process, dprob, Direct())
37+
jsol = solve(jprob, SSAStepper())
38+
nothing # hide
39+
```
40+
Finally, we plot the results:
41+
```@example crn_library_birth_death
42+
using Plots
43+
oplt = plot(osol; title = "Reaction rate equation (ODE)")
44+
splt = plot(ssol; title = "Chemical Langevin equation (SDE)")
45+
jplt = plot(jsol; title = "Stochastic chemical kinetics (Jump)")
46+
plot(oplt, splt, jplt; size=(800,700), layout = (3,1))
47+
```
748

8-
rs = @reaction_network begin
9-
c1, X --> 2X
10-
c2, X --> 0
11-
c3, 0 --> X
49+
## Michaelis-Menten enzyme kinetics
50+
[Michaelis-Menten enzyme kinetics](https://en.wikipedia.org/wiki/Michaelis%E2%80%93Menten_kinetics) is a simple description of an enzyme ($E$) transforming a substrate ($S$) into a product ($P$). Under certain assumptions it can be simplified to a singe function (a Michaelis-Menten function) and used as a reaction rate. Here we instead present the full system model:
51+
```@example crn_library_michaelis_menten
52+
using Catalyst
53+
mm_system = @reaction_network begin
54+
kB, S + E --> SE
55+
kD, SE --> S + E
56+
kP, SE --> P + E
1257
end
13-
p = (:c1 => 1.0, :c2 => 2.0, :c3 => 50.)
14-
tspan = (0.,4.)
15-
u0 = [:X => 5.]
58+
```
59+
Next, we perform ODE, SDE, and jump simulations of the model:
60+
```@example crn_library_michaelis_menten
61+
u0 = [:S => 301, :E => 100, :SE => 0, :P => 0]
62+
tspan = (0., 100.)
63+
ps = [:kB => 0.00166, :kD => 0.0001, :kP => 0.1]
1664
17-
# solve ODEs
18-
oprob = ODEProblem(rs, u0, tspan, p)
65+
using OrdinaryDiffEq
66+
oprob = ODEProblem(mm_system, u0, tspan, ps)
1967
osol = solve(oprob, Tsit5())
2068
21-
# solve for Steady states
22-
ssprob = SteadyStateProblem(rs, u0, p)
23-
sssol = solve(ssprob, SSRootfind())
69+
using StochasticDiffEq
70+
sprob = SDEProblem(mm_system, u0, tspan, ps)
71+
ssol = solve(sprob, ImplicitEM())
2472
25-
# solve SDEs
26-
sprob = SDEProblem(rs, u0, tspan, p)
27-
ssol = solve(sprob, EM(), dt=.01)
28-
29-
# solve JumpProblem
30-
u0 = [:X => 5]
31-
dprob = DiscreteProblem(rs, u0, tspan, p)
32-
jprob = JumpProblem(rs, dprob, Direct())
73+
using JumpProcesses
74+
dprob = DiscreteProblem(mm_system, u0, tspan, ps)
75+
jprob = JumpProblem(mm_system, dprob, Direct())
3376
jsol = solve(jprob, SSAStepper())
3477
35-
plot(plot(osol; title = "Reaction Rate Equation ODEs"),
36-
plot(ssol; title = "Chemical Langevin SDEs"),
37-
plot(jsol; title = "Stochastic Chemical Kinetics Jump Processes");
38-
layout = (3, 1))
78+
using Plots
79+
oplt = plot(osol; title = "Reaction rate equation (ODE)")
80+
splt = plot(ssol; title = "Chemical Langevin equation (SDE)")
81+
jplt = plot(jsol; title = "Stochastic chemical kinetics (Jump)")
82+
plot(oplt, splt, jplt; size=(800,700), layout = (3,1))
3983
```
4084

41-
## Example: Michaelis-Menten enzyme kinetics
42-
43-
```@example bcrn2
44-
using Catalyst, DifferentialEquations, Plots
45-
46-
rs = @reaction_network begin
47-
c1, S + E --> SE
48-
c2, SE --> S + E
49-
c3, SE --> P + E
85+
## SIR infection model
86+
The [SIR model](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SIR_model) is the simplest model of the spread of an infectious disease. While the real system is very different from the chemical and cellular processes typically modelled with CRNs, it (and several other epidemiological systems) can be modelled using the same CRN formalism. The SIR model consists of three species: susceptible ($S$), infected ($I$), and removed ($R$) individuals, and two reaction events: infection and recovery.
87+
```@example crn_library_sir
88+
using Catalyst
89+
sir_model = @reaction_network begin
90+
α, S + I --> 2I
91+
β, I --> R
5092
end
51-
p = (:c1 => 0.00166, :c2 => 0.0001, :c3 => 0.1)
52-
tspan = (0., 100.)
53-
u0 = [:S => 301., :E => 100., :SE => 0., :P => 0.]
93+
```
94+
First we perform a deterministic ODE simulation:
95+
```@example crn_library_sir
96+
using OrdinaryDiffEq, Plots
97+
u0 = [:S => 99, :I => 1, :R => 0]
98+
tspan = (0.0, 500.0)
99+
ps = [:α => 0.001, :β => 0.01]
54100
55-
# solve ODEs
56-
oprob = ODEProblem(rs, u0, tspan, p)
57-
osol = solve(oprob, Tsit5())
101+
# Solve ODEs.
102+
oprob = ODEProblem(sir_model, u0, tspan, ps)
103+
osol = solve(oprob, Tsit5())
104+
plot(osol; title = "Reaction rate equation (ODE)")
105+
```
106+
Next we perform 3 different Jump simulations. Note that for the stochastic model, the occurrence of a outbreak is not certain. Rather, there is a possibility that it fizzles out without a noteworthy peak.
107+
```@example crn_library_sir
108+
using JumpProcesses
109+
dprob = DiscreteProblem(sir_model, u0, tspan, ps)
110+
jprob = JumpProblem(sir_model, dprob, Direct())
58111
59-
# solve JumpProblem
60-
u0 = [:S => 301, :E => 100, :SE => 0, :P => 0]
61-
dprob = DiscreteProblem(rs, u0, tspan, p)
62-
jprob = JumpProblem(rs, dprob, Direct())
63-
jsol = solve(jprob, SSAStepper())
112+
jsol1 = solve(jprob, SSAStepper())
113+
jsol2 = solve(jprob, SSAStepper())
114+
jsol3 = solve(jprob, SSAStepper())
115+
jsol1 = solve(jprob, SSAStepper(); seed=1) # hide
116+
jsol2 = solve(jprob, SSAStepper(); seed=2) # hide
117+
jsol3 = solve(jprob, SSAStepper(); seed=3) # hide
64118
65-
plot(plot(osol; title = "Reaction Rate Equation ODEs"),
66-
plot(jsol; title = "Stochastic Chemical Kinetics Jump Processes");
67-
layout = (2, 1))
119+
jplt1 = plot(jsol1; title = "Outbreak")
120+
jplt2 = plot(jsol2; title = "Outbreak")
121+
jplt3 = plot(jsol3; title = "No outbreak")
122+
plot(jplt1, jplt2, jplt3; size=(800,700), layout = (3,1))
68123
```
69124

70-
## Example: SIR infection model
71-
```@example bcrn3
72-
using Catalyst, DifferentialEquations, Plots
125+
## The Wilhelm model
126+
The Wilhelm model was introduced in [*Wilhelm (2009)*](https://bmcsystbiol.biomedcentral.com/articles/10.1186/1752-0509-3-90) as the smallest CRN model (with constant rates) that exhibits bistability.
127+
```@example crn_library_wilhelm
128+
wilhelm_model = @reaction_network begin
129+
k1, Y --> 2X
130+
k2, 2X --> X + Y
131+
k3, X + Y --> Y
132+
k4, X --> 0
133+
end
134+
```
135+
We can simulate the model for two different initial conditions, demonstrating the existence of two different stable steady states.
136+
```@example crn_library_wilhelm
137+
using OrdinaryDiffEq, Plots
138+
u0_1 = [:X => 1.5, :Y => 0.5]
139+
u0_2 = [:X => 2.5, :Y => 0.5]
140+
tspan = (0., 10.)
141+
ps = [:k1 => 8.0, :k2 => 2.0, :k3 => 1.0, :k4 => 1.5]
73142
74-
rs = @reaction_network begin
75-
α, S + I --> 2I
76-
β, I --> R
143+
oprob1 = ODEProblem(wilhelm_model, u0_1, tspan, ps)
144+
oprob2 = ODEProblem(wilhelm_model, u0_2, tspan, ps)
145+
osol1 = solve(oprob1, Tsit5())
146+
osol2 = solve(oprob2, Tsit5())
147+
oplt1 = plot(osol1; idxs = :X, label = "X(0) = 1.5")
148+
oplt2 = plot!(osol2; idxs = :X, label = "X(0) = 2.5", yguide = "X", size = (800,700))
149+
```
150+
151+
## Simple self-activation loop
152+
The simplest self-activation loop consist of a single species (here called $X$) which activates its own production. If its production rate is modelled with a hill function with $n>1$, the system may exhibit bistability.
153+
```@example crn_library_self_activation
154+
using Catalyst
155+
sa_loop = @reaction_network begin
156+
v₀ + hill(X,v,K,n), ∅ --> X
157+
d, X --> ∅
77158
end
78-
p = [:α => .1/100, :β => .01]
79-
tspan = (0.0,500.0)
80-
u0 = [:S => 99.0, :I => 1.0, :R => 0.0]
159+
```
160+
A simple example of such a loop is a transcription factor which activates its own gene. Here, $v₀$ represents a basic transcription rate (leakage) in the absence of the transcription factor.
81161

82-
# Solve ODEs.
83-
oprob = ODEProblem(rs, u0, tspan, p)
84-
osol = solve(oprob)
162+
We simulate the self-activation loop from a single initial condition using both deterministic (ODE) and stochastic (jump) simulations. We note that while the deterministic simulation reaches a single steady state, the stochastic one switches between two different states.
163+
```@example crn_library_self_activation
164+
using OrdinaryDiffEq, Plots
165+
u0 = [:X => 4]
166+
tspan = (0.0, 1000.0)
167+
ps = [:v₀ => 0.1, :v => 2.0, :K => 10.0, :n => 2, :d => 0.1]
85168
86-
# Solve Jumps.
87-
dprob = DiscreteProblem(rs, u0, tspan, p)
88-
jprob = JumpProblem(rs, dprob, Direct())
169+
oprob = ODEProblem(sa_loop, u0, tspan, ps)
170+
osol = solve(oprob, Tsit5())
171+
172+
dprob = DiscreteProblem(sa_loop, u0, tspan, ps)
173+
jprob = JumpProblem(sa_loop, dprob, Direct())
89174
jsol = solve(jprob, SSAStepper())
175+
jsol = solve(jprob, SSAStepper(); seed = 2091) # hide
90176
91-
plot(plot(osol; title = "Reaction Rate Equation ODEs"),
92-
plot(jsol; title = "Stochastic Chemical Kinetics Jump Processes");
93-
layout = (2, 1))
177+
plot(osol; label = "Reaction rate equation (ODE)")
178+
plot!(jsol; label = "Stochastic chemical kinetics (Jump)", yguide = "X", size = (800,600))
94179
```
95180

96-
## Example: Brusselator chemical reaction network
97-
```@example bcrn4
98-
using Catalyst, DifferentialEquations, Plots
99-
100-
rs = @reaction_network begin
101-
@parameters A B
181+
## The Brusselator
182+
The [Brusselator](https://en.wikipedia.org/wiki/Brusselator) is a well known (theoretical) CRN model able to produce oscillations (its name is a portmanteau of "Brussels" and "oscillator").
183+
```@example crn_library_brusselator
184+
using Catalyst
185+
brusselator = @reaction_network begin
102186
A, ∅ --> X
103187
1, 2X + Y --> 3X
104188
B, X --> Y
105189
1, X --> ∅
106190
end
107-
tspan = (0.0,50.0)
191+
```
192+
It is generally known to (for reaction rate equation-based ODE simulations) produce oscillations when $B > 1 + A^2$. However, this results is based on models generated when *combinatorial adjustment of rates is not performed*. Since Catalyst automatically perform these adjustments, and one reaction contain a stoichiometric constant $>1$, the threshold will be different. Here, we trial two different values of $B$. In both cases, $B < 1 + A^2$, however, in he second case the system is able to generate oscillations.
193+
```@example crn_library_brusselator
194+
using OrdinaryDiffEq, Plots
108195
u0 = [:X => 1.0, :Y => 1.0]
196+
tspan = (0., 50.)
197+
ps1 = [:A => 1.0, :B => 1.0]
198+
ps2 = [:A => 1.0, :B => 1.8]
109199
110-
# Non-oscillation parameter set
111-
oprob1 = ODEProblem(rs, u0, tspan, [:A => 1.0, :B => 1.0])
112-
osol1 = solve(oprob1)
200+
oprob1 = ODEProblem(brusselator, u0, tspan, ps1)
201+
oprob2 = ODEProblem(brusselator, u0, tspan, ps2)
202+
osol1 = solve(oprob1, Rodas5P())
203+
osol2 = solve(oprob2, Rodas5P())
204+
oplt1 = plot(osol1; title = "No Oscillation")
205+
oplt2 = plot(osol2; title = "Oscillation")
113206
114-
# Oscillation parameter set
115-
oprob2 = ODEProblem(rs, u0, tspan, [:A => 1.0, :B => 3.0])
116-
osol2 = solve(oprob2)
207+
plot(oplt1, oplt2; layout = (1,2), size(800,700))
208+
```
209+
210+
## The repressilator
211+
The repressilator was introduced in [*Elowitz & Leibler (2000)*](https://www.nature.com/articles/35002125) as a simple system that is able to generate oscillations (most notably, they demonstrated this both in a model and in a synthetic in vivo implementation in *Escherichia col*). It consists of three genes, repressing each other in a cycle. Here, we will implement it using three species ($X$, $Y$, and $Z$) which production rates are (repressing) [Hill functions](https://en.wikipedia.org/wiki/Hill_equation_(biochemistry)).
212+
```@example crn_library_brusselator
213+
using Catalyst
214+
repressilator = @reaction_network begin
215+
hillr(Z,v,K,n), ∅ --> X
216+
hillr(X,v,K,n), ∅ --> Y
217+
hillr(Y,v,K,n), ∅ --> Z
218+
d, (X, Y, Z) --> ∅
219+
end
220+
```
221+
Whether it oscillates or not depends on its parameter values. Here, we will perform deterministic (ODE) simulations for two different values of $K$, showing that it oscillates for one value and not the other one. Next, we will perform stochastic (SDE) simulations for both $K$ values, showing that the stochastic model is able to sustain oscillations in both cases. This is an example of the phenomena of *noise-induced oscillation*.
222+
```@example crn_library_brusselator
223+
using OrdinaryDiffEq, StochasticDiffEq, Plots
224+
u0 = [:X => 50.0, :Y => 15.0, :Z => 15.0]
225+
tspan = (0., 200.)
226+
ps1 = [:v => 10.0, :K => 20.0, :n => 3, :d => 0.1]
227+
ps2 = [:v => 10.0, :K => 50.0, :n => 3, :d => 0.1]
228+
229+
oprob1 = ODEProblem(repressilator, u0, tspan, ps1)
230+
oprob2 = ODEProblem(repressilator, u0, tspan, ps2)
231+
osol1 = solve(oprob1, Tsit5())
232+
osol2 = solve(oprob2, Tsit5())
233+
oplt1 = plot(osol1; title = "Oscillation (ODE, K = 20)")
234+
oplt2 = plot(osol2; title = "No oscillation (ODE, K = 50)")
235+
236+
sprob1 = SDEProblem(repressilator, u0, tspan, ps1)
237+
sprob2 = SDEProblem(repressilator, u0, tspan, ps2)
238+
ssol1 = solve(sprob1, ImplicitEM())
239+
ssol2 = solve(sprob2, ImplicitEM())
240+
ssol1 = solve(sprob1, ImplicitEM(); seed = 1) # hide
241+
ssol2 = solve(sprob2, ImplicitEM(); seed = 100) # hide
242+
splt1 = plot(ssol1; title = "Oscillation (SDE, K = 20)")
243+
splt2 = plot(ssol2; title = "Oscillation (SDE, K = 50)")
244+
245+
plot(oplt1, oplt2, splt1, splt2; layout = (2,2), size = (800,600))
246+
```
247+
248+
## The Willamowski–Rössler model
249+
The Willamowski–Rössler model was introduced in [*Willamowski & Rössler (1979)*](https://www.degruyter.com/document/doi/10.1515/zna-1980-0308/html?lang=en) as an example of a simple CRN model which exhibits [*chaotic behaviours*](https://en.wikipedia.org/wiki/Chaos_theory). This means that small changes in initial conditions can produce relatively large changes in the system's trajectory.
250+
```@example crn_library_chaos
251+
using Catalyst
252+
wr_model = @reaction_network begin
253+
k1, 2X --> 3X
254+
k2, X --> 2X
255+
k3, Z + 2X --> 2Z
256+
k4, Y + X --> 2Y
257+
k5, Y --> ∅
258+
k6, 2Z --> ∅
259+
k7, Z --> ∅
260+
end
261+
```
262+
Here we first simulate the model for a single initial conditions, showing in both time-state space and phase space how how it reaches a [*strange attractor*](https://www.dynamicmath.xyz/strange-attractors/).
263+
```@example crn_library_chaos
264+
using OrdinaryDiffEq, Plots
265+
u0 = [:X => 1.5, :Y => 1.5, :Z => 1.5]
266+
tspan = (0.0, 50.0)
267+
p = [:k1 => 2.1, :k2 => 0.7, :k3 => 2.9, :k4 => 1.1, :k5 => 1.0, :k6 => 0.5, :k7 => 2.7]
268+
oprob = ODEProblem(wr_model, u0, tspan, p)
269+
sol = solve(oprob, Rodas5P())
117270
118-
plot(plot(osol1; title = "No oscillation (B < 1 + A^2)"),
119-
plot(osol2; title = "Oscillation (B > 1 + A^2)");
120-
layout = (2, 1))
271+
plt1 = plot(sol; title = "Time-state space")
272+
plt2 = plot(sol; idxs = (:X, :Y, :Z), title = "Phase space")
273+
plot(plt1, plt2; layout = (1,2), size = (800,400))
121274
```

0 commit comments

Comments
 (0)