|
| 1 | +# `CoupledSDEs` |
| 2 | + |
| 3 | +```@docs |
| 4 | +CoupledSDEs |
| 5 | +``` |
| 6 | + |
| 7 | +## [Examples defining stochastic dynamics](@id defining-stochastic-dynamics) |
| 8 | + |
| 9 | +Let's look at some examples of the different types of stochastic systems that can be defined. |
| 10 | + |
| 11 | +For simplicity, we choose a slow exponential growth in 2 dimensions as the deterministic dynamics `f`: |
| 12 | +```@example type |
| 13 | +using DynamicalSystemsBase, StochasticDiffEq, DiffEqNoiseProcess |
| 14 | +using CairoMakie |
| 15 | +import Random # hide |
| 16 | +Random.seed!(10) # hide |
| 17 | +f!(du, u, p, t) = du .= 1.01u # deterministic part |
| 18 | +
|
| 19 | +function plot_trajectory(Y, t) |
| 20 | + fig = Figure() |
| 21 | + ax = Axis(fig[1,1]; xlabel = "time", ylabel = "variable") |
| 22 | + for var in columns(Y) |
| 23 | + lines!(ax, t, var) |
| 24 | + end |
| 25 | + fig |
| 26 | +end; |
| 27 | +``` |
| 28 | + |
| 29 | +### Additive noise |
| 30 | +When $g(u, p, t)$ is independent of the state $u$, the noise is called additive; otherwise, it is multiplicative. |
| 31 | +We can define a simple additive noise system as follows: |
| 32 | +```@example type |
| 33 | +sde = CoupledSDEs(f!, zeros(2)); |
| 34 | +``` |
| 35 | +which is equivalent to |
| 36 | +```@example type |
| 37 | +t0 = 0.0; W0 = zeros(2); |
| 38 | +W = WienerProcess(t0, W0, 0.0) |
| 39 | +sde = CoupledSDEs(f!, zeros(2); |
| 40 | + noise_process=W, covariance=[1 0; 0 1], noise_strength=1.0 |
| 41 | + ); |
| 42 | +``` |
| 43 | +We defined a Wiener process `W`, whose increments are vectors of normally distributed random numbers of length matching the output of `g`. The noise is applied element-wise, i.e., `g.*dW`. Since the noise processes are uncorrelated, meaning the covariance matrix is diagonal, this type of noise is referred to as diagonal. |
| 44 | + |
| 45 | +We can sample a trajectory from this system using the `trajectory` function also used for the deterministic systems: |
| 46 | +```@example type |
| 47 | +tr = trajectory(sde, 1.0) |
| 48 | +plot_trajectory(tr...) |
| 49 | +``` |
| 50 | + |
| 51 | +#### Correlated noise |
| 52 | +In the case of correlated noise, the random numbers in a vector increment `dW` are correlated. This can be achieved by specifying the covariance matrix $\Sigma$ via the `covariance` keyword: |
| 53 | +```@example type |
| 54 | +ρ = 0.3 |
| 55 | +Σ = [1 ρ; ρ 1] |
| 56 | +diffeq = (alg = LambaEM(), dt=0.1) |
| 57 | +sde = CoupledSDEs(f!, zeros(2); covariance=Σ, diffeq=diffeq) |
| 58 | +``` |
| 59 | +Alternatively, we can parametrise the covariance matrix by defining the diffusion function $g$ ourselves: |
| 60 | +```@example type |
| 61 | +g!(du, u, p, t) = (du .= [1 p[1]; p[1] 1]; return nothing) |
| 62 | +sde = CoupledSDEs(f!, zeros(2), (ρ); g=g!, noise_prototype=zeros(2, 2)) |
| 63 | +``` |
| 64 | +Here, we had to provide `noise_prototype` to indicate that the diffusion function `g` will output a 2x2 matrix. |
| 65 | + |
| 66 | +#### Scalar noise |
| 67 | +If all state variables are forced by the same single random variable, we have scalar noise. |
| 68 | +To define scalar noise, one has to give an one-dimensional noise process to the `noise_process` keyword of the `CoupledSDEs` constructor. |
| 69 | +```@example type |
| 70 | +t0 = 0.0; W0 = 0.0; |
| 71 | +noise = WienerProcess(t0, W0, 0.0) |
| 72 | +sde = CoupledSDEs(f!, rand(2)/10; noise_process=noise) |
| 73 | +
|
| 74 | +tr = trajectory(sde, 1.0) |
| 75 | +plot_trajectory(tr...) |
| 76 | +``` |
| 77 | +We can see that noise applied to each variable is the same. |
| 78 | + |
| 79 | +### Multiplicative and time-dependent noise |
| 80 | +In the SciML ecosystem, multiplicative noise is defined through the condition $g_i(t, u)=a_i u$. However, in the literature the name is more broadly used for any situation where the noise is non-additive and depends on the state $u$, possibly also in a non-linear way. When defining a `CoupledSDEs`, we can make the noise term time- and state-dependent by specifying an explicit time- or state-dependence in the noise function `g`, just like we would define `f`. For example, we can define a system with temporally decreasing multiplicative noise as follows: |
| 81 | +```@example type |
| 82 | +function g!(du, u, p, t) |
| 83 | + du .= u ./ (1+t) |
| 84 | + return nothing |
| 85 | +end |
| 86 | +sde = CoupledSDEs(f!, rand(2)./10; g=g!) |
| 87 | +``` |
| 88 | + |
| 89 | +#### Non-diagonal noise |
| 90 | +Non-diagonal noise allows for the terms to be linearly mixed (correlated) via `g` being a matrix. Suppose we have two Wiener processes and two state variables such that the output of `g` is a 2x2 matrix. Therefore, we have |
| 91 | +```math |
| 92 | +du_1 = f_1(u,p,t)dt + g_{11}(u,p,t)dW_1 + g_{12}(u,p,t)dW_2 \\ |
| 93 | +du_2 = f_2(u,p,t)dt + g_{21}(u,p,t)dW_1 + g_{22}(u,p,t)dW_2 |
| 94 | +``` |
| 95 | +To indicate the structure that `g` should have, we must use the `noise_prototype` keyword. Let us define a special type of non-diagonal noise called commutative noise. For this we can utilize the `RKMilCommute` algorithm which is designed to utilize the structure of commutative noise. |
| 96 | + |
| 97 | +```@example type |
| 98 | +σ = 0.25 # noise strength |
| 99 | +function g!(du, u, p, t) |
| 100 | + du[1,1] = σ*u[1] |
| 101 | + du[2,1] = σ*u[2] |
| 102 | + du[1,2] = σ*u[1] |
| 103 | + du[2,2] = σ*u[2] |
| 104 | + return nothing |
| 105 | +end |
| 106 | +diffeq = (alg = RKMilCommute(), reltol = 1e-3, abstol = 1e-3, dt=0.1) |
| 107 | +sde = CoupledSDEs(f!, rand(2)./10; g=g!, noise_prototype = zeros(2, 2), diffeq = diffeq) |
| 108 | +``` |
| 109 | + |
| 110 | +!!! warning |
| 111 | + Non-diagonal problems need specific solvers. See the [SciML recommendations](https://docs.sciml.ai/DiffEqDocs/stable/solvers/sde_solve/#sde_solve). |
0 commit comments