Skip to content

Commit 1256e17

Browse files
committed
polish. Add quick-start example. Update simulation example settings.
1 parent 9e3cd68 commit 1256e17

File tree

2 files changed

+62
-26
lines changed

2 files changed

+62
-26
lines changed

docs/src/introduction_to_catalyst/math_models_intro.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Likewise, the following drops the combinatoric scaling factors, giving unscaled
110110
osys = convert(ODESystem, rn; combinatoric_ratelaws = false)
111111
```
112112

113-
## Chemical Langevin Equation (CLE) SDE Models
113+
## [Chemical Langevin Equation (CLE) SDE Models](@id math_models_in_catalyst_cle_sdes)
114114
The CLE SDE models Catalyst creates for a general system correspond to the coupled system of SDEs given by
115115
```math
116116
d X_m = \sum_{k=1}^K \nu_m^k a_k(\mathbf{X}(t),t) dt + \sum_{k=1}^K \nu_m^k \sqrt{a_k(\mathbf{X}(t),t)} dW_k(t), \quad m = 1,\dots,M,
@@ -137,7 +137,7 @@ dC(t) &= \frac{3}{2} k_1 A^{2} B \, dt + 3 \sqrt{\frac{k_1}{2} A^{2} B} \, dW_1(
137137
\end{align}
138138
```
139139

140-
## Stochastic Chemical Kinetics Jump Process Models
140+
## [Stochastic Chemical Kinetics Jump Process Models](@id math_models_in_catalyst_sck_jumps)
141141
The stochastic chemical kinetics jump process models Catalyst creates for a general system correspond to the coupled system of jump processes, in the time change representation, given by
142142
```math
143143
X_m(t) = X_m(0) + \sum_{k=1}^K \nu_m^k Y_k\left( \int_{0}^t a_k(\mathbf{X}(s^-),s) \, ds \right), \quad m = 1,\dots,M.

docs/src/model_simulation/finite_state_projection_simulation.md

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,62 @@
11
# [Solving the chemical master equation using FiniteStateProjection.jl](@id finite-state_projection)
2-
Previously we have shown how *stochastic chemical kinetics* describe how chemical reaction network models can be [exactly simulated](@ref simulation_intro_jumps) (using e.g. Gillespie's algorithm). We also described how the [SDE](@ref simulation_intro_SDEs) and [ODE](@ref simulation_intro_ODEs) approaches were approximation of these jump simulations, and only valid for large copy numbers. To gain a good understanding of the system's time-development, we typically have to carry out a large number of jump simulations. Here, an alternative approach is instead to simulate the *full probability distribution of the system*. This corresponds to the distribution from which these jump simulations are drawn.
2+
```@raw html
3+
<details><summary><strong>Quick-start example</strong></summary>
4+
```
5+
The following code provides a brief example of hwo to simulate the chemical master equation using the FiniteStateProjection.jl package.
6+
```julia
7+
# Create reaction network model (a bistable switch).
8+
using Catalyst
9+
rs_bistable = @reaction_network begin
10+
    hillr(Y, v, K, n), ∅ --> X
11+
    hillr(X, v, K, n), ∅ --> Y
12+
d, (X,Y) --> 0
13+
end
314

4-
[*The chemical master equation*](https://en.wikipedia.org/wiki/Master_equation) (CME) describes the time development of this distribution[^1]. In fact, this equation is at the core of chemical reaction network kinetics, with all other approaches (such as ODE, SDE, and Jump simulations) being derived as various approximations of it. The CME is a system of ODEs, with one variable *for each possible state of the system*. Each of these variables describes the probability of the system being in that state, over time. For a system with a single species $X$, the CME looks like
15+
# Create a FSPSystem. The second argument denotes species order in u0 and sol.
16+
using FiniteStateProjection
17+
fsp_sys = FSPSystem(rs_bistable, [:X, :Y])
18+
19+
# Create ODEProblem. Initial condition is the system's initial distribution.
20+
# Initial condition also designates projection space (outside of which solution should be very close to 0).
21+
u0 = zeros(20,20)
22+
u0[6,2] = 1.0
23+
tspan = (0.0, 50.0)
24+
ps = [:v => 1.0, :K => 3.0, :n => 3, :d => 0.2]
25+
oprob = ODEProblem(fsp_sys, u0, tspan, ps)
26+
27+
# Simulate ODE (it can be quite large, so consider performance options).
28+
# Plot solution as a heatmap at a specific time point.
29+
using OrdinaryDiffEqRosenbrock, Plots
30+
osol = solve(oprob, Rodas5P())
31+
heatmap(osol(50.0); xguide = "Y", yguide = "X")
32+
```
33+
```@raw html
34+
</details>
35+
```
36+
\
37+
38+
Previously, we have shown how [*stochastic chemical kinetics*](@ref math_models_in_catalyst_sck_jumps) describe how chemical reaction network models can be [exactly simulated](@ref simulation_intro_jumps) (using e.g. [Gillespie's algorithm](https://en.wikipedia.org/wiki/Gillespie_algorithm)). We also described how the [SDE](@ref math_models_in_catalyst_cle_sdes) and [ODE](@ref math_models_in_catalyst_rre_odes) approaches were approximations of these jump simulations, and only valid for large copy numbers. To gain a good understanding of the system's time development, we typically have to carry out a large number of jump simulations. An alternative approach, however, is to instead simulate the *full probability distribution of the system*. This corresponds to the distribution from which these jump simulations are drawn.
39+
40+
[*The chemical master equation*](https://en.wikipedia.org/wiki/Master_equation) (CME) describes the time development of this distribution[^1]. In fact, this equation is at the core of chemical reaction network kinetics, with all other approaches (such as ODE, SDE, and Jump simulations) being derived as various approximations of it. The CME is a system of ODEs, with one variable *for each possible state of the system*. Each of the ODE's variables describes (the rate of change in) the probability of the system being in that state. For a system with a single species $X$, the CME looks like
541
```math
642
\begin{aligned}
743
\frac{dp(x=0)}{dt} &= f_0(p(x=0), p(x=1), ...) \\
844
\frac{dp(x=1)}{dt} &= f_0(p(x=0), p(x=1), ...) \\
945
\frac{dp(x=2)}{dt} &= f_0(p(x=0), p(x=1), ...) \\
10-
&\vdots\\
46+
&\vdots\\
1147
\end{aligned}
1248
```
13-
Here, we note that, since (for almost all chemical reaction networks) there is a non-zero probability that $X$ is any specific integer value, the CME have an infinite number of variables. Hence, it cannot be solved practically. However, one notes that for high enough species values, the probability of the system attaining such values becomes negligibly small. Here, a truncated version of the CME can be solved practically. An approach for this is the *finite state projection*[^2]. Below we describe how to use the [FiniteStateProjection.jl](https://github.com/SciML/FiniteStateProjection.jl) package to solve the truncated CME. While this approach can be very powerful, we note that for system's with many species, even the truncated CME typically have too many states to be feasible to solve.
49+
We note that, since (for almost all chemical reaction networks) there is a non-zero probability that $X$ is at any specific integer value, the CME have an infinite number of variables (corresponding to the infinite number of potential states). Hence, it cannot be solved practically. However, for high enough species values, the probability of the system attaining such values becomes negligibly small. Here, a truncated version of the CME can be solved practically. An approach for this is the *finite state projection*[^2]. Below we describe how to use the [FiniteStateProjection.jl](https://github.com/SciML/FiniteStateProjection.jl) package to solve the truncated CME (with the package's [documentation](https://docs.sciml.ai/FiniteStateProjection/dev/) providing a more extensive description). While the CEM approach can be very powerful, we note that even for systems with few species, the truncated CME typically have too many states to be feasibly solved.
1450

1551
## [Finite state projection simulation of single-species model](@id state_projection_one_species)
16-
For this example we will use a simple [birth-death model](@ref basic_CRN_library_bd), where a single species ($X$) is created and degraded at constant rates ($p$ and $d$, respectively).
52+
For this example, we will use a simple [birth-death model](@ref basic_CRN_library_bd), where a single species ($X$) is created and degraded at constant rates ($p$ and $d$, respectively).
1753
```@example state_projection_one_species
1854
using Catalyst
1955
rs = @reaction_network begin
2056
(p,d), 0 <--> X
2157
end
2258
```
23-
Next we perform jump simulations (using the [ensemble simulation interface](@ref ensemble_simulations_monte_carlo)) of the model. Here, we can see how the it develops from an initial condition and reaches a steady state distribution.
59+
Next, we perform jump simulations (using the [ensemble simulation interface](@ref ensemble_simulations_monte_carlo)) of the model. Here, we can see how it develops from an initial condition and reaches a steady state distribution.
2460
```@example state_projection_one_species
2561
using JumpProcesses, Plots
2662
u0 = [:X => 5]
@@ -31,75 +67,75 @@ eprob = EnsembleProblem(jprob)
3167
esol = solve(eprob, SSAStepper(); trajectories = 10)
3268
plot(esol; ylimit = (0.0, Inf))
3369
```
34-
Using chemical master equation simulations, we want to simulate how the *full probability distribution* of these jump simulations develop across the simulation time-frame.
70+
Using chemical master equation simulations, we want to simulate how the *full probability distribution* of these jump simulations develops across the simulation time frame.
3571

3672
As a first step, we import the FiniteStateProjection package. Next, we convert our [`ReactionSystem`](@ref) to a `FSPSystem` (from which we later will generate an ODE).
3773
```@example state_projection_one_species
3874
using FiniteStateProjection
3975
fsp_sys = FSPSystem(rs)
4076
nothing # hide
4177
```
42-
Next, we set our initial condition. For normal simulations, $X$'s initial condition would be a single value. Here, however, we will simulate $X$'s probability distribution. Hence, its initial condition will also be a probability distribution. In FiniteStateProjection's interface, the initial condition is a vector, where the $i$'th index is the probability that $X$ have an initial value of $i-1$. The total sum of all probabilities across the vector should be normalised to $1$. Here we assume that $X$'s initial conditions is known to be $5$ (hence the corresponding probability is $1$, and the remaining ones are $0$):
78+
Next, we set our initial condition. For normal simulations, $X$'s initial condition would be a single value. Here, however, we will simulate $X$'s probability distribution. Hence, its initial condition will also be a probability distribution. In FiniteStateProjection's interface, the initial condition is an array, where the $i$'th index is the probability that $X$ have an initial value of $i-1$. The total sum of all probabilities across the vector should be normalised to $1.0$. Here we assume that $X$'s initial conditions is known to be $5$ (hence the corresponding probability is $1.0$, and the remaining ones are $0.0$):
4379
```@example state_projection_one_species
4480
u0 = zeros(75)
4581
u0[6] = 1.0
46-
bar(u0)
82+
bar(u0, label = "t = 0.0")
4783
```
48-
We also plot the full distribution using the `bar` function. Finally, the initial condition vector also define the finite space onto which we project the chemical master equation. I.e. we will assume that, throughout the entire simulation, the probability of $X$ reaching values outside this initial vector is negligible.
84+
We also plot the full distribution using the `bar` function. Finally, the initial condition vector defines the finite space onto which we project the CME. I.e. we will assume that, throughout the entire simulation, the probability of $X$ reaching values outside this initial vector is negligible.
4985
!!! warn
50-
This last fact is important. Even if the probability seems to ve very small on the boundary provided by the initial condition, there is still a risk that probability will "leak". Here, it can be good to make simulations using different projections, ensuring that the results are consistent (especially for longer simulations).
86+
This last bit is important. Even if the probability seems to be very small on the boundary provided by the initial condition, there is still a risk that probability will "leak". Here, it can be good to make simulations using different projections, ensuring that the results are consistent (especially for longer simulations).
5187

52-
Now, we can finally create an `ODEProblem` using out `FSPSystem`, our initial conditions, and the parameters declared previously. We can simulate this `ODEProblem` like any other ODE.
88+
Now, we can finally create an `ODEProblem` using our `FSPSystem`, initial conditions, and the parameters declared previously. We can simulate this `ODEProblem` like any other ODE.
5389
```@example state_projection_one_species
5490
using OrdinaryDiffEqDefault
5591
oprob = ODEProblem(fsp_sys, u0, tspan, ps)
5692
osol = solve(oprob)
5793
nothing # hide
5894
```
59-
Finally, we can plot the $X$'s probability distribution at various time point's of the simulation. Again, we will uset he `bar` function to plot teh distribution, and the interface described [here](@ref simulation_structure_interfacing_solutions) to acess the simulation at various timestamps.
95+
Finally, we can plot $X$'s probability distribution at various simulation time points. Again, we will use the `bar` function to plot the distribution, and the interface described [here](@ref simulation_structure_interfacing_solutions) to access the simulation at various time points.
6096
```@example state_projection_one_species
61-
bar(osol(1.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 1.0")
97+
bar(osol(1.0);  bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 1.0")
6298
bar!(osol(2.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 2.0")
6399
bar!(osol(5.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 5.0")
64-
bar!(osol(10.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 10.0")
100+
bar!(osol(10.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 10.0",
101+
xguide = "X (copy numbers)", yguide = "Probability density")
65102
```
66103

67104
## [Finite state projection simulation of multi-species model](@id state_projection_multi_species)
68-
Next, we will consider a system with more than one species. The workflow will be identical, however, we will have to make an additional consideration regarding our initial conditions. We will also need to use a different plotting approach.
105+
Next, we will consider a system with more than one species. The workflow will be identical, however, we will have to make an additional consideration regarding our initial conditions, simulation performance, and plotting approach.
69106

70-
For this example we will consider a simple dimerisation model. In it, $X$ gets produced and degraded at constant rates, and can also dimerise to form $X₂$.
107+
For this example, we will consider a simple dimerisation model. In it, $X$ gets produced and degraded at constant rates, and can also dimerise to form $X₂$.
71108
```@example state_projection_multi_species
72109
using Catalyst # hide
73110
rs = @reaction_network begin
74111
(p,d), 0 <--> X
75112
(kB,kD), 2X <--> X₂
76113
end
77114
```
78-
79-
Next, we will declare our parameter values and initial condition. In this case, the initial condition is a matrix where element $(i,j)$ denotes the initial probability that $(X(0),X₂(0)) = (i-1,j-1)$. In this case, we will use an initial condition where we know that $(X(0),X₂(0)) = (0,0)$.
115+
Next, we will declare our parameter values and initial condition. In this case, the initial condition is a matrix where element $(i,j)$ denotes the initial probability that $(X(0),X₂(0)) = (i-1,j-1)$. In this case, we will use an initial condition where we know that $(X(0),X₂(0)) = (5,0)$.
80116
```@example state_projection_multi_species
81117
ps = [:p => 1.0, :d => 0.2, :kB => 2.0, :kD => 5.0]
82118
u0 = zeros(25,25)
83-
u0[1,1] = 1.0
119+
u0[6,1] = 1.0
84120
```
85-
In the next step, however, we have to make an additional consideration. Since we have more than one species, we have to define which dimension of the initial condition (and hence also the output solution) correspond to which species. Here we provide a second argument to `FSPSystem`, which is a vector listing all species in the order they occur in the `u0` array.
121+
In the next step, however, we have to make an additional consideration. Since we have more than one species, we have to define which dimension of the initial condition (and hence also the output solution) corresponds to which species. Here we provide a second argument to `FSPSystem`, which is a vector listing all species in the order they occur in the `u0` array.
86122
```@example state_projection_multi_species
87123
using FiniteStateProjection # hide
88124
fsp_sys = FSPSystem(rs, [:X, :X₂])
89125
nothing # hide
90126
```
91-
Finally, we can simulate the model just like in the 1-dimensional case. Here we will specifically use the `Rodas5P()` ODE solver (as it performs noticeably better than teh default choice).
127+
Finally, we can simulate the model just like in the 1-dimensional case. In this case, however, we are simulating an ODE with $25⋅25 = 625$ states, which means we need to make some considerations regarding performance. In this case, we will simply specify the `Rodas5P()` ODE solver (more extensive advice on performance can be found [here](@ref ode_simulation_performance)).
92128
```@example state_projection_multi_species
93129
using Plots # hide
94130
using OrdinaryDiffEqRosenbrock
95131
oprob = ODEProblem(fsp_sys, u0, 100.0, ps)
96-
@time osol = solve(oprob, Rodas5P())
132+
osol = solve(oprob, Rodas5P())
97133
heatmap(osol[end]; xguide = "X₂", yguide = "X")
98134
```
99135
Here we perform a simulation with a long time span ($t = 100$) aiming to find the system's steady state distribution. Next, we plot it using the `heatmap` function.
100136

101137
## [Finite state projection steady state simulations](@id state_projection_steady_state_sim)
102-
Previously we described how the [SteadyStateDiffEq.jl](https://github.com/SciML/SteadyStateDiffEq.jl) package can be used to [find an ODE's steady state through forward simulation](@ref steady_state_stability). The same interface can be used for ODEs generated through FiniteStateProjection.jl. Below we use this to find the steady state of the dimerisation example studied in the last example.
138+
Previously, we have shown how the [SteadyStateDiffEq.jl](https://github.com/SciML/SteadyStateDiffEq.jl) package can be used to [find an ODE's steady state through forward simulation](@ref steady_state_stability). The same interface can be used for ODEs generated through FiniteStateProjection. Below, we use this to find the steady state of the dimerisation example studied in the last example.
103139
```@example state_projection_multi_species
104140
using SteadyStateDiffEq, OrdinaryDiffEqRosenbrock
105141
ssprob = SteadyStateProblem(fsp_sys, u0, ps)

0 commit comments

Comments
 (0)