|
| 1 | +# [Bifurcation Diagrams](@id bifurcation_diagrams) |
| 2 | +Bifurcation diagrams describes how, for a dynamic system, the quantity and quality of its steady states changes with a parameter's value. These can be computed through the [BifurcationKit.jl](https://github.com/bifurcationkit/BifurcationKit.jl) package. ModelingToolkit provides a simple interface for creating BifurcationKit compatible `BifurcationProblem`s from `NonlinearSystem`s and `ODESystem`s. All teh features provided by BifurcationKit can then be applied to these systems. This tutorial provides a brief introduction for these features, with BifurcationKit.jl providing [a more extensive documentation](https://bifurcationkit.github.io/BifurcationKitDocs.jl/stable/). |
| 3 | + |
| 4 | +### Creating a `BifurcationProblem` |
| 5 | +Let us first consider a simple `NonlinearSystem`: |
| 6 | +```@example Bif1 |
| 7 | +using ModelingToolkit |
| 8 | +@variables t x(t) y(t) |
| 9 | +@parameters μ α |
| 10 | +eqs = [0 ~ μ*x - x^3 + α*y, |
| 11 | + 0 ~ -y] |
| 12 | +@named nsys = NonlinearSystem(eqs, [x, y], [μ, α]) |
| 13 | +``` |
| 14 | +we wish to compute a bifurcation diagram for this system as we vary the parameter `μ`. For this, we need to provide the following information: |
| 15 | +1. The system for which we wish to compute the bifurcation diagram (`nsys`). |
| 16 | +2. The parameter which we wish to vary (`μ`). |
| 17 | +3. The parameter set for which we want to compute the bifurcation diagram. |
| 18 | +4. An initial guess of the state of the system for which there is a steady state at our provided parameter value. |
| 19 | +5. The variable which value we wish to plot in the bifurcation diagram (this argument is optional, if not provided, BifurcationKit default plot functions are used). |
| 20 | + |
| 21 | +We declare this additional information: |
| 22 | +```@example Bif1 |
| 23 | +bif_par = μ |
| 24 | +p_start = [μ => -1.0, α => 1.0] |
| 25 | +u0_guess = [x => 1.0, y => 1.0] |
| 26 | +plot_var = x; |
| 27 | +``` |
| 28 | +For the initial state guess (`u0_guess`), typically any value can be provided, however, read BifurcatioKit's documentation for more details. |
| 29 | + |
| 30 | +We can now create our `BifurcationProblem`, which can be provided as input to BifurcationKit's various functions. |
| 31 | +```@example Bif1 |
| 32 | +using BifurcationKit |
| 33 | +bprob = BifurcationProblem(nsys, u0_guess, p_start, bif_par; plot_var=plot_var, jac=false) |
| 34 | +``` |
| 35 | +Here, the `jac` argument (by default set to `true`) sets whenever to provide BifurcationKit with a Jacobian or not. |
| 36 | + |
| 37 | + |
| 38 | +### Computing a bifurcation diagram |
| 39 | + |
| 40 | +Let us consider the `BifurcationProblem` from the last section. If we wish to compute the corresponding bifurcation diagram we must first declare various settings used by BifurcationKit to compute the diagram. These are stored in a `ContinuationPar` structure (which also contain a `NewtonPar` structure). |
| 41 | +```@example Bif1 |
| 42 | +p_span = (-4.0, 6.0) |
| 43 | +opt_newton = NewtonPar(tol = 1e-9, max_iterations = 20) |
| 44 | +opts_br = ContinuationPar(dsmin = 0.001, dsmax = 0.05, ds = 0.01, |
| 45 | + max_steps = 100, nev = 2, newton_options = opt_newton, |
| 46 | + p_min = p_span[1], p_max = p_span[2], |
| 47 | + detect_bifurcation = 3, n_inversion = 4, tol_bisection_eigenvalue = 1e-8, dsmin_bisection = 1e-9); |
| 48 | +``` |
| 49 | +Here, `p_span` sets the interval over which we wish to compute the diagram. |
| 50 | + |
| 51 | +Next, we can use this as input to our bifurcation diagram, and then plot it. |
| 52 | +```@example Bif1 |
| 53 | +bf = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside=true) |
| 54 | +``` |
| 55 | +Here, the value `2` sets how sub-branches of the diagram that BifurcationKit should compute. Generally, for bifurcation diagrams, it is recommended to use the `bothside=true` argument. |
| 56 | +```@example Bif1 |
| 57 | +using Plots |
| 58 | +plot(bf; putspecialptlegend=false, markersize=2, plotfold=false, xguide="μ", yguide = "x") |
| 59 | +``` |
| 60 | +Here, the system exhibits a pitchfork bifurcation at *μ=0.0*. |
| 61 | + |
| 62 | +### Using `ODESystem` inputs |
| 63 | +It is also possible to use `ODESystem`s (rather than `NonlinearSystem`s) as input to `BifurcationProblem`. Here follows a brief such example. |
| 64 | + |
| 65 | +```@example Bif2 |
| 66 | +using BifurcationKit, ModelingToolkit, Plots |
| 67 | +
|
| 68 | +@variables t x(t) y(t) |
| 69 | +@parameters μ |
| 70 | +D = Differential(t) |
| 71 | +eqs = [D(x) ~ μ*x - y - x*(x^2+y^2), |
| 72 | + D(y) ~ x + μ*y - y*(x^2+y^2)] |
| 73 | +@named osys = ODESystem(eqs, t) |
| 74 | +
|
| 75 | +bif_par = μ |
| 76 | +plot_var = x |
| 77 | +p_start = [μ => 1.0] |
| 78 | +u0_guess = [x => 0.0, y=> 0.0] |
| 79 | +
|
| 80 | +bprob = BifurcationProblem(osys, u0_guess, p_start, bif_par; plot_var=plot_var, jac=false) |
| 81 | +
|
| 82 | +p_span = (-3.0, 3.0) |
| 83 | +opt_newton = NewtonPar(tol = 1e-9, max_iterations = 20) |
| 84 | +opts_br = ContinuationPar(dsmin = 0.001, dsmax = 0.05, ds = 0.01, |
| 85 | + max_steps = 100, nev = 2, newton_options = opt_newton, |
| 86 | + p_max = p_span[2], p_min = p_span[1], |
| 87 | + detect_bifurcation = 3, n_inversion = 4, tol_bisection_eigenvalue = 1e-8, dsmin_bisection = 1e-9) |
| 88 | +
|
| 89 | +bf = bifurcationdiagram(bprob, PALC(), 2, (args...) -> opts_br; bothside=true) |
| 90 | +using Plots |
| 91 | +plot(bf; putspecialptlegend=false, markersize=2, plotfold=false, xguide="μ", yguide = "x") |
| 92 | +``` |
| 93 | +Here, the value of `x` in the steady state does not change, however, at `μ=0` a Hopf bifurcation occur and the steady state turn unstable. |
0 commit comments