Skip to content

Commit fe29787

Browse files
committed
better file name
1 parent 9356ed1 commit fe29787

File tree

1 file changed

+274
-0
lines changed

1 file changed

+274
-0
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
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.
3+
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+
```
48+
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
57+
end
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]
64+
65+
using OrdinaryDiffEq
66+
oprob = ODEProblem(mm_system, u0, tspan, ps)
67+
osol = solve(oprob, Tsit5())
68+
69+
using StochasticDiffEq
70+
sprob = SDEProblem(mm_system, u0, tspan, ps)
71+
ssol = solve(sprob, ImplicitEM())
72+
73+
using JumpProcesses
74+
dprob = DiscreteProblem(mm_system, u0, tspan, ps)
75+
jprob = JumpProblem(mm_system, dprob, Direct())
76+
jsol = solve(jprob, SSAStepper())
77+
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))
83+
```
84+
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
92+
end
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]
100+
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())
111+
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
118+
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))
123+
```
124+
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]
142+
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 --> ∅
158+
end
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.
161+
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]
168+
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())
174+
jsol = solve(jprob, SSAStepper())
175+
jsol = solve(jprob, SSAStepper(); seed = 2091) # hide
176+
177+
plot(osol; label = "Reaction rate equation (ODE)")
178+
plot!(jsol; label = "Stochastic chemical kinetics (Jump)", yguide = "X", size = (800,600))
179+
```
180+
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
186+
A, ∅ --> X
187+
1, 2X + Y --> 3X
188+
B, X --> Y
189+
1, X --> ∅
190+
end
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
195+
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]
199+
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")
206+
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())
270+
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))
274+
```

0 commit comments

Comments
 (0)