Skip to content

Commit 45869f3

Browse files
authored
Merge pull request #307 from yewalenikhil65/master
Generating reactions programmatically using Reaction Systems
2 parents ef2d280 + dfc6982 commit 45869f3

File tree

3 files changed

+356
-1
lines changed

3 files changed

+356
-1
lines changed

docs/make.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ makedocs(
5050
"tutorials/generated_systems.md",
5151
"tutorials/advanced_examples.md",
5252
"tutorials/bifurcation_diagram.md",
53-
"tutorials/parameter_estimation.md"
53+
"tutorials/parameter_estimation.md",
54+
"tutorials/generating_reactions_programmatically.md"
5455
],
5556
"API" => Any[
5657
"api/catalyst_api.md"

docs/src/assets/additive_kernel.svg

Lines changed: 219 additions & 0 deletions
Loading
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Generating ReactionSystems Programmatically
2+
This tutorial shows how to programmatically construct a `ReactionSystem` 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`, 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)).
3+
4+
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.
5+
6+
We begin by importing some necessary packages.
7+
```julia
8+
using ModelingToolkit, Catalyst, LinearAlgebra
9+
using DiffEqBase, DiffEqJump
10+
using Plots, SpecialFunctions
11+
```
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
13+
```julia
14+
## Parameter
15+
N = 10 # maximum cluster size
16+
Vₒ = (4π/3)*(10e-06*100)^3 # volume of a monomers in cm³
17+
Nₒ = 1e-06/Vₒ # initial conc. = (No. of init. monomers) / bulk volume
18+
uₒ = 10000 # No. of monomers initially
19+
V = uₒ/Nₒ # Bulk volume of system in cm³
20+
21+
integ(x) = Int(floor(x))
22+
n = integ(N/2)
23+
nr = N%2 == 0 ? (n*(n + 1) - n) : (n*(n + 1)) # No. of forward reactions
24+
```
25+
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+
27+
```julia
28+
# possible pairs of reactant multimers
29+
pair = []
30+
for i = 2:N
31+
push!(pair,[1:integ(i/2) i .- (1:integ(i/2))])
32+
end
33+
pair = vcat(pair...)
34+
vᵢ = @view pair[:,1] # Reactant 1 indices
35+
vⱼ = @view pair[:,2] # Reactant 2 indices
36+
volᵢ = Vₒ*vᵢ # cm⁻³
37+
volⱼ = Vₒ*vⱼ # cm⁻³
38+
sum_vᵢvⱼ = @. vᵢ + vⱼ # Product index
39+
```
40+
We next specify the rates (i.e. kernel) at which reactants collide to form products. For simplicity, we allow a user-selected additive kernel or constant kernel. The constants(`B` and `C`) are adopted from Scott's paper [2](https://journals.ametsoc.org/view/journals/atsc/25/1/1520-0469_1968_025_0054_asocdc_2_0_co_2.xml)
41+
```julia
42+
# set i to 1 for additive kernel, 2 for constant
43+
i = 1
44+
if i==1
45+
B = 1.53e03 # s⁻¹
46+
kv = @. B*(volᵢ + volⱼ)/V # dividing by volume as its a bi-molecular reaction chain
47+
elseif i==2
48+
C = 1.84e-04 # cm³ s⁻¹
49+
kv = fill(C/V, nr)
50+
end
51+
```
52+
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`.
53+
```julia
54+
# state variables are X, pars stores rate parameters for each rx
55+
@parameters t
56+
@variables k[1:nr] X[collect(1:N)](t)
57+
pars = Pair.(k, kv)
58+
59+
# time-span
60+
if i == 1
61+
tspan = (0. ,2000.)
62+
elseif i == 2
63+
tspan = (0. ,350.)
64+
end
65+
66+
# initial condition of monomers
67+
u₀ = zeros(Int64, N)
68+
u₀[1] = uₒ
69+
u₀map = Pair.(X, u₀) # map variable to its initial value
70+
```
71+
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.
72+
```julia
73+
# vector to store the Reactions in
74+
rx = []
75+
for n = 1:nr
76+
# for clusters of the same size, double the rate
77+
if (vᵢ[n] == vⱼ[n])
78+
push!(rx, Reaction(k[n], [X[vᵢ[n]]], [X[sum_vᵢvⱼ[n]]], [2], [1]))
79+
else
80+
push!(rx, Reaction(k[n], [X[vᵢ[n]], X[vⱼ[n]]], [X[sum_vᵢvⱼ[n]]],
81+
[1, 1], [1]))
82+
end
83+
end
84+
rs = ReactionSystem(rx, t, X, k)
85+
```
86+
We now convert the `ReactionSystem` into a `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
87+
```julia
88+
# solving the system
89+
jumpsys = convert(JumpSystem, rs)
90+
dprob = DiscreteProblem(jumpsys, u₀map, tspan, pars)
91+
jprob = JumpProblem(jumpsys, dprob, Direct(), save_positions=(false,false))
92+
jsol = solve(jprob, SSAStepper(), saveat = tspan[2]/30)
93+
```
94+
Lets check the results for the first three polymers/cluster sizes. We compare to the analytical solution for this system:
95+
```julia
96+
# Results for first three polymers...i.e. monomers, dimers and trimers
97+
v_res = [1;2;3]
98+
99+
# comparison with analytical solution
100+
# we only plot the stochastic solution at a small number of points
101+
# to ease distinguishing it from the exact solution
102+
t = jsol.t
103+
sol = zeros(length(v_res), length(t))
104+
if i == 1
105+
ϕ = @. 1 - exp(-B*Nₒ*Vₒ*t)
106+
for j in v_res
107+
sol[j,:] = @. Nₒ*(1 - ϕ)*(((j*ϕ)^(j-1))/gamma(j+1))*exp(-j*ϕ)
108+
end
109+
elseif i == 2
110+
ϕ = @. (C*Nₒ*t)
111+
for j in v_res
112+
sol[j,:] = @. 4Nₒ*((ϕ^(j-1))/((ϕ + 2)^(j+1)))
113+
end
114+
end
115+
116+
# plotting normalised concentration vs analytical solution
117+
default(lw=2, xlabel="Time (sec)")
118+
scatter(ϕ, jsol(t)[1,:]/uₒ, label="X1 (monomers)", markercolor=:blue)
119+
plot!(ϕ, sol[1,:]/Nₒ, line = (:dot,4,:blue), label="Analytical sol--X1")
120+
121+
scatter!(ϕ, jsol(t)[2,:]/uₒ, label="X2 (dimers)", markercolor=:orange)
122+
plot!(ϕ, sol[2,:]/Nₒ, line = (:dot,4,:orange), label="Analytical sol--X2")
123+
124+
scatter!(ϕ, jsol(t)[3,:]/uₒ, label="X3 (trimers)", markercolor=:purple)
125+
plot!(ϕ, sol[3,:]/Nₒ, line = (:dot,4,:purple), label="Analytical sol--X3",
126+
ylabel = "Normalized Concentration")
127+
```
128+
For the **additive kernel** we find
129+
130+
![additive_kernel](../assets/additive_kernel.svg)
131+
132+
## Sources
133+
1. https://en.wikipedia.org/wiki/Smoluchowski_coagulation_equation
134+
2. Scott, W. T. (1968). Analytic Studies of Cloud Droplet Coalescence I, Journal of Atmospheric Sciences, 25(1), 54-65. Retrieved Feb 18, 2021, from https://journals.ametsoc.org/view/journals/atsc/25/1/1520-0469_1968_025_0054_asocdc_2_0_co_2.xml
135+
3. Ian J. Laurenzi, John D. Bartels, Scott L. Diamond, A General Algorithm for Exact Simulation of Multicomponent Aggregation Processes, Journal of Computational Physics, Volume 177, Issue 2, 2002, Pages 418-449, ISSN 0021-9991, https://doi.org/10.1006/jcph.2002.7017.

0 commit comments

Comments
 (0)