|
1 | 1 | # [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. |
| 3 | + |
| 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 |
| 5 | +```math |
| 6 | +\begin{aligned} |
| 7 | +\frac{dp(x=0)}{dt} &= f_0(p(x=0), p(x=1), ...) \\ |
| 8 | +\frac{dp(x=1)}{dt} &= f_0(p(x=0), p(x=1), ...) \\ |
| 9 | +\frac{dp(x=2)}{dt} &= f_0(p(x=0), p(x=1), ...) \\ |
| 10 | + &\vdots\\ |
| 11 | +\end{aligned} |
| 12 | +``` |
| 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. |
2 | 14 |
|
3 | 15 | ## [Finite state projection simulation of single-species model](@id state_projection_one_species)
|
4 | 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).
|
@@ -46,41 +58,57 @@ nothing # hide
|
46 | 58 | ```
|
47 | 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.
|
48 | 60 | ```@example state_projection_one_species
|
49 |
| -bar(osol(1.0); width = 1.0, linecolor = 1, alpha = 0.7, linealpha = 0.7, label = "t = 1.0") |
50 |
| -bar!(osol(2.0); linecolor = 1, alpha = 0.7, linealpha = 0.7, label = "t = 2.0") |
51 |
| -bar!(osol(5.0); linecolor = 1, alpha = 0.7, linealpha = 0.7, label = "t = 5.0") |
52 |
| -bar!(osol(10.0); linecolor = 1, alpha = 0.7, linealpha = 0.7, label = "t = 10.0") |
| 61 | +bar(osol(1.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 1.0") |
| 62 | +bar!(osol(2.0); bar_width = 1.0, linewidth = 0, alpha = 0.7, label = "t = 2.0") |
| 63 | +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") |
53 | 65 | ```
|
54 | 66 |
|
55 | 67 | ## [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. |
56 | 69 |
|
| 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₂$. |
57 | 71 | ```@example state_projection_multi_species
|
58 | 72 | using Catalyst # hide
|
59 | 73 | rs = @reaction_network begin
|
60 | 74 | (p,d), 0 <--> X
|
61 |
| - (kB,kD), 2X <--> X2 |
| 75 | + (kB,kD), 2X <--> X₂ |
62 | 76 | end
|
63 | 77 | ```
|
64 | 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)$. |
65 | 80 | ```@example state_projection_multi_species
|
66 | 81 | ps = [:p => 1.0, :d => 0.2, :kB => 2.0, :kD => 5.0]
|
67 | 82 | u0 = zeros(25,25)
|
68 | 83 | u0[1,1] = 1.0
|
69 | 84 | ```
|
70 |
| - |
| 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. |
71 | 86 | ```@example state_projection_multi_species
|
72 |
| -using OrdinaryDiffEqRosenbrock, Plots # hide |
73 |
| -fsp_sys = FSPSystem(rs, [:X, :X2]) |
| 87 | +using FiniteStateProjection # hide |
| 88 | +fsp_sys = FSPSystem(rs, [:X, :X₂]) |
| 89 | +nothing # hide |
| 90 | +``` |
| 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). |
| 92 | +```@example state_projection_multi_species |
| 93 | +using Plots # hide |
| 94 | +using OrdinaryDiffEqRosenbrock |
74 | 95 | oprob = ODEProblem(fsp_sys, u0, 100.0, ps)
|
75 | 96 | @time osol = solve(oprob, Rodas5P())
|
76 |
| -heatmap(osol[end]; xguide = "X2", yguide = "X") |
| 97 | +heatmap(osol[end]; xguide = "X₂", yguide = "X") |
77 | 98 | ```
|
| 99 | +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. |
78 | 100 |
|
79 | 101 | ## [Finite state projection steady state simulations](@id state_projection_steady_state_sim)
|
80 | 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.
|
81 | 103 | ```@example state_projection_multi_species
|
82 | 104 | using SteadyStateDiffEq, OrdinaryDiffEqRosenbrock
|
83 | 105 | ssprob = SteadyStateProblem(fsp_sys, u0, ps)
|
84 | 106 | sssol = solve(ssprob, DynamicSS(Rodas5P()))
|
85 |
| -heatmap(sssol; xguide = "X2", yguide = "X") |
86 |
| -``` |
| 107 | +heatmap(sssol; xguide = "X₂", yguide = "X") |
| 108 | +``` |
| 109 | + |
| 110 | + |
| 111 | +--- |
| 112 | +## References |
| 113 | +[^1]: [Daniel T. Gillespie, *A rigorous derivation of the chemical master equation*, Physica A: Statistical Mechanics and its Applications (1992).](https://www.sciencedirect.com/science/article/abs/pii/037843719290283V) |
| 114 | +[^2]: [Brian Munsky, Mustafa Khammash, *The finite state projection algorithm for the solution of the chemical master equation*, Journal of Chemical Physics (2006).](https://pubs.aip.org/aip/jcp/article-abstract/124/4/044104/561868/The-finite-state-projection-algorithm-for-the?redirectedFrom=fulltext) |
0 commit comments