Skip to content

Commit 223c0fc

Browse files
committed
update references in simulation files
1 parent 0d13a40 commit 223c0fc

File tree

5 files changed

+40
-38
lines changed

5 files changed

+40
-38
lines changed

docs/src/model_simulation/ensemble_simulations.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ In many contexts, a single model is re-simulated under similar conditions. Examp
33
- Performing Monte Carlo simulations of a stochastic model to gain insight in its behaviour.
44
- Scanning a model's behaviour for different parameter values and/or initial conditions.
55

6-
While this can be handled using `for` loops, it is typically better to first create an `EnsembleProblem`, and then perform an ensemble simulation. Advantages include a more concise interface and the option for [automatic simulation parallelisation](@ref ref). Here we provide a short tutorial on how to perform parallel ensemble simulations, with a more extensive documentation being available [here](@ref https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/).
6+
While this can be handled using `for` loops, it is typically better to first create an `EnsembleProblem`, and then perform an ensemble simulation. Advantages include a more concise interface and the option for [automatic simulation parallelisation](@ref ode_simulation_performance_parallelisation). Here we provide a short tutorial on how to perform parallel ensemble simulations, with a more extensive documentation being available [here](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/).
77

88
## [Monte Carlo simulations using unmodified conditions](@id ensemble_simulations_monte_carlo)
9-
We will first consider Monte Carlo simulations where the simulation conditions are identical in-between simulations. First, we declare a [simple self-activation loop](@ref ref) model
9+
We will first consider Monte Carlo simulations where the simulation conditions are identical in-between simulations. First, we declare a [simple self-activation loop](@ref basic_CRN_library_self_activation) model
1010
```@example ensemble
1111
using Catalyst
1212
sa_model = @reaction_network begin
@@ -19,6 +19,7 @@ ps = [:v0 => 0.1, :v => 2.5, :K => 40.0, :n => 4.0, :deg => 0.01]
1919
```
2020
We wish to simulate it as an SDE. Rather than performing a single simulation, however, we want to perform multiple ones. Here, we first create a normal `SDEProblem`, and use it as the single input to a `EnsembleProblem` (`EnsembleProblem` are created similarly for ODE and jump simulations, but the `ODEProblem` or `JumpProblem` is used instead).
2121
```@example ensemble
22+
using StochasticDiffEq
2223
sprob = SDEProblem(sa_model, u0, tspan, ps)
2324
eprob = EnsembleProblem(sprob)
2425
nothing # hide
@@ -30,9 +31,10 @@ nothing # hide
3031
```
3132
Finally, we can use our ensemble simulation solution as input to `plot` (just like normal simulations):
3233
```@example ensemble
34+
using Plots
3335
plot(sols; la = 0.5)
3436
```
35-
Here, each simulation is displayed as an individual trajectory. We also use the [`la` plotting option](@ref ref) to reduce the transparency of each individual line, improving the plot visual.
37+
Here, each simulation is displayed as an individual trajectory. We also use the [`la` plotting option](@ref simulation_plotting_options) to reduce the transparency of each individual line, improving the plot visual.
3638

