Skip to content

Commit e75c34f

Browse files
committed
finish tutorial updates
1 parent 5dda9b8 commit e75c34f

File tree

1 file changed

+88
-52
lines changed

1 file changed

+88
-52
lines changed

docs/src/tutorials/simple_poisson_process.md

Lines changed: 88 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ primarily in chemical or population process models, where several types of jumps
66
may occur, can skip directly to the [second tutorial](@ref ssa_tutorial) for a
77
tutorial covering similar material but focused on the SIR model.
88

9-
JumpProcesses allows the simulation of jump processes where the transition rate, i.e.
10-
intensity or propensity, can be a function of the current solution, current
9+
JumpProcesses allows the simulation of jump processes where the transition rate,
10+
i.e. intensity or propensity, can be a function of the current solution, current
1111
parameters, and current time. Throughout this tutorial these are denoted by `u`,
1212
`p` and `t`. Likewise, when a jump occurs any
1313
DifferentialEquations.jl-compatible change to the current system state, as
1414
encoded by a [DifferentialEquations.jl
1515
integrator](https://docs.sciml.ai/DiffEqDocs/stable/basics/integrator/), is
16-
allowed. This includes changes to the current state or to parameter values.
16+
allowed. This includes changes to the current state or to parameter values (for
17+
example via a callback).
1718

1819
This tutorial requires several packages, which can be added if not already
1920
installed via
@@ -29,7 +30,7 @@ default(; lw = 2)
2930
```
3031
3132
## `ConstantRateJump`s
32-
Our first example will be to simulate a simple Poission counting process,
33+
Our first example will be to simulate a simple Poisson counting process,
3334
``N(t)``, with a constant transition rate of λ. We can interpret this as a birth
3435
process where new individuals are created at the constant rate λ. ``N(t)`` then
3536
gives the current population size. In terms of a unit Poisson counting process,
@@ -61,7 +62,7 @@ sol = solve(jprob, SSAStepper())
6162
plot(sol, label="N(t)", xlabel="t", legend=:bottomright)
6263
```
6364
64-
We can define and simulate our jump process using JumpProcesses. We first load our
65+
We can define and simulate our jump process as follows. We first load our
6566
packages
6667
```@example tut1
6768
using JumpProcesses, Plots
@@ -104,29 +105,28 @@ tspan = (0.0, 10.0)
104105
```
105106
Finally, we construct the associated SciML problem types and generate one
106107
realization of the process. We first create a `DiscreteProblem` to encode that
107-
we are simulating a process that evolves in discrete time steps. Note, this
108-
currently requires that the process has constant transition rates *between*
109-
jumps
108+
we are simulating a process that evolves in discrete time steps.
110109
```@example tut1
111110
dprob = DiscreteProblem(u₀, tspan, p)
112111
```
113112
We next create a [`JumpProblem`](@ref) that wraps the discrete problem, and
114-
specifies which algorithm to use for determining next jump times (and in the
115-
case of multiple possible jumps the next jump type). Here we use the classical
116-
`Direct` method, proposed by Gillespie in the chemical reaction context, but
117-
going back to earlier work by Doob and others (and also known as Kinetic Monte
118-
Carlo in the physics literature)
113+
specifies which algorithm, called an aggregator in JumpProcesses, to use for
114+
determining next jump times (and in the case of multiple possible jumps the next
115+
jump type). Here we use the classical `Direct` method, proposed by Gillespie in
116+
the chemical reaction context, but going back to earlier work by Doob and others
117+
(and also known as Kinetic Monte Carlo in the physics literature)
119118
```@example tut1
120119
# a jump problem, specifying we will use the Direct method to sample
121120
# jump times and events, and that our jump is encoded by crj
122121
jprob = JumpProblem(dprob, Direct(), crj)
123122
```
124-
We are finally ready to simulate one realization of our jump process
123+
We are finally ready to simulate one realization of our jump process, selecting
124+
`SSAStepper` to handle time-stepping our system from jump to jump
125125
```@example tut1
126126
# now we simulate the jump process in time, using the SSAStepper time-stepper
127127
sol = solve(jprob, SSAStepper())
128128
129-
plot(sol, label="N(t)", xlabel="t", legend=:bottomright)
129+
plot(sol, labels = "N(t)", xlabel = "t", legend = :bottomright)
130130
```
131131
132132
### More general `ConstantRateJump`s
@@ -157,11 +157,11 @@ second `ConstantRateJump`. We then construct the corresponding problems, passing
157157
both jumps to `JumpProblem`, and can solve as before
158158
```@example tut1
159159
p = (λ = 2.0, μ = 1.5)
160-
u₀ = [0,0] # (N(0), D(0))
160+
u₀ = [0, 0] # (N(0), D(0))
161161
dprob = DiscreteProblem(u₀, tspan, p)
162162
jprob = JumpProblem(dprob, Direct(), crj, deathcrj)
163163
sol = solve(jprob, SSAStepper())
164-
plot(sol, label=["N(t)" "D(t)"], xlabel="t", legend=:topleft)
164+
plot(sol, labels = ["N(t)" "D(t)"], xlabel = "t", legend = :topleft)
165165
```
166166
167167
In the next tutorial we will also introduce [`MassActionJump`](@ref)s, which are
@@ -175,67 +175,99 @@ by adding or subtracting a constant vector from `u`.
175175
## `VariableRateJump`s for processes that are not constant between jumps
176176
So far we have assumed that our jump processes have transition rates that are
177177
constant in between jumps. In many applications this may be a limiting
178-
assumption. To support such models JumpProcesses has the [`VariableRateJump`](@ref)
179-
type, which represents jump processes that have an arbitrary time dependence in
180-
the calculation of the transition rate, including transition rates that depend
181-
on states which can change in between `ConstantRateJump`s. Let's consider the
182-
previous example, but now let the birth rate be time dependent, ``b(t) = \lambda
183-
\left(\sin(\pi t / 2) + 1\right)``, so that our model becomes
178+
assumption. To support such models JumpProcesses has the
179+
[`VariableRateJump`](@ref) type, which represents jump processes that have an
180+
arbitrary time dependence in the calculation of the transition rate, including
181+
transition rates that depend on states which can change in between two jumps
182+
occurring. Let's consider the previous example, but now let the birth rate be
183+
time dependent, ``b(t) = \lambda \left(\sin(\pi t / 2) + 1\right)``, so that our
184+
model becomes
184185
```math
185186
\begin{align*}
186187
N(t) &= Y_b\left(\int_0^t \left( \lambda \sin\left(\tfrac{\pi s}{2}\right) + 1 \right) \, d s\right) - Y_d \left(\int_0^t \mu N(s^-) \, ds \right), \\
187188
D(t) &= Y_d \left(\int_0^t \mu N(s^-) \, ds \right).
188189
\end{align*}
189190
```
190191
192+
191193
The birth rate is cyclical, bounded between a lower-bound of ``λ`` and an
192-
upper-bound of ``2 λ``. We'll then re-encode the first jump as a
193-
`VariableRateJump`
194+
upper-bound of ``2 λ``. We'll then re-encode the first (birth) jump as a
195+
`VariableRateJump`. Two types of `VariableRateJump`s are supported, general and
196+
bounded. The latter are generally more performant, but are also more restrictive
197+
in when they can be used. They also require specifying additional information
198+
beyond just `rate` and `affect!` functions.
199+
200+
Let's see how to build a bounded `VariableRateJump` encoding our new birth
201+
process. We first specify the rate and affect functions, just like for a
202+
`ConstantRateJump`,
194203
```@example tut1
195204
rate1(u,p,t) = p.λ * (sin(pi*t/2) + 1)
196-
lrate1(u,p,t) = p.λ
197-
urate1(u, p, t) = 2 * p.λ
198-
L1(u, p, t) = typemax(t)
199205
affect1!(integrator) = (integrator.u[1] += 1)
200-
vrj1 = VariableRateJump(rate1, affect1!; lrate=lrate1, urate=urate1, L=L1)
206+
```
207+
We next provide functions that determine a time interval over which the rate is
208+
bounded from above given `u`, `p` and `t`. From these we can construct the new
209+
bounded `VariableRateJump`:
210+
```@example tut1
211+
# We require that rate1(u,p,s) <= urate(u,p,s)
212+
# for t <= s <= t + rateinterval(u,p,t)
213+
rateinterval(u, p, t) = typemax(t)
214+
urate(u, p, t) = 2 * p.λ
215+
216+
# Optionally, we can give a lower bound over the same interval.
217+
# This may boost computational performance.
218+
lrate(u, p, t) = p.λ
219+
220+
# now we construct the bounded VariableRateJump
221+
vrj1 = VariableRateJump(rate1, affect1!; lrate, urate, rateinterval)
201222
```
202223
203-
Since births modify the population size `u[1]` and deaths `u[2]` occur at a rate
204-
proportional to the population size. We must represent this relation in
205-
a dependency graph. Note that the indices in the graph correspond to the order
206-
in which the jumps appear when the problem is constructed. The graph below
207-
indicates that births (event 1) modify deaths (event 2), but deaths do not
208-
modify births.
224+
Finally, to efficiently simulate the new jump process we must also specify a
225+
dependency graph. This indicates when a given jump occurs, which jumps in the
226+
system need to have their rates and/or rate bounds recalculated (for example,
227+
due to depending on changed components in `u`). We also assume the convention
228+
that a given jump depends on itself. Since the first (birth) jump modifies the
229+
population size `u[1]`, and the second (death) jump occurs at a rate
230+
proportional to `u[1]`, when the first jump occurs we need to recalculate both
231+
of the rates. In contrast, death does not change `u[1]`, and so the dependencies
232+
of the second (death) jump are only itself. Note that the indices in the graph
233+
correspond to the order in which the jumps appear when the problem is
234+
constructed. The graph below encodes the dependents of the birth and death jumps
235+
respectively
209236
```@example tut1
210-
dep_graph = [[2], []]
237+
dep_graph = [[1,2], [2]]
211238
```
212239
213240
We can then construct the corresponding problem, passing both jumps to
214-
`JumpProblem` as well as the dependency graph. Since we are dealing with
215-
a `VariableRateJump` we must use the `Coevolve` aggregator.
241+
`JumpProblem` as well as the dependency graph. We must use an aggregator that
242+
supports bounded `VariableRateJump`s, in this case we choose the `Coevolve`
243+
aggregator.
216244
```@example tut1
217-
jprob = JumpProblem(dprob, Coevolve(), vrj1, deathcrj; dep_graph=dep_graph)
245+
jprob = JumpProblem(dprob, Coevolve(), vrj1, deathcrj; dep_graph)
218246
sol = solve(jprob, SSAStepper())
219-
plot(sol, label=["N(t)" "D(t)"], xlabel="t", legend=:topleft)
247+
plot(sol, labels = ["N(t)" "D(t)"], xlabel = "t", legend = :topleft)
220248
```
221249
222-
In a scenario, where we did not know the bounds of the time-dependent rate. We
223-
would have to use a continuous problem type to properly handle the jump times.
224-
Under this assumption we would define the `VariableRateJump` as following:
250+
If we did not know the upper rate bound or rate interval functions for the
251+
time-dependent rate, we would have to use a continuous problem type and general
252+
`VariableRateJump` to correctly handle calculating the jump times. Under this
253+
assumption we would define a general `VariableRateJump` as following:
225254
```@example tut1
226255
vrj2 = VariableRateJump(rate1, affect1!)
227256
```
228257
229-
Since the death rate now depends on a `VariableRateJump` without bounds, we need
230-
to redefine the death jump process as a `VariableRateJump`
258+
Since the death rate now depends on a variable, `u[2]`, modified by a general
259+
`VariableRateJump` (i.e. one that is not bounded), we also need to redefine the
260+
death jump process as a general `VariableRateJump`
231261
```@example tut1
232262
deathvrj = VariableRateJump(deathrate, deathaffect!)
233263
```
234264
235-
To simulate our jump process we now need to construct an
236-
ordinary differential equation problem, `ODEProblem`, but setting the ODE
237-
derivative to preserve the state (i.e. to zero). We are essentially defining a
238-
combined ODE-jump process, i.e. a [piecewise deterministic Markov
265+
To simulate our jump process we now need to construct a continuous problem type
266+
to couple the jumps to, for example an ordinary differential equation (ODE) or
267+
stochastic differential equation (SDE). Let's use an ODE, encoded via an
268+
`ODEProblem`. We simply set the ODE derivative to zero to preserve the state. We
269+
are essentially defining a combined ODE-jump process, i.e. a [piecewise
270+
deterministic Markov
239271
process](https://en.wikipedia.org/wiki/Piecewise-deterministic_Markov_process),
240272
but one where the ODE is trivial and does not change the state. To use this
241273
problem type and the ODE solvers we first load `OrdinaryDiffEq.jl` or
@@ -251,7 +283,7 @@ using OrdinaryDiffEq
251283
# or using DifferentialEquations
252284
```
253285
We can then construct our ODE problem with a trivial ODE derivative component.
254-
Note, to work with the ODE solver time stepper we must change our initial
286+
Note, to work with the ODE solver time stepper we must also change our initial
255287
condition to be floating point valued
256288
```@example tut1
257289
function f!(du, u, p, t)
@@ -262,13 +294,17 @@ u₀ = [0.0, 0.0]
262294
oprob = ODEProblem(f!, u₀, tspan, p)
263295
jprob = JumpProblem(oprob, Direct(), vrj2, deathvrj)
264296
```
265-
We simulate our jump process, using the `Tsit5` ODE solver as the time stepper in
266-
place of `SSAStepper`
297+
We can now simulate our jump process, using the `Tsit5` ODE solver as the time
298+
stepper in place of `SSAStepper`
267299
```@example tut1
268300
sol = solve(jprob, Tsit5())
269301
plot(sol, label=["N(t)" "D(t)"], xlabel="t", legend=:topleft)
270302
```
271303
304+
For more details on when bounded vs. general `VariableRateJump`s can be used,
305+
see the [next tutorial](@ref ssa_tutorial) and the [Jump Problems](@ref
306+
jump_problem_type) documentation page.
307+
272308
## Having a Random Jump Distribution
273309
Suppose we want to simulate a compound Poisson process, ``G(t)``, where
274310
```math

0 commit comments

Comments
 (0)