Skip to content

Commit 3479ed8

Browse files
authored
docs: update README and examples (#8)
1 parent 4322cf4 commit 3479ed8

File tree

4 files changed

+116
-156
lines changed

4 files changed

+116
-156
lines changed

README.md

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,68 +29,60 @@ the state of host population can also be represented as a vector
2929
by concatenating the state of each component of host `u = vcat(S, vec(I), vec(R))`,
3030
where `S` is a vector of length `n` and `I`, `R` are matrixes of size `n × m`.
3131
However, in evolutionary biology,
32-
the "mutation" and "extinction" will change the types of "hosts" and "viruses",
32+
the "mutation" and "extinction" will change the types of hosts and viruses,
3333
which means the `n` and `m` changes during the evolution,
3434
and the length of the state vector `u` will also change.
3535

3636
## How to use?
3737

38-
Similarly to `DifferentialEquations.jl`,
39-
you must define reactions firstly (jump in `DifferentialEquations.jl`),
40-
For example, the infect reaction of above SIR model is defined as:
38+
The package [`Catalyst.jl`](https://github.com/SciML/Catalyst.jl) provides a simple way
39+
to build biochemical reaction for `DifferentialEquations.jl`.
40+
Similarly, this package provides a macro `@reaction_eq` which generate reaction(s),
41+
with given equation.
4142

43+
For example, the infect reaction of above SIR model with multi-type of viruses can be defined as:
4244
```julia
43-
# reaction: S_i + I_ij -> 2I_ij
44-
@cfunc infect_c(β, S, I) = β * S' * I # function to calculate the rate of infection
45-
@ufunc function infect_u!(ind, S, I) # function to update the state when infection happens
46-
# ind is the index of the reaction selected with weight calculated by `infect_c`
47-
S[ind[2]] -= 1 # S_j -= 1
48-
I[ind] += 1 # I_ij += 1
49-
return nothing
50-
end
51-
infect = Reaction(infect_c, infect_u!)
45+
@reaction_eq infect β S + I[i] --> 2I[i]
5246
```
47+
where `i` donates the virus type. The equation `S + I[i] --> 2I[i]` means
48+
the an host infected by the virus `i` infect a susceptible host with rate `β`,
49+
then convert the the susceptible host to a infectious host.
50+
This expression will not only generate one reaction but a group of reactions trough the index `i`.
5351

54-
where `@cfunc` is a macro to help you define a function to calculate the rate of reaction,
55-
`@ufunc` is a macro to help you define a function to update the state when reaction happens.
56-
Unlike `DifferentialEquations.jl`, the "calculate" function returns an array of rates,
57-
which allows variable length state and contains a lot sub-reactions.
58-
Additionally, the "update" function accepts a special argument `ind`,
59-
which tells you which sub-reaction is selected and should always be the first argument.
60-
All of these is designed to work with variable length state.
61-
62-
Besides, there is another macro `@reaction` helps you define a reaction more easily.
63-
The below code is equivalent to the above code:
64-
52+
However, the mutation and extinction can not be defined easily by the macro `@reaction_eq` currently.
53+
Thus the alternative macro `@reaction` provides a low-level way to build reaction(s)
6554
```julia
66-
@reaction infect begin
67-
β * S' * I
55+
@reaction mutation begin
56+
@quickloop μ * I[i]
6857
begin
69-
S[ind[2]] -= 1
70-
I[ind] += 1
58+
i = ind[1]
59+
I[i] -= 1 # the host individual is converted to another type
60+
push!(I, 1) # add a new type of infectious host to the system
61+
push!(α, randn() + α[i]) # the virulence of the new host type is generated randomly with mean `α[i]`
7162
end
7263
end
7364
```
65+
This expression defined mutation of virus which contains two parts:
66+
1. The `@quickloop μ * I[i]` defines how to calculate the rate of mutation,
67+
2. The `begin ... end` block defines what happens when the host is mutated,
68+
where `ind` is a preserved variable which is used to store the index of the mutated host.
7469

7570
Once you have defined all reactions, put them together as a tuple:
76-
7771
```julia
78-
reactions = (infect, ...)
72+
reactions = (infect, mutation, ...)
7973
```
80-
8174
and define the initial state and parameters of the system as a named tuple:
82-
8375
```julia
84-
params == 0.1, ..., S = [100], I = [1;;], R = [0;;]) # the [1;;] syntax requires Julia >= 1.7
76+
params == 0.1, μ = 0.001, ..., S = scalar(100), I = [1], R = [0], α = [0.5])
8577
```
78+
where the `scalar` will create a type similar to `Number`,
79+
but it can be update in-place like `Ref` like `S[] += 1`.
8680

87-
Then, you can use `gillespie` to simulate the system:
88-
81+
Once reaction and parameters is defined, you can use `gillespie` to simulate the system:
8982
```julia
9083
max_time = 100 # the maximum time of simulation
9184
params′, t, term = gillespie(max_time, params, reactions)
9285
```
93-
9486
where the `gillespie` function returns an tuple `t, ps′, term`
9587
where `t` is the time when the simulation ends, `params′` is an updated `params`,
9688
and `term` is a flag indicating whether the simulation is finished after the maximum time
@@ -102,15 +94,13 @@ but you can use my another package `RecordedArrays` to record them, like this:
10294
```julia
10395
using RecordedArrays
10496
c = DiscreteClock(max_time) # clock store information of max_time
105-
S = recorded(DynamicEntry, c, [100]) # create a recorded vector as S with the clock c
106-
I = recorded(DynamicEntry, c, [1;;]) # create a recorded matrix as I with the clock c
107-
R = recorded(DynamicEntry, c, [0;;]) # create a recorded matrix as R with the clock c
108-
params = (; β = 0.1, ..., S, I, R) # create new params with recorded S, I, R
97+
S = recorded(DynamicEntry, c, 100) # create a recorded number as S with the clock c
98+
I = recorded(DynamicEntry, c, [1]) # create a recorded vector as I with the clock c
99+
R = recorded(DynamicEntry, c, [0]) # create a recorded vector as R with the clock c
100+
α = recorded(StaticEntry, c, [0.5]) # create a recorded vector as α with the clock c
101+
params = (; β = 0.1, μ = 0.001, ..., S, I, R, α) # create new params with recorded S, I, R, α
109102
gillespie(c, params, reactions) # run the simulation with the clock and new params
110103
```
111104

112105
More information about `RecordedArrays`, see its
113106
[documentation](https://wangl-cc.github.io/RecordedArrays.jl/dev).
114-
115-
Examples and references of this package can be found in
116-
[documentation](https://wangl-cc.github.io/EvolutionaryModelingTools.jl/dev).

docs/src/example.md

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ ps = (; r, d, K, x) # define the parameters for the model
4747
rs = (growth, death, comp) # define the reactions for the model
4848
4949
# simulate
50-
Random.seed!(1)
51-
ps_new, t, state = gillespie(c, ps, rs)
50+
ps_new, t, state = gillespie(MersenneTwister(1), c, ps, rs)
5251
5352
# plot
5453
timeseries(ps_new.x;
@@ -134,12 +133,88 @@ ps = (; r, d, K, μ, x, m) # define the parameters for the model
134133
rs = (growth, mutation, competition) # define the reactions for the model
135134
136135
# simulate
137-
Random.seed!(1)
138-
ps_new, t, state = gillespie(check_extinction, c, ps, rs)
136+
ps_new, t, state = gillespie(check_extinction, MersenneTwister(1), c, ps, rs)
139137
140138
# plot
141139
timeseries(ps_new.x;
142140
grid=false, frame=:box, legend=false,
143141
title="Population Dynamics", xlabel="Time", ylabel="Population Size",
144142
)
145143
```
144+
145+
## SIR model with vital dynamics and logistic population
146+
147+
A simple SIR model with vital dynamics and logistic population,
148+
where the host population follows the logistic growth model.
149+
150+
This model may contains more reactions than the previous example,
151+
which can be generated easily by `@reaction_eq`.
152+
153+
The deterministic differential equation of this model is:
154+
155+
```math
156+
\begin{aligned}
157+
\dot{S} &= r (S + I + R) - S(d + c (S + I + R) + \beta I) \\
158+
\dot{I} &= I (\beta S - d - c (S + I + R) - \nu) \\
159+
\dot{R} &= R (\nu - d - c (S + I + R))
160+
\end{aligned}
161+
```
162+
163+
```@example sir_with_vital_dynamics_and_logistic_population
164+
using RecordedArrays
165+
using EvolutionaryModelingTools
166+
using Random
167+
using Plots
168+
169+
const T = 100.0
170+
const β = 0.005
171+
const ν = 0.01
172+
const α = 0.2
173+
const r = 0.5
174+
const d = 0.1
175+
const c = 0.001
176+
const S = 100
177+
const I = 10
178+
const R = 0
179+
180+
# epidemic dynamics
181+
@reaction_eq infection β S + I --> I + I
182+
@reaction_eq recovery ν I --> R
183+
@reaction_eq virulence α I --> 0 # death of infection host caused by virus
184+
# demography dynamics, generate reactions with @eval
185+
for sym in (:S, :I, :R)
186+
r_name = Symbol(:growth_, sym)
187+
d_name = Symbol(:death_, sym)
188+
@eval @reaction_eq $r_name r $sym --> S + $sym # growth
189+
@eval @reaction_eq $d_name d $sym --> 0 # death
190+
for sym′ in (:S, :I, :R)
191+
c_name = Symbol(:competition_, sym, sym′)
192+
@eval @reaction_eq $c_name c $sym + $sym′ --> $sym′ # competition
193+
end
194+
end
195+
196+
const REACTIONS = (
197+
infection, recovery, virulence,
198+
growth_S, growth_I, growth_R,
199+
death_S, death_I, death_R,
200+
competition_SS, competition_SI, competition_SR,
201+
competition_IS, competition_II, competition_IR,
202+
competition_RS, competition_RI, competition_RR
203+
)
204+
205+
clock = ContinuousClock(T)
206+
ps = (;β, ν, α, r, d, c,
207+
S=recorded(DynamicEntry, clock, S),
208+
I=recorded(DynamicEntry, clock, I),
209+
R=recorded(DynamicEntry, clock, R),
210+
)
211+
ps_new, t, term = gillespie(MersenneTwister(1), clock, ps, REACTIONS)
212+
213+
plt = plot(grid=false, frame=:box,
214+
title="Population Dynamics", xlabel="Time", ylabel="Population Size"
215+
)
216+
timeseries!(plt, ps_new.S; label="S")
217+
timeseries!(plt, ps_new.I; label="I")
218+
timeseries!(plt, ps_new.R; label="R")
219+
plt
220+
```

docs/src/index.md

Lines changed: 0 additions & 106 deletions
This file was deleted.

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../README.md

example/sir.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ using EvolutionaryModelingTools
44
using EvolutionaryModelingTools.Scalar
55

66
# parameters
7-
const T = 100.0
8-
const β = 0.001
9-
const ν = 0.01
7+
const T = 10.0
8+
const β = 0.005
9+
const ν = 0.1
1010
const α = 0.2
1111
const r = 0.5
1212
const d = 0.1

0 commit comments

Comments
 (0)