3739
Various convenience functions are available for analysing and plotting ensemble simulations (a full list can be found [here]). Here, we use these to first create an `EnsembleSummary` (retrieving each simulation's value at time points `0.0, 1.0, 2.0, ... 1000.0`). Next, we use this as an input to the `plot` command, which automatically plots the mean $X$ activity across the ensemble, while also displaying the 5% and 95% quantiles as the shaded area:
3840
```@example ensemble
@@ -45,15 +47,16 @@ Previously, we assumed that each simulation used the same initial conditions and
4547

4648
Here, we first create an `ODEProblem` of our previous self-activation loop:
4749
```@example ensemble
48-
oprob = ODEProblem(sa_model, u0, tspan, p)
50+
using OrdinaryDiffEq
51+
oprob = ODEProblem(sa_model, u0, tspan, ps)
4952
nothing # hide
5053
```
5154
Next, we wish to simulate the model for a range of initial conditions of $X$`. To do this we create a problem function, which takes the following arguments:
5255
- `prob`: The problem given to our `EnsembleProblem` (which is the problem that `prob_func` modifies in each iteration).
5356
- `i`: The number of this specific Monte Carlo iteration in the interval `1:trajectories`.
5457
- `repeat`: The iteration of the repeat of the simulation. Typically `1`, but potentially higher if [the simulation re-running option](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#Building-a-Problem) is used.
5558

56-
Here we will use the following problem function (utilising [remake](@ref ref)), which will provide a uniform range of initial concentrations of $X$:
59+
Here we will use the following problem function (utilising [remake](@ref simulation_structure_interfacing_problems_remake)), which will provide a uniform range of initial concentrations of $X$:
5760
```@example ensemble
5861
function prob_func(prob, i, repeat)
5962
remake(prob; u0 = [:X => i * 5.0])

docs/src/model_simulation/ode_simulation_performance.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Generally, this short checklist provides a quick guide for dealing with ODE perf
1313
## [Regarding stiff and non-stiff problems and solvers](@id ode_simulation_performance_stiffness)
1414
Generally, ODE problems can be categorised into [*stiff ODEs* and *non-stiff ODEs*](https://en.wikipedia.org/wiki/Stiff_equation). This categorisation is important due to stiff ODEs requiring specialised solvers. A common cause of failure to simulate an ODE is the use of a non-stiff solver for a stiff problem. There is no exact way to determine whether a given ODE is stiff or not, however, systems with several different time scales (e.g. a CRN with both slow and fast reactions) typically generate stiff ODEs.
1515

16-
Here we simulate the (stiff) [Brusselator](@ref ref) model using the `Tsit5` solver (which is designed for non-stiff ODEs):
16+
Here we simulate the (stiff) [Brusselator](@ref basic_CRN_library_brusselator) model using the `Tsit5` solver (which is designed for non-stiff ODEs):
1717
```@example ode_simulation_performance_1
1818
using Catalyst, OrdinaryDiffEq, Plots
1919
@@ -52,7 +52,7 @@ Finally, we should note that stiffness is not tied to the model equations only.
5252

5353

5454
## [ODE solver selection](@id ode_simulation_performance_solvers)
55-
OrdinaryDiffEq implements an unusually large number of ODE solvers, with the performance of the simulation heavily depending on which one is chosen. These are provided as the second argument to the `solve` command, e.g. here we use the `Tsit5` solver to simulate a simple [birth-death process](@ref ref):
55+
OrdinaryDiffEq implements an unusually large number of ODE solvers, with the performance of the simulation heavily depending on which one is chosen. These are provided as the second argument to the `solve` command, e.g. here we use the `Tsit5` solver to simulate a simple [birth-death process](@ref basic_CRN_library_bd):
5656
```@example ode_simulation_performance_2
5757
using Catalyst, OrdinaryDiffEq
5858
@@ -123,7 +123,7 @@ nothing # hide
123123
### [Using a sparse Jacobian](@id ode_simulation_performance_sparse_jacobian)
124124
For a system with $n$ variables, the Jacobian will be an $n\times n$ matrix. This means that, as $n$ becomes large, the Jacobian can become *very* large, potentially causing a significant strain on memory. In these cases, most Jacobian entries are typically $0$. This means that a [*sparse*](https://en.wikipedia.org/wiki/Sparse_matrix) Jacobian (rather than a *dense* one, which is the default) can be advantageous. To designate sparse Jacobian usage, simply provide the `sparse = true` option when constructing an `ODEProblem`:
125125
```@example ode_simulation_performance_3
126-
oprob = ODEProblem(brusselator, u0, tspan, p; sparse = true)
126+
oprob = ODEProblem(brusselator, u0, tspan, ps; sparse = true)
127127
nothing # hide
128128
```
129129

@@ -172,10 +172,10 @@ Generally, the use of preconditioners is only recommended for advanced users who
172172
## [Parallelisation on CPUs and GPUs](@id ode_simulation_performance_parallelisation)
173173
Whenever an ODE is simulated a large number of times (e.g. when investigating its behaviour for different parameter values), the best way to improve performance is to [parallelise the simulation over multiple processing units](https://en.wikipedia.org/wiki/Parallel_computing). Indeed, an advantage of the Julia programming language is that it was designed after the advent of parallel computing, making it well-suited for this task. Roughly, parallelisation can be divided into parallelisation on [CPUs](https://en.wikipedia.org/wiki/Central_processing_unit) and on [GPUs](https://en.wikipedia.org/wiki/General-purpose_computing_on_graphics_processing_units). CPU parallelisation is most straightforward, while GPU parallelisation requires specialised ODE solvers (which Catalyst have access to).
174174

175-
Both CPU and GPU parallelisation require first building an `EnsembleProblem` (which defines the simulations you wish to perform) and then supplying this with the correct parallelisation options. These have [previously been introduced in Catalyst's documentation](@ref ref) (but in the context of convenient bundling of similar simulations, rather than to improve performance), with a more throughout description being found in [OrdinaryDiffEq's documentation](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#ensemble). Finally, a general documentation of parallel computing in Julia is available [here](https://docs.julialang.org/en/v1/manual/parallel-computing/).
175+
Both CPU and GPU parallelisation require first building an `EnsembleProblem` (which defines the simulations you wish to perform) and then supplying this with the correct parallelisation options. `EnsembleProblem`s have [previously been introduced in Catalyst's documentation](@ref ensemble_simulations) (but in the context of convenient bundling of similar simulations, rather than to improve performance), with a more throughout description being found in [OrdinaryDiffEq's documentation](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#ensemble). Finally, a general documentation of parallel computing in Julia is available [here](https://docs.julialang.org/en/v1/manual/parallel-computing/).
176176

177177
### [CPU parallelisation](@id ode_simulation_performance_parallelisation_CPU)
178-
For this example (and the one for GPUs), we will consider a modified [Michaelis-Menten enzyme kinetics model](@ref ref), which describes an enzyme ($E$) that converts a substrate ($S$) to a product ($P$):
178+
For this example (and the one for GPUs), we will consider a modified [Michaelis-Menten enzyme kinetics model](@ref basic_CRN_library_mm), which describes an enzyme ($E$) that converts a substrate ($S$) to a product ($P$):
179179
```@example ode_simulation_performance_4
180180
using Catalyst
181181
mm_model = @reaction_network begin
@@ -186,12 +186,12 @@ mm_model = @reaction_network begin
186186
end
187187
```
188188
The model can be simulated, showing how $P$ is produced from $S$:
189-
```@example ode_simulation_performance_3
189+
```@example ode_simulation_performance_4
190190
using OrdinaryDiffEq, Plots
191191
u0 = [:S => 1.0, :E => 1.0, :SE => 0.0, :P => 0.0]
192192
tspan = (0.0, 50.0)
193-
p = [:kB => 1.0, :kD => 0.1, :kP => 0.5, :d => 0.1]
194-
oprob = ODEProblem(mm_model, u0, tspan, p)
193+
ps = [:kB => 1.0, :kD => 0.1, :kP => 0.5, :d => 0.1]
194+
oprob = ODEProblem(mm_model, u0, tspan, ps)
195195
sol = solve(oprob, Tsit5())
196196
plot(sol)
197197
```
@@ -208,7 +208,7 @@ Here, `prob_func` takes 3 arguments:
208208

209209
and output the `ODEProblem` simulated in the i'th simulation.
210210

211-
Let us assume that we wish to simulate our model 100 times, for $kP = 0.01, 0.02, ..., 0.99, 1.0$. We define our `prob_func` using [`remake`](@ref ref):
211+
Let us assume that we wish to simulate our model 100 times, for $kP = 0.01, 0.02, ..., 0.99, 1.0$. We define our `prob_func` using [`remake`](@ref simulation_structure_interfacing_problems_remake):
212212
```@example ode_simulation_performance_4
213213
function prob_func(prob, i, repeat)
214214
return remake(prob; p = [:kP => 0.01*i])
@@ -240,12 +240,12 @@ esol = solve(eprob, Tsit5(), EnsembleDistributed(); trajectories=100)
240240
nothing # hide
241241
```
242242
To utilise multiple processes, you must first give Julia access to these. You can check how many processes are available using the `nprocs` (which requires the [Distributed.jl](https://github.com/JuliaLang/Distributed.jl) package):
243-
```julia
243+
```@example ode_simulation_performance_4
244244
using Distributed
245245
nprocs()
246246
```
247247
Next, more processes can be added using `addprocs`. E.g. here we add an additional 4 processes:
248-
```julia
248+
```@example ode_simulation_performance_4
249249
addprocs(4)
250250
nothing # hide
251251
```
@@ -309,7 +309,6 @@ Generally, it is recommended to use `EnsembleGPUArray` for large models (that ha
309309
```julia
310310
esol1 = solve(eprob, Tsit5(), EnsembleGPUArray(CUDA.CUDABackend()); trajectories = 10000)
311311
esol2 = solve(eprob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()); trajectories = 10000)
312-
nothing # hide
313312
```
314313
Note that we have to provide the `CUDA.CUDABackend()` argument to our ensemble algorithms (to designate our GPU backend, in this case, CUDA).
315314

0 commit comments

Comments
 (0)