|
| 1 | +# [Ensemble/Monte Carlo Simulations](@id ensemble_simulations) |
| 2 | +In many contexts, a single model is re-simulated under similar conditions. Examples include: |
| 3 | +- Performing Monte Carlo simulations of a stochastic model to gain insight in its behaviour. |
| 4 | +- Scanning the behaviour of a model for different parameter values and/or initial conditions. |
| 5 | + |
| 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/). |
| 7 | + |
| 8 | +## [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 |
| 10 | +```@example ensemble |
| 11 | +using Catalyst |
| 12 | +sa_model = @reaction_network begin |
| 13 | + v0 + hill(X,v,K,n), ∅ --> X |
| 14 | + deg, X --> ∅ |
| 15 | +end |
| 16 | +u0 = [:X => 10.0] |
| 17 | +tspan = (0.0, 1000.0) |
| 18 | +ps = [:v0 => 0.1, :v => 2.5, :K => 40.0, :n => 4.0, :deg => 0.01] |
| 19 | +``` |
| 20 | +We wish to simulate it as an SDE. Rather than performing a single simulation, however, we want to make multiple ones. Here, we first create a normal `SDEProblem`, and use it as the single input to a `EnsembleProblem` (similar for ODEs and jump simulations, but the `ODEProblem` or `JumpProblem` is used instead). |
| 21 | +```@example ensemble |
| 22 | +sprob = SDEProblem(sa_model, u0, tspan, ps) |
| 23 | +eprob = EnsembleProblem(sprob) |
| 24 | +nothing # hide |
| 25 | +``` |
| 26 | +Next, the `EnsembleProblem` can be used as input to the `solve` command. Here, we use exactly the same inputs that we use for single simulations, however, we add a `trajectories` argument to denote how many simulations we wish to carry out. Here we perform 100 simulations: |
| 27 | +```@example ensemble |
| 28 | +sols = solve(eprob, STrapezoid(); trajectories = 100) |
| 29 | +nothing # hide |
| 30 | +``` |
| 31 | +Finally, we can use our ensemble simulation solution as input to `plot` (just like normal simulations): |
| 32 | +```@example ensemble |
| 33 | +plot(sols; la = 0.5) |
| 34 | +``` |
| 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. |
| 36 | + |
| 37 | +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: |
| 38 | +```@example ensemble |
| 39 | +e_sumary = EnsembleAnalysis.EnsembleSummary(sols, 0.0:1.0:1000.0) |
| 40 | +plot(e_sumary) |
| 41 | +``` |
| 42 | + |
| 43 | +## [Ensemble simulations using varying simulation conditions](@id ensemble_simulations_varying_conditions) |
| 44 | +Previously, we assumed that each simulation used the same initial conditions and parameter values. If this is not the case (when e.g. performing a parameter scan), a `prob_func` optional argument must be supplied to the `EnsembleProblem`, this describes how the problem should be modified for each individual simulation of the ensemble. |
| 45 | + |
| 46 | +Here, we first create an `ODEProblem` of our previous self-activation loop: |
| 47 | +```@example ensemble |
| 48 | +oprob = ODEProblem(sa_model, u0, tspan, p) |
| 49 | +nothing # hide |
| 50 | +``` |
| 51 | +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: |
| 52 | +- `prob`: The problem given to our `EnsembleProblem`, which is the problem that |
| 53 | + `prob_func` modifies in each iteration. |
| 54 | +- `i`: The number of this specific Monte Carlo iteration in the interval |
| 55 | + `1:trajectories`. |
| 56 | +- `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. |
| 57 | + |
| 58 | +Here we will use the following problem function, which will provide a uniform range of initial conditions: |
| 59 | +```@example ensemble |
| 60 | +function prob_func(prob, i, repeat) |
| 61 | + remake(prob; u0 = [:X => i * 5.0]) |
| 62 | +end |
| 63 | +nothing # hide |
| 64 | +``` |
| 65 | +Next, we create our `EnsembleProblem`, and simulate it 10 times: |
| 66 | +```@example ensemble |
| 67 | +eprob = EnsembleProblem(oprob; prob_func) |
| 68 | +sols = solve(eprob, Tsit5(); trajectories = 10) |
| 69 | +plot(sols) |
| 70 | +``` |
| 71 | +Here we see that the deterministic model (unlike the stochastic one), only activates for some initial conditions (while other tends to an inactive state). |
| 72 | + |
| 73 | +The `EnsembleProblem` constructor accepts a few additional optional options (`output_func`, `reduction`, `u_init`, and `safetycopy`), which are described in more detail [here](https://docs.sciml.ai/DiffEqDocs/stable/features/ensemble/#Building-a-Problem). These can be used to e.g. rerun an individual simulation which does not fulfil some condition, or extract and save only some selected information from a simulation (rather than the full simulation). |
0 commit comments