BifurcationKit: detecting fold bifurcation

This post is related to my previous one.

I am new to bifurcation analyis and I am working with BifurcationKit to reproduce the bifurcation analysis performed by Grimbert Faugueras on the Jansen-Rit model.

Specifically, I want to reproduce these 2 figures:


I am not able to detect the fold bifurcation of limit cycles at p = 137.5.

I have tried continuation with detect_fold = true:

and computing branches of periodic orbits starting from the 1st Hopf point.

Since the branch I am trying to find is disconnected from the main branch, do I need to use deflated continuation? I don’t understand how to use deflated continuation.

My code so far is below, any help would be appreciated.

using Revise, Plots
using BifurcationKit

const BK = BifurcationKit

# Define the function Οƒ
function Οƒ(v, e0 = 2.5, v0 = 6, r=0.56)
    2 * e0 / (1 + exp(r * (v0 - v)))
end

# vector field
function jansenrit(z, param)
	(;A, a, B, b, C1, C2, C3, C4, p) = param
	y0, y3, y1, y4, y2, y5 = z
	[
	    y3
        A * a * Οƒ(y1 - y2) - 2 * a * y3 - a^2 * y0
        y4
        A * a * (p + C2 * Οƒ(C1 * y0)) - 2 * a * y4 - a^2 * y1
        y5
        B * b * C4 * Οƒ(C3 * y0) - 2 * b * y5 - b^2 * y2
	]
end

# parameter values
C= 135
par = (A = 3.25, a = 100, B = 22, b = 50, C1 = C, C2 = 0.8 * C, C3 = 0.25 * C, C4 = 0.25 * C, p = 50.0)

# initial condition
z0 = [0.0, 0.0, 15.0, 0.0, 10.0, 0.0]

# Bifurcation Problem
prob = BifurcationProblem(jansenrit, z0, par, (@optic _.p);
	record_from_solution = (x, p; k...) -> (y0 = x[1],y3 = x[2],y1 = x[3],y4 = x[4],y2 = x[5],y5 = x[6],),)

optnewton = NewtonPar(tol = 1e-11, verbose = true)

# continuation options, we limit the parameter range for p
opts_br = ContinuationPar(p_min = -50.0, p_max = 400.0, max_steps = 8000, newton_options = optnewton, detect_fold = true)

# continuation of equilibria
br = continuation(prob, PALC(), opts_br;
	# we want to compute both sides of the branch of the initial
	# value of p = 100
	bothside = true, normC = norminf)

#propertynames(br)
scene = plot(br, legend=:topleft)

print("PERIODIC ORBITS")

# arguments for periodic orbits
# one function to record information and one
# function for plotting
args_po = (	record_from_solution = (x, p; k...) -> begin
		xtt = get_periodic_orbit(p.prob, x, p.p)
		return (max = maximum(xtt[1,:]),
				min = minimum(xtt[1,:]),
				period = getperiod(p.prob, x, p.p))
	end,
	plot_solution = (x, p; k...) -> begin
		xtt = get_periodic_orbit(p.prob, x, p.p)
		arg = (marker = :d, markersize = 1)
		plot!(xtt.t, xtt[1,:]; label = "y0", arg..., k...)
		plot!(xtt.t, xtt[2,:]; label = "y3", arg..., k...)
		plot!(xtt.t, xtt[3,:]; label = "y1", arg..., k...)
        plot!(xtt.t, xtt[4,:]; label = "y4", arg..., k...)
		plot!(xtt.t, xtt[5,:]; label = "y2", arg..., k...)
		plot!(xtt.t, xtt[6,:]; label = "y5", arg..., k...)
		plot!(br; subplot = 1, putspecialptlegend = false)
		end,
	# we use the supremum norm
	normC = norminf)

# continuation parameters
opts_po_cont = ContinuationPar(opts_br, ds= 0.001, dsmin = 1e-4, dsmax = 0.1,
	max_steps = 1000,
	tol_stability = 1e-5)

br_pocoll = @time continuation(
	# we want to branch from the 5th bif. point
	br, 4, opts_po_cont,
	# we want to use the Collocation method to locate PO, with polynomial degree 4
	PeriodicOrbitOCollProblem(50, 4; meshadapt = true);
	# regular continuation options
	normC = norminf,
	args_po...)

colour_stability = [stable ? :green : :red for stable in br_pocoll.stable]

plot(br, branchlabel = "equilibria")
plot!(br_pocoll.param, br_pocoll.max, label = "periodic orbits max", color = colour_stability)
plot!(br_pocoll.param, br_pocoll.min, color = colour_stability)
1 Like

The problem is again the tolerance as for the fixed points. I dont know why but it can’t get to 1e-11 in sup norm. You can see that by looking at the newton iterations:

