🟢 ABC problem

The goal of this tutorial is to show how to compute a Manifold from a BifurcationProblem as function of two free parameters.

using CairoMakie
using BifurcationKit, MultiParamContinuation

const BK = BifurcationKit
const MPC = MultiParamContinuation

function abc!(dz, z, p, t = 0)
    (;D, B, σ, β, α) = p
    u1, u2, u3 = z
    dz[1] = -u1 + D*(1 - u1)*exp(u3)
    dz[2] = -u2 + D*(1 - u1)*exp(u3) - D*σ*u2*exp(u3)
    dz[3] = -u3 - β*u3 + D*B*(1 - u1)*exp(u3) + D*B*α*σ*u2*exp(u3)
    dz
end

# we group the differentials together
par_abc = (D = 0.11, B = 8., α = 1., σ = 0.04, β = 1.56)
z0 = [1., 0., 0. ]
prob_bk = BifurcationProblem(abc!, z0, par_abc, (@optic _.D),
        record_from_solution = (x, p; k...) -> (u3 = x[3], u1 = x[1], u2 = x[2]),)

opts_br = ContinuationPar(p_max = 1.5, n_inversion = 8, nev = 3)
br = BK.continuation(prob_bk, PALC(), opts_br; normC = norminf)
 ┌─ Curve type: EquilibriumCont
 ├─ Number of points: 38
 ├─ Type of vectors: Vector{Float64}
 ├─ Parameter D starts at 0.11, ends at 1.5
 ├─ Algo: PALC
 └─ Special points:

- #  1,     hopf at D ≈ +0.20599319 ∈ (+0.20599317, +0.20599319), |δp|=2e-08, [converged], δ = ( 2,  2), step =  12
- #  2,     hopf at D ≈ +0.23201597 ∈ (+0.23201591, +0.23201597), |δp|=7e-08, [converged], δ = (-2, -2), step =  16
- #  3,     hopf at D ≈ +0.26423661 ∈ (+0.26423544, +0.26423661), |δp|=1e-06, [converged], δ = ( 2,  2), step =  21
- #  4,     hopf at D ≈ +0.35310237 ∈ (+0.35300637, +0.35310237), |δp|=1e-04, [converged], δ = (-2, -2), step =  28
- #  5, endpoint at D ≈ +1.50000000,                                                                     step =  37

We can also compute the stationary points as function of two free parameters:

prob = MPC.ManifoldProblem_BK(
                        prob_bk, br.sol[1].x, (@optic _.D), (@optic _.β);
                        record_from_solution = (X, p; k...) -> begin
                            return (β = X[end], D = X[end-1], u3 = X[3])
                        end,
                        finalize_solution = (X,p) -> begin
                            D = X[end-1]
                            β = X[end]
                            keep = (0.01 <= D <= 0.5) && (1.5 <= β <= 1.65)
                            return keep
                        end,
                        )

S_eq = @time MPC.continuation(prob,
                        Henderson(np0 = 3,
                                    θmin = 0.001,
                                    # use_curvature = true,
                                    use_tree = true,
                                  ),
                        CoveringPar(max_charts = 20000,
                                max_steps = 1000,
                                verbose = 0,
                                newton_options = NewtonPar(tol = 1e-10),
                                R0 = .04,
                                ϵ = 0.1,
                                delta_angle = 10.15,
                                ))
Surface 2-d
   ├─ # charts = 771
   └─ problem = 

You can plot the data as follows

function plot_data(S; k...)
    fig = Figure()
    ax = Axis3(fig[1,1], zlabel = "u3", xlabel = "D", ylabel = "β", title = "$(length(S)) charts")
    plot_data!(ax, S; k...)
    fig
end

