Hutchinson with Diffusion (codim2, sparse matrices, periodic orbits)

Consider the Hutchinson equation with diffusion

\[\begin{aligned} & \frac{\partial u(t, x)}{\partial t}=d \frac{\partial^2 u(t, x)}{\partial x^2}-a u(t-1, x)[1+u(t, x)], \quad t>0, x \in(0, \pi), \\ & \frac{\partial u(t, x)}{\partial x}=0, x=0, \pi \end{aligned}\]

where $a>0, d>0$.

Problem discretization

We start by discretizing the above PDE based on finite differences.

using Revise, DDEBifurcationKit, Plots, SparseArrays, LinearAlgebrausing BifurcationKitconst BK = BifurcationKitfunction Hutchinson(u, ud, p)   (; a, d, Δ) = p   d .** u) .- a .* ud.u[1] .* (1 .+ u)enddelaysF(par) = [1.]

Bifurcation analysis

We can now instantiate the model

# discretisationNx = 200; Lx = pi/2;X = -Lx .+ 2Lx/Nx*(0:Nx-1) |> collecth = 2Lx/NxΔ = spdiagm(0 => -2ones(Nx), 1 => ones(Nx-1), -1 => ones(Nx-1) ) / h^2; Δ[1,1]=Δ[end,end]=-1/h^2

We are now ready to compute the bifurcation of the trivial (constant in space) solution:

# bifurcation problempars = (a = 0.5, d = 1.0, τ = 1.0, Δ = Δ, N = Nx)x0 = zeros(Nx)prob = ConstantDDEBifProblem(Hutchinson, delaysF, x0, pars, (@optic _.a))optn = NewtonPar(eigsolver = DDE_DefaultEig())opts = ContinuationPar(p_max = 10., p_min = 0., newton_options = optn, ds = 0.01, detect_bifurcation = 3, nev = 5, dsmax = 0.2, n_inversion = 4)br = continuation(prob, PALC(), opts; normC = norminf)br
 ┌─ Curve type: EquilibriumCont
 ├─ Number of points: 42
 ├─ Type of vectors: Vector{Float64}
 ├─ Parameter a starts at 0.5, ends at 10.0
 ├─ Algo: PALC [Secant]
 └─ Special points:

- #  1,     hopf at a ≈ +1.57668056 ∈ (+1.56784173, +1.57668056), |δp|=9e-03, [converged], δ = ( 2,  2), step =  10
- #  2,     hopf at a ≈ +2.26389996 ∈ (+2.26169025, +2.26389996), |δp|=2e-03, [converged], δ = ( 2,  2), step =  13
- #  3,     hopf at a ≈ +4.75534651 ∈ (+4.75424166, +4.75534651), |δp|=1e-03, [converged], δ = ( 2,  2), step =  22
- #  4,     hopf at a ≈ +9.43550952 ∈ (+9.43109010, +9.43550952), |δp|=4e-03, [converged], δ = ( 2,  2), step =  39
- #  5, endpoint at a ≈ +10.00000000,                                                                     step =  41

We note that the first Hopf point is close to the theoretical value $a=\frac\pi 2$. This can be improved by increasing opts.n_inversion.

We can now plot the branch

scene = plot(br)
Example block output

Performance improvements

The previous implementation being simple, it leaves a lot of performance on the table. For example, the jacobian is dense because it is computed with automatic differentiation without sparsity detection.

We show how to specify the jacobian and speed up the code a lot.

# analytical jacobianfunction JacHutchinson(u, p)   (;a, d, Δ) = p   # we compute the jacobian at the steady state   J0 = d * Δ .- a .* Diagonal(u)   J1 = -a .* Diagonal(1 .+ u)   return J0, [J1]endprob2 = ConstantDDEBifProblem(Hutchinson, delaysF, x0, pars, (@optic _.a); J = JacHutchinson)optn = NewtonPar(eigsolver = DDE_DefaultEig())opts = ContinuationPar(p_max = 10., p_min = 0., newton_options = optn, ds = 0.01, detect_bifurcation = 3, nev = 5, dsmax = 0.2, n_inversion = 4)br = continuation(prob2, PALC(), opts; normC = norminf)br
 ┌─ Curve type: EquilibriumCont
 ├─ Number of points: 42
 ├─ Type of vectors: Vector{Float64}
 ├─ Parameter a starts at 0.5, ends at 10.0
 ├─ Algo: PALC [Secant]
 └─ Special points:

- #  1,     hopf at a ≈ +1.57668056 ∈ (+1.56784173, +1.57668056), |δp|=9e-03, [converged], δ = ( 2,  2), step =  10
- #  2,     hopf at a ≈ +2.26389996 ∈ (+2.26169025, +2.26389996), |δp|=2e-03, [converged], δ = ( 2,  2), step =  13
- #  3,     hopf at a ≈ +4.75534651 ∈ (+4.75424166, +4.75534651), |δp|=1e-03, [converged], δ = ( 2,  2), step =  22
- #  4,     hopf at a ≈ +9.43550952 ∈ (+9.43109010, +9.43550952), |δp|=4e-03, [converged], δ = ( 2,  2), step =  39
- #  5, endpoint at a ≈ +10.00000000,                                                                     step =  41

We can compute the Hopf normal form

get_normal_form(br, 1)
SuperCritical - Hopf bifurcation point at a ≈ 1.5766805597910794.
Frequency ω ≈ 1.572488487324084
Period of the periodic orbit ≈ 3.995695585582144
Normal form z⋅(iω + a⋅δa + b⋅|z|²):
┌─ a = 0.4520928886866457 + 0.28642933056270276im
└─ b = -0.0016905496698795845 - 0.002052701380718443im

Continuation of Hopf points

brhopfs = [continuation(br, i, (@optic _.d),         ContinuationPar(br.contparams, detect_bifurcation = 2, p_min = 0.1, p_max = 2.5, max_steps = 1000);         verbosity = 2,         detect_codim2_bifurcation = 2,         plot = true,         bothside = true,         jacobian_ma = BK.MinAugMatrixBased(),         ) for i = 1:3]plot(brhopfs..., title = "Hopf curves")
Example block output

Computation of the periodic orbit

br_pocoll = @time continuation(            br, 1, ContinuationPar(br.contparams; detect_bifurcation = 0, max_steps = 3, newton_options = NewtonPar(eigsolver = DDE_DefaultEig(), verbose = true), plot_every_step = 1),            Collocation(20, 4; jacobian = BK.FullSparse());            verbosity = 2,            plot = true,            normC = norminf,            )plot(br, br_pocoll)
Example block output

We can plot a solution from the curve

sol = BK.get_periodic_orbit(br_pocoll, 3)heatmap(sol.t, X, sol[:,:], xlabel = "time")
Example block output

References