opts_br_po = ContinuationPar(p_min =-100.0, p_max = 400.0, max_steps = 3000, newton_options = NewtonPar(tol = 1e-12, verbose = true), plot_every_step = 150, detect_bifurcation = 0)

br_po2 = @time continuation(br, 3, opts_br_po,
                    PeriodicOrbitOCollProblem(50,5; jacobian = BK.DenseAnalyticalInplace(), meshadapt = true);
                    verbosity = 1,
                    plot = true,
                    alg = PALC(tangent = Bordered()),
                    linear_algo = COPBLS(),
                    normC = norminf,

which gives

Continuation step 310 
Step size = 1.0000e-04
Parameter p = 1.4571e+01 ⟢  1.4571e+01 [guess]

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Newton step         residual      linear iterations β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚       0     β”‚       3.3916e-05     β”‚        0       β”‚
β”‚       1     β”‚       1.2987e-11     β”‚        1       β”‚
β”‚       2     β”‚       2.9181e-12     β”‚        1       β”‚
β”‚       3     β”‚       3.4021e-12     β”‚        1       β”‚
β”‚       4     β”‚       1.1385e-11     β”‚        1       β”‚
β”‚       5     β”‚       7.6389e-12     β”‚        1       β”‚
β”‚       6     β”‚       2.2868e-12     β”‚        1       β”‚
β”‚       7     β”‚       1.7537e-11     β”‚        1       β”‚
β”‚       8     β”‚       1.4163e-11     β”‚        1       β”‚
β”‚       9     β”‚       1.0234e-11     β”‚        1       β”‚
β”‚      10     β”‚       8.0037e-12     β”‚        1       β”‚
β”‚      11     β”‚       1.0922e-11     β”‚        1       β”‚
β”‚      12     β”‚       1.2774e-11     β”‚        1       β”‚
β”‚      13     β”‚       1.9409e-11     β”‚        1       β”‚
β”‚      14     β”‚       1.2409e-11     β”‚        1       β”‚
β”‚      15     β”‚       7.0216e-12     β”‚        1       β”‚
β”‚      16     β”‚       7.3513e-12     β”‚        1       β”‚
β”‚      17     β”‚       1.6162e-11     β”‚        1       β”‚
β”‚      18     β”‚       3.1005e-12     β”‚        1       β”‚
β”‚      19     β”‚       3.1916e-12     β”‚        1       β”‚
β”‚      20     β”‚       9.8766e-12     β”‚        1       β”‚
β”‚      21     β”‚       2.0967e-11     β”‚        1       β”‚
β”‚      22     β”‚       6.6990e-12     β”‚        1       β”‚
β”‚      23     β”‚       2.3850e-12     β”‚        1       β”‚
β”‚      24     β”‚       1.5516e-11     β”‚        1       β”‚
β”‚      25     β”‚       2.2145e-11     β”‚        1       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Instead, if you use smaller tolerances:

br_po2 = @time continuation(br, 3, opts_br_po,
                    PeriodicOrbitOCollProblem(50,5; jacobian = BK.DenseAnalyticalInplace(), meshadapt = true);
                    verbosity = 1,
                    alg = PALC(tangent = Bordered()),
                    normC = norminf,
                    callback_newton = BK.cbMaxNorm(1e2), #limit residual to avoid Inf or NaN
                )

plot(br, br_po, br_po2)
plot!(br_po2, vars=(:param, :min))

1 Like

Thanks for looking into this @rveltz
Is it meant to be BK.DenseAnalytical() instead of BK.DenseAnalyticalInplace()? I am getting:
UndefVarError: DenseAnalyticalInplace not defined in BifurcationKit and I have the latest version (0.4.4)

Sorry, discard this. It is a new faster jacobian that will be added soon

1 Like

Ok! Can you send me the exact code you used? I am trying what you said and I am failing to converge

br_po2 = @time continuation(br, 3, opts_br_po,
                    PeriodicOrbitOCollProblem(50,5; jacobian = BK.DenseAnalytical(), meshadapt = true);
                    verbosity = 0,
                    plot = true,
                    alg = PALC(tangent = Bordered()),
                    linear_algo = COPBLS(),
                    normC = norminf,
                    callback_newton = BK.cbMaxNorm(1e2), #limit residual to avoid Inf or NaN
)

Should the second param be 4 instead of 3?

AssertionError: The provided index does not refer to a Hopf Point

If I run the below, I get:

β”Œ Error: Failure to converge with given tolerances.
β”‚ We reached the smallest value [dsmin] valid for ds, namely 0.0001.
β”‚ Stopping continuation at continuation step 374.

using Revise, Plots
using BifurcationKit

const BK = BifurcationKit

# Define the function Οƒ
function Οƒ(v, e0 = 2.5, v0 = 6, r=0.56)
    2 * e0 / (1 + exp(r * (v0 - v)))
end

# vector field
function jansenrit(z, param)
	(;A, a, B, b, C1, C2, C3, C4, p) = param
	y0, y3, y1, y4, y2, y5 = z
	[
	    y3
        A * a * Οƒ(y1 - y2) - 2 * a * y3 - a^2 * y0
        y4
        A * a * (p + C2 * Οƒ(C1 * y0)) - 2 * a * y4 - a^2 * y1
        y5
        B * b * C4 * Οƒ(C3 * y0) - 2 * b * y5 - b^2 * y2
	]
end

# parameter values
C= 135
par = (A = 3.25, a = 100, B = 22, b = 50, C1 = C, C2 = 0.8 * C, C3 = 0.25 * C, C4 = 0.25 * C, p = 50.0)

# initial condition
z0 = [0.0, 0.0, 15.0, 0.0, 10.0, 0.0]

# Bifurcation Problem
prob = BifurcationProblem(jansenrit, z0, par, (@optic _.p);
	record_from_solution = (x, p; k...) -> (y0 = x[1],y3 = x[2],y1 = x[3],y4 = x[4],y2 = x[5],y5 = x[6],),)

optnewton = NewtonPar(tol = 1e-11, verbose = true)

# continuation options, we limit the parameter range for p
opts_br = ContinuationPar(p_min = -50.0, p_max = 400.0, max_steps = 8000, newton_options = optnewton)
	
# continuation of equilibria
br = continuation(prob, PALC(), opts_br;
	# we want to compute both sides of the branch of the initial
	# value of p = 100
	bothside = true, normC = norminf)
	
scene = plot(br, legend=:topleft)


print("PERIODIC ORBITS")

# continuation parameters
opts_br_po = ContinuationPar(p_min =-100.0, p_max = 400.0, max_steps = 3500, newton_options = NewtonPar(tol = 1e-12, verbose = true), plot_every_step = 150, detect_bifurcation = 0)

br_po2 = @time continuation(br, 4, opts_br_po,
                    PeriodicOrbitOCollProblem(50,5; jacobian = BK.DenseAnalytical(), meshadapt = true);
                    verbosity = 0,
                    plot = true,
                    alg = PALC(tangent = Bordered()),
                    linear_algo = COPBLS(),
                    normC = norminf,
                    callback_newton = BK.cbMaxNorm(1e2), #limit residual to avoid Inf or NaN
)

plot(br, br_po, br_po2)
plot!(br_po2, vars=(:param, :min))

yes

same as above decrease tol in newtonPar for periodicorbits

Thanks, I have managed to reproduce the figure! I now want to colour the branches based on stability. However, br_po.stable and br_po_2.stable contain nothing.

I have also noticed that the branches contain many fold points, with guess status. Is this related to the above?

No, it is because it is close to the homoclinic point. Their distance is 1e-4 !

very interesting work

1 Like

Is there another way of determining the stability of the periodic orbit branches? Or is it impossible because of the homoclinic orbit?

It is because the tolerance on the stability is a bit too high. If you look at

You can remediate to these spurious bifurcations by looking at br_po2.eig, there should always be the zero Floquet exponent. But close to the homoclinic, it is difficult to get it precisely. This can cause spurious detection of bifurcatons.

You can change this by specifying a tolerance for stability:

opts_br_po = ContinuationPar(opts_br, p_min =-100.0, p_max = 400.0, max_steps = 3000, dsmax = 0.3, newton_options = NewtonPar(tol = 1e-10, verbose = false), plot_every_step = 150, detect_bifurcation = 3, tol_stability = 1e-4)

I will remediate to that in the near future

Thanks! I am getting the stability now but I still have way more special points than I should. Is there also a way of remediating this?

if you zoom on the homoclinic point, it gives:

If you want to better resolve this zone you can increase the descretization. You can also try a different method to compute the periodic orbit

using OrdinaryDiffEq
prob_ode = ODEProblem(jansenrit!, z0, (0,1.), par)
br_po2 = continuation(br, 3, opts_br_po,
                    # PeriodicOrbitOCollProblem(50,5; jacobian = BK.DenseAnalyticalInplace(), meshadapt = true);
                    ShootingProblem(6, prob_ode, Rodas5(); abstol = 1e-10, reltol = 1e-8, parallel = true);
                    verbosity = 1,
                    plot = true,
                    alg = PALC(tangent = Bordered()),
                    normC = norminf,
                    callback_newton = BK.cbMaxNorm(1e2),
)
1 Like

And how do I increase the discretisation? Is that N in PeriodicOrbitOCollProblem?

1 Like

yes

but I would not worry too much about those bifurcations, you are very close to the homoclinic point

1 Like