function plot_data!(ax, S; ind = (3,4,5),ind_col = 1, fil=x->true, cols = [real(c.index) for c in filter(x -> fil(x.u), S.atlas)])
    pts = mapreduce(c->[c.u[ind[1]], c.u[ind[2]], c.u[ind[3]]]', vcat, filter(x -> fil(x.u), S.atlas))
    hm = scatter!(ax, pts, color = cols)
end

plot_data(S_eq)
Example block output

Surface of Hopf points as function of 3 parameters

opts_cover = CoveringPar(max_charts = 1000,
    max_steps = 600,
    # verbose = 1,
    newton_options = NewtonPar(tol = 1e-11, verbose = false),
    R0 = .31,
    ϵ = 0.15,
    # delta_angle = 10.15,
    )

atlas_hopf = @time MPC.continuation(deepcopy(br), 1, 
    (@optic _.α), (@optic _.β), 
    opts_cover;
    alg = Henderson(np0 = 5,
                θmin = 0.001,
                use_curvature = false,
                use_tree = true,
            ),
    )
fig = Figure()
ax = Axis3(fig[1,1], zlabel = "β", xlabel = "D", ylabel = "α", title = "Hopf surface $(length(atlas_hopf)) charts")
plot_data!(ax, atlas_hopf, ind = (4,5,6))
fig

Surface of Periodic orbits as function of 2 parameters

We trace the curve of periodic orbits from a Hopf point:

argspo = (record_from_solution = (x, p; k...) -> begin
                xtt = BK.get_periodic_orbit(p.prob, x, p.p)
                return (max = maximum(xtt[3,:]), min = minimum(xtt[3,:]), period = x[end])
            end,
    plot_solution = (ax, x, p; k...) -> begin
        xtt = BK.get_periodic_orbit(p.prob, x, p.p)
        lines!(ax, xtt.t, xtt.u[1,:]; label = "u1", linewidth = 2)
        lines!(ax, xtt.t, xtt.u[2,:]; label = "u2")
        BK.plot!(get(k, :ax1, nothing), br)
    end,)

# continuation parameters
opts_po_cont = ContinuationPar(dsmax = 0.03, dsmin = 1e-4, ds = 0.0005, max_steps = 130, tol_stability = 4e-2, plot_every_step = 20)

br_po = BK.continuation(
    br, 1, opts_po_cont,
    PeriodicOrbitOCollProblem(50, 4; update_section_every_step = 1, jacobian = BK.DenseAnalyticalInplace());
    δp = 0.0001,
    argspo...,
    normC = norminf)
 ┌─ Curve type: PeriodicOrbitCont from Hopf bifurcation point.
 ├─ Number of points: 131
 ├─ Type of vectors: Vector{Float64}
 ├─ Parameter D starts at 0.20609319124934633, ends at 0.24571837750815176
 ├─ Algo: PALC
 └─ Special points:

- #  1,       bp at D ≈ +0.21722034 ∈ (+0.21722034, +0.21722524), |δp|=5e-06, [converged], δ = ( 1,  0), step =  27
- #  2,       bp at D ≈ +0.21468033 ∈ (+0.21468033, +0.21468078), |δp|=4e-07, [converged], δ = (-1,  0), step =  39
- #  3, endpoint at D ≈ +0.24427890,                                                                     step = 131

We can now compute the manifold

using LinearAlgebra
const coll = br_po.prob

prob = MPC.ManifoldProblem_BK(
                        br_po.prob, br_po.sol[1].x, (@optic _.D), (@optic _.β),
                        record_from_solution = (X, p; k...) -> begin
                            xtt = BK.get_periodic_orbit(coll, X[1:end-2], nothing)
                            Max = maximum(xtt[3,:])
                            return (u3 = Max, D = X[end-1], β = X[end], period = X[end-2])
                        end,
                        finalize_solution = (X,p) -> begin
                            D = X[end-1]
                            β = X[end]
                            keep = (0.1 <= D <= 0.5) && (1.5 <= β <= 1.65)
                            return keep #&& norm(X) < 10
                        end,
                        )

S_po = @time MPC.continuation(prob,
                        Henderson(np0 = 6,
                                  θmin = 0.001,
                                  use_curvature = true,
                                  ),
                        CoveringPar(max_charts = 20000,
                                max_steps = 200,
                                verbose = 1,
                                newton_options = NewtonPar(tol = 1e-10, verbose = false),
                                R0 = .95,
                                ϵ = 0.4,
                                delta_angle = 4pi,
                                )
                        )
Surface 2-d
   ├─ # charts = 200
   └─ problem = 
fig = Figure()
ax3 = Axis3(fig[1,1], zlabel = "u3", xlabel = "D", ylabel = "β", title = "PO $(length(S_po)) charts")
pts = mapreduce(c->[c.data[1], c.data[3], c.data[4]]', vcat, S_po.atlas)
scatter!(ax3, pts, color = [c.data[2] for c in S_po.atlas])
fig
Example block output