Skip to content

Commit edba70e

Browse files
authored
Merge pull request #844 from SciML/programmatic_generative_modelling_example
Programmatic generative modelling example
2 parents fb529e9 + da186b6 commit edba70e

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

docs/pages.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pages = Any[
1919
"model_creation/chemistry_related_functionality.md",
2020
"Model creation examples" => Any[
2121
"model_creation/examples/basic_CRN_examples.md",
22+
"model_creation/examples/programmatic_generative_linear_pathway.md",
2223
"model_creation/examples/hodgkin_huxley_equation.md",
2324
"model_creation/examples/smoluchowski_coagulation_equation.md"
2425
]
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# [Programmatic, generative, modelling of a linear pathway](@id programmatic_generative_linear_pathway)
2+
This example will show how to use programmatic, generative, modelling to model a system implicitly. I.e. rather than listing all system reactions explicitly, the reactions are implicitly generated from a simple set of rules. This example is specifically designed to show how [programmatic modelling](@ref ref) enables *generative workflows* (demonstrating one of its advantages as compared to [DSL-based modelling](@ref ref)). In our example, we will model linear pathways, so we will first introduce these. Next, we will model them first using the DSL, and then using a generative programmatic workflow.
3+
4+
## [Linear pathways](@id programmatic_generative_linear_pathway_intro)
5+
Linear pathways consists of a series of species ($X_0$, $X_1$, $X_2$, ..., $X_n$) where each activates the subsequent one. These are often modelled through the following reaction system:
6+
```math
7+
X_{i-1}/\tau,\hspace{0.33cm} ∅ \to X_{i}\\
8+
1/\tau,\hspace{0.33cm} X_{i} \to ∅
9+
```
10+
for $i = 1, ..., n$, where the activation of $X_1$ depends on some input species $X_0$.
11+
12+
A common use of these linear pathways is the implementation of *time delays*. Consider a species $X(t)$ which is activated by species $X_0(t)$. This can be modelled by making the production rate of $X(t)$ a function of the *time-delayed* value of $X_0(t)$:
13+
```math
14+
f(X_0(t-\tau)),\hspace{0.33cm} ∅ \to X
15+
```
16+
This is a so-called *discrete-delay* (which will generate a *delay differential equation*). However, in reality, $X(t)$ probably does not depend on only $f(X_0(t-\tau))$, but rather *a distribution of previous $X_0(t)$ values*. This can be modelled through a *distributed delay*s
17+
```math
18+
f(\int_{0}^{\inf} X_0(t-\tau)g(\tau) d\tau),\hspace{0.33cm} ∅ \to X
19+
```
20+
for some kernel $g(\tau)$. Here, a common kernel is a [gamma distribution](https://en.wikipedia.org/wiki/Gamma_distribution), which generates a gamma-distributed delay:
21+
```math
22+
g(\tau; \alpha, \beta) = \frac{\beta^{\alpha}\tau^{\alpha-1}}{\Gamma(\alpha)}e^{-\beta\tau}
23+
```
24+
When this is converted to an ODE, this generates an integro-differential equation. These (as well as the simpler delay differential equations) can be difficult to solve and analyse (especially when SDE or jump simulations are desired). Here, *the linear chain trick* can be used to instead model the delay as a linear pathway of the form described above[^1]. A result by Fargue shows that this is equivalent to a gamma-distributed delay, where $\alpha$ is equivalent to $n$ (the number of species in our linear pathway) and $\beta$ to %\tau$ (the delay length term)[^2]. While modelling time delays using the linear chain trick introduces additional system species, it is often advantageous as it enables simulations using standard ODE, SDE, and Jump methods.
25+
26+
## [Modelling linear pathways using the DSL](@id programmatic_generative_linear_pathway_dsl)
27+
It is known that two linear pathways have similar delays if the following equality holds:
28+
```math
29+
\frac{1}{\tau_1 n_1} = \frac{1}{\tau_2 n_2}
30+
```
31+
However, the shape of the delay depends on the number of intermediaries ($n$). Here we wish to investigate this shape for two choices of $n$ ($n = 3$ and $n = 10$). We do so by implementing two models using the DSL, one for each $n$.
32+
```@example programmatic_generative_linear_pathway_dsl
33+
using Catalyst
34+
35+
lp_n3 = @reaction_network begin
36+
1/τ, X0 --> 0
37+
(X0/τ, 1/τ), 0 <--> X1
38+
(X1/τ, 1/τ), 0 <--> X2
39+
(X2/τ, 1/τ), 0 <--> X3
40+
end
41+
42+
lp_n10 = @reaction_network begin
43+
1/τ, X0 --> 0
44+
(X0/τ, 1/τ), 0 <--> X1
45+
(X1/τ, 1/τ), 0 <--> X2
46+
(X2/τ, 1/τ), 0 <--> X3
47+
(X3/τ, 1/τ), 0 <--> X4
48+
(X4/τ, 1/τ), 0 <--> X5
49+
(X5/τ, 1/τ), 0 <--> X6
50+
(X6/τ, 1/τ), 0 <--> X7
51+
(X7/τ, 1/τ), 0 <--> X8
52+
(X8/τ, 1/τ), 0 <--> X9
53+
(X9/τ, 1/τ), 0 <--> X10
54+
end
55+
nothing # hide
56+
```
57+
Next, we prepare an ODE for each model (scaling the initial concentration of $X_0$ and the value of $\tau$ appropriately for each model).
58+
```@example programmatic_generative_linear_pathway_dsl
59+
using OrdinaryDiffEq, Plots
60+
u0_n3 = [:X0 => 3*1.0, :X1 => 0.0, :X2 => 0.0, :X3 => 0.0]
61+
ps_n3 = [:τ => 1.0/3]
62+
oprob_n3 = ODEProblem(lp_n3, u0_n3, (0.0, 5.0), ps_n3)
63+
64+
u0_n10 = [:X0 => 10*1.0, :X1 => 0.0, :X2 => 0.0, :X3 => 0.0, :X4 => 0.0, :X5 => 0.0, :X6 => 0.0, :X7 => 0.0, :X8 => 0.0, :X9 => 0.0, :X10 => 0.0]
65+
ps_n10 = [:τ => 1.0/10.0]
66+
oprob_n10 = ODEProblem(lp_n10, u0_n10, (0.0, 5.0), ps_n10)
67+
nothing # hide
68+
```
69+
Finally, we plot the concentration of the final species in each linear pathway, noting that while the two pulses both peak at $t = 1.0$, their shapes depend on $n$.
70+
```@example programmatic_generative_linear_pathway_dsl
71+
sol_n3 = solve(oprob_n3)
72+
sol_n10 = solve(oprob_n10)
73+
plot(sol_n3; idxs = :X3, label = "n = 3")
74+
plot!(sol_n10; idxs = :X10, label = "n = 10")
75+
```
76+
77+
## [Modelling linear pathways using programmatic, generative, modelling](@id programmatic_generative_linear_pathway_generative)
78+
Above, we investigated the impact of linear pathways' lengths on their behaviours. Since the models were implemented using the DSL, we had to implement a new model for each pathway (in each case writing out all reactions). Here, we will instead show how [programmatic modelling](@ref ref) can be used to generate pathways of arbitrary lengths.
79+
80+
First, we create a function, `generate_lp`, which creates a linear pathway model of length `n`. It utilises [*vector variables*](@ref ref) to create an arbitrary number of species, and also creates an [observable](@ref ref) for the final species of the chain.
81+
```@example programmatic_generative_linear_pathway_generative
82+
using Catalyst # hide
83+
function generate_lp(n)
84+
# Creates a vector `X` with n+1 species.
85+
@species X(t)[1:n+1]
86+
@species Xend(t)
87+
88+
# Generate
89+
# (1) A degradation reaction for the input species.
90+
# (2) Production reactions for all intermediary species.
91+
# (2) Degradation reactions for all intermediary species.
92+
rxs = [
93+
Reaction(1/τ, [X[1]], []);
94+
[Reaction(X[i]/τ, [], [X[i+1]]) for i in 1:n];
95+
[Reaction(1/τ, [X[i+1]], []) for i in 1:n]
96+
]
97+
98+
# Assembly and return a complete `ReactionSystem` (including an observable for the final species).
99+
@named lp_n = ReactionSystem(rxs, t; observed = [Xend ~ X[end]])
100+
return complete(lp_n)
101+
end
102+
nothing # hide
103+
```
104+
Next, we create a function that generates an `ODEProblem` (with appropriate initial conditions and parameter values) for arbitrarily lengthed linear pathway models.
105+
```@example programmatic_generative_linear_pathway_generative
106+
function generate_oprob(n)
107+
lp = generate_lp(n)
108+
X_init = fill(0.0, n + 1)
109+
X_init[1] = n * 1.0
110+
u0 = [lp.X => X_init]
111+
ps = [τ => 1.0 / n]
112+
return ODEProblem(lp, u0, (0.0, 5.0), ps)
113+
end
114+
nothing # hide
115+
```
116+
We can now simulate linear pathways of arbitrary lengths using a simple syntax. We use this to recreate our previous result from the DSL:
117+
```@example programmatic_generative_linear_pathway_generative
118+
sol_n3 = solve(generate_oprob(3))
119+
sol_n10 = solve(generate_oprob(10))
120+
plot(sol_n3; idxs = :Xend, label = "n = 3")
121+
plot!(sol_n10; idxs = :Xend, label = "n = 10")
122+
```
123+
If we wish to investigate the behaviour of a pathway with a different length, we can easily add this to the plot
124+
```@example programmatic_generative_linear_pathway_generative
125+
sol_n20 = solve(generate_oprob(20))
126+
plot!(sol_n20; idxs = :Xend, label = "n = 20")
127+
```
128+
129+
130+
---
131+
## References
132+
[^1]: [J. Metz, O. Diekmann *The Abstract Foundations of Linear Chain Trickery* (1991).](https://ir.cwi.nl/pub/1559/1559D.pdf)
133+
[^2]: D. Fargue *Reductibilite des systemes hereditaires a des systemes dynamiques (regis par des equations differentielles aux derivees partielles)*, Comptes rendus de l'Académie des Sciences (1973).
134+
[^3]: [N. Korsbo, H. Jönsson *It’s about time: Analysing simplifying assumptions for modelling multi-step pathways in systems biology*, PLoS Computational Biology (2020).](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1007982)

0 commit comments

Comments
 (0)