Skip to content

Commit f6e847b

Browse files
authored
Merge pull request #919 from isaacsas/update_smol_tutorial
Update smol tutorial
2 parents bc6d339 + 7cac054 commit f6e847b

File tree

3 files changed

+69
-53
lines changed

3 files changed

+69
-53
lines changed

docs/pages.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ pages = Any[
1818
"Model creation examples" => Any[
1919
"model_creation/examples/basic_CRN_library.md",
2020
"model_creation/examples/programmatic_generative_linear_pathway.md",
21-
"model_creation/examples/hodgkin_huxley_equation.md" #"model_creation/examples/smoluchowski_coagulation_equation.md"
21+
"model_creation/examples/hodgkin_huxley_equation.md",
22+
"model_creation/examples/smoluchowski_coagulation_equation.md"
2223
]
2324
],
2425
"Model simulation" => Any[

docs/src/assets/Project.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
55
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
66
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
77
DiffEqParamEstim = "1130ab10-4a5a-5621-a13d-e4788d82bd4c"
8-
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
98
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
109
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
1110
DynamicalSystems = "61744808-ddfa-5f27-97ff-6e42cc95d634"
@@ -38,7 +37,7 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
3837

3938
[compat]
4039
BenchmarkTools = "1.5"
41-
BifurcationKit = "0.3"
40+
BifurcationKit = "0.3.4"
4241
CairoMakie = "0.12"
4342
Catalyst = "13"
4443
DataFrames = "1.6"

docs/src/model_creation/examples/smoluchowski_coagulation_equation.md

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,72 +4,89 @@ This tutorial shows how to programmatically construct a [`ReactionSystem`](@ref)
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.
55

66
We begin by importing some necessary packages.
7-
```julia
7+
```@example smcoag1
88
using ModelingToolkit, Catalyst, LinearAlgebra
9-
using DiffEqBase, JumpProcesses
9+
using JumpProcesses
1010
using Plots, SpecialFunctions
1111
```
1212
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
13+
```@example smcoag1
14+
# maximum cluster size
15+
N = 10
16+
17+
# volume of a monomers in cm³
18+
Vₒ = (4π / 3) * (10e-06 * 100)^3
19+
20+
# initial conc. = (No. of init. monomers) / bulk volume
21+
Nₒ = 1e-06 / Vₒ
22+
23+
# No. of monomers initially
24+
uₒ = 10000
25+
26+
# Bulk volume of system in cm³
27+
V = uₒ / Nₒ
28+
n = floor(Int, N / 2)
29+
30+
# No. of forward reactions
31+
nr = ((N % 2) == 0) ? (n*(n + 1) - n) : (n*(n + 1))
32+
nothing #hide
2433
```
2534
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ⱼ`
2635

27-
```julia
36+
```@example smcoag1
2837
# possible pairs of reactant multimers
2938
pair = []
3039
for i = 2:N
31-
push!(pair, [1:integ(i/2) i .- (1:integ(i/2))])
40+
halfi = floor(Int, i/2)
41+
push!(pair, [(1:halfi) (i .- (1:halfi))])
3242
end
3343
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⁻³
44+
vᵢ = @view pair[:, 1] # Reactant 1 indices
45+
vⱼ = @view pair[:, 2] # Reactant 2 indices
46+
volᵢ = Vₒ * vᵢ # cm⁻³
47+
volⱼ = Vₒ * vⱼ # cm⁻³
3848
sum_vᵢvⱼ = @. vᵢ + vⱼ # Product index
49+
nothing #hide
3950
```
4051
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
52+
```@example smcoag1
4253
# set i to 1 for additive kernel, 2 for constant
4354
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
55+
if i == 1
56+
B = 1.53e03 # s⁻¹
57+
58+
# dividing by volume as it is a bimolecular reaction chain
59+
kv = @. B * (volᵢ + volⱼ) / V
4760
elseif i==2
48-
C = 1.84e-04 # cm³ s⁻¹
49-
kv = fill(C/V, nr)
61+
C = 1.84e-04 # cm³ s⁻¹
62+
kv = fill(C / V, nr)
5063
end
64+
nothing #hide
5165
```
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-
# unknown variables are X, pars stores rate parameters for each rx
66+
We'll set the parameters and the initial condition that only monomers are present at ``t=0`` in `u₀map`.
67+
```@example smcoag1
68+
# k is a vector of the parameters, with values given by the vector kv
69+
@parameters k[1:nr] = kv
70+
71+
# create the vector of species X_1,...,X_N
5572
t = default_t()
56-
@species k[1:nr] (X(t))[1:N]
57-
pars = Pair.(collect(k), kv)
73+
@species (X(t))[1:N]
5874
5975
# time-span
6076
if i == 1
61-
tspan = (0. ,2000.)
77+
tspan = (0.0, 2000.0)
6278
elseif i == 2
63-
tspan = (0. ,350.)
79+
tspan = (0.0, 350.0)
6480
end
6581
6682
# initial condition of monomers
6783
u₀ = zeros(Int64, N)
6884
u₀[1] = uₒ
69-
u₀map = Pair.(collect(X), u₀) # map variable to its initial value
85+
u₀map = Pair.(collect(X), u₀) # map species to its initial value
86+
nothing #hide
7087
```
7188
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
89+
```@example smcoag1
7390
# vector to store the Reactions in
7491
rx = []
7592
for n = 1:nr
@@ -82,19 +99,21 @@ for n = 1:nr
8299
end
83100
end
84101
@named rs = ReactionSystem(rx, t, collect(X), collect(k))
102+
rs = complete(rs)
85103
```
86104
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://docs.sciml.ai/DiffEqDocs/stable/types/jump_types/) documentation
87-
```julia
105+
```@example smcoag1
88106
# 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)
107+
jumpsys = complete(convert(JumpSystem, rs))
108+
dprob = DiscreteProblem(rs, u₀map, tspan)
109+
jprob = JumpProblem(jumpsys, dprob, Direct(), save_positions = (false, false))
110+
jsol = solve(jprob, SSAStepper(), saveat = tspan[2] / 30)
111+
nothing #hide
93112
```
94113
Lets check the results for the first three polymers/cluster sizes. We compare to the analytical solution for this system:
95-
```julia
114+
```@example smcoag1
96115
# Results for first three polymers...i.e. monomers, dimers and trimers
97-
v_res = [1;2;3]
116+
v_res = [1; 2; 3]
98117
99118
# comparison with analytical solution
100119
# we only plot the stochastic solution at a small number of points
@@ -114,20 +133,17 @@ elseif i == 2
114133
end
115134
116135
# plotting normalised concentration vs analytical solution
117-
default(lw=2, xlabel="Time (sec)")
118-
scatter(ϕ, jsol(t)[1,:]/uₒ, label="X1 (monomers)", markercolor=:blue)
136+
default(lw = 2, xlabel = "Time (sec)")
137+
scatter(ϕ, jsol(t)[1,:] / uₒ, label = "X1 (monomers)", markercolor = :blue)
119138
plot!(ϕ, sol[1,:]/Nₒ, line = (:dot,4,:blue), label="Analytical sol--X1")
120139
121-
scatter!(ϕ, jsol(t)[2,:]/uₒ, label="X2 (dimers)", markercolor=:orange)
122-
plot!(ϕ, sol[2,:]/Nₒ, line = (:dot,4,:orange), label="Analytical sol--X2")
140+
scatter!(ϕ, jsol(t)[2,:] / uₒ, label = "X2 (dimers)", markercolor = :orange)
141+
plot!(ϕ, sol[2,:] / Nₒ, line = (:dot, 4, :orange), label = "Analytical sol--X2")
123142
124-
scatter!(ϕ, jsol(t)[3,:]/uₒ, label="X3 (trimers)", markercolor=:purple)
125-
plot!(ϕ, sol[3,:]/Nₒ, line = (:dot,4,:purple), label="Analytical sol--X3",
143+
scatter!(ϕ, jsol(t)[3,:] / uₒ, label = "X3 (trimers)", markercolor = :purple)
144+
plot!(ϕ, sol[3,:] / Nₒ, line = (:dot, 4, :purple), label = "Analytical sol--X3",
126145
ylabel = "Normalized Concentration")
127146
```
128-
For the **additive kernel** we find
129-
130-
![additive_kernel](../../assets/additive_kernel.svg)
131147

132148
---
133149
## References

0 commit comments

Comments
 (0)