|
| 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