from tvbo import Dynamics
model_yaml = """
name: TsodyksMarkram
description: Tsodyks-Markram mean-field model with synaptic plasticity
parameters:
J: {name: J, value: 3.07, domain: {lo: 0, hi: 10}}
alpha: {name: alpha, value: 1.4, domain: {lo: 0.1, hi: 5}}
E0: {name: E0, value: -2.0, domain: {lo: -10, hi: 2}}
tau: {name: tau, value: 0.013, domain: {lo: 0.001, hi: 0.1}}
tauD: {name: tauD, value: 0.20, domain: {lo: 0.01, hi: 1.0}}
tauF: {name: tauF, value: 1.5, domain: {lo: 0.1, hi: 5.0}}
U0: {name: U0, value: 0.3, domain: {lo: 0, hi: 1}}
derived_variables:
SS0: {name: SS0, equation: {lhs: SS0, rhs: "J*u*x*E + E0"}}
SS1: {name: SS1, equation: {lhs: SS1, rhs: "alpha*log(1 + exp(SS0/alpha))"}}
state_variables:
E:
name: E
initial_value: 0.238616
equation: {lhs: "Derivative(E, t)", rhs: "(-E + SS1)/tau"}
x:
name: x
initial_value: 0.982747
equation: {lhs: "Derivative(x, t)", rhs: "(1 - x)/tauD - u*x*E"}
u:
name: u
initial_value: 0.367876
equation: {lhs: "Derivative(u, t)", rhs: "(U0 - u)/tauF + U0*(1 - u)*E"}
number_of_modes: 1
"""
# Load model from inline YAML string
model = Dynamics.from_string(model_yaml)Tsodyks-Markram Neural Mass Model
Replicating BifurcationKit.jl TMModel.jl with all 4 PO discretization methods
Overview
This example replicates the Tsodyks-Markram tutorial from BifurcationKit.jl’s official documentation, demonstrating all four periodic orbit discretization methods:
- Collocation — Orthogonal collocation at Gauss points
- Trapezoid — Finite-difference trapezoid rule
- Shooting — Standard multiple shooting
- Poincaré — Poincaré shooting on a hyperplane
The model describes short-term synaptic plasticity with three variables: - E: Mean firing rate - x: Synaptic depression (available neurotransmitter) - u: Synaptic facilitation (release probability)
Model Definition (Inline YAML with Dynamics.from_string)
Method 1: Collocation (Adaptive Mesh)
Orthogonal collocation with automatic mesh refinement:
from tvbo import SimulationExperiment, Continuation
po_collocation = """
name: tm_po_collocation
dynamics: TsodyksMarkram
free_parameters:
- name: E0
domain: {lo: "-2", hi: "-1"}
bothside: true
branches:
- name: po_from_hopf
source_point: "hopf:2"
bothside: false
continuation:
name: tm_po_collocation_po_from_hopf
ds: 0.001
ds_min: 1.0e-4
ds_max: 0.1
max_steps: 110
tol_stability: 1.0e-5
discretization:
method: collocation
mesh_intervals: 50
degree: 4
linear_solver:
method: COPBLS
parameters:
- {name: mesh_adaptation, value: true}
"""
cont = Continuation.from_string(po_collocation)
exp = SimulationExperiment(dynamics=model, continuations=[cont])
print(exp.render_code('bifurcationkit.jl'))using BifurcationKit
using OrdinaryDiffEq
function TsodyksMarkram!(dx, _x, p, t = 0)
(;J, alpha, E0, tau, tauD, tauF, U0) = p
E, x, u = _x
SS0 = E0 + E .* J .* u .* x
SS1 = alpha .* log(1 + exp(SS0 ./ alpha))
dx[1] = (SS1 - E) ./ tau
dx[2] = (1 - x) ./ tauD - E .* u .* x
dx[3] = (U0 - u) ./ tauF + E .* U0 .* (1 - u)
dx
end
# Parameter values
p = (J = 3.07, alpha = 1.4, E0 = -2.0, tau = 0.013, tauD = 0.2, tauF = 1.5, U0 = 0.3)
# Override continuation parameter to start within [p_min, p_max]
p = merge(p, (E0 = -2.0,))
# Initial conditions from model defaults
x0 = [
0.238616, # Initial value for E
0.982747, # Initial value for x
0.367876, # Initial value for u
]
# Wrapper: BifurcationKit expects f!(du, x, p) (no explicit time argument)
function TsodyksMarkram_vf!(du, x, p)
TsodyksMarkram!(du, x, p, 0.0) # pass dummy time
return du
end
# Find a steady state via time integration (more robust than raw Newton on x0)
function _find_steady_state(f!, x0, p; T=2000.0)
function ode_f!(du, u, _p, t)
f!(du, u, p, t)
end
prob_ode = ODEProblem{true, SciMLBase.FullSpecialize}(ode_f!, x0, (0.0, T), p)
sol = solve(prob_ode; abstol=1e-10, reltol=1e-10, save_everystep=false)
return sol[:, end]
end
x0_eq = _find_steady_state(TsodyksMarkram!, x0, p)
# Record named state variables for each continuation step
record_from_sol = (x, p; k...) -> (E = x[1], x = x[2], u = x[3],)
# Bifurcation Problem
prob = BifurcationProblem(TsodyksMarkram_vf!, x0_eq, p, (@optic _.E0);
record_from_solution = record_from_sol)
# ContinuationPar
opts_br = ContinuationPar(p_min = -2.0,
p_max = -1.0)
using Logging
prev_logger = current_logger()
global_logger(SimpleLogger(devnull, Logging.Error))
br = continuation(prob, PALC(), opts_br; normC = norminf, bothside = true)
global_logger(prev_logger)
bifurcation_result = br
# Record PO envelope (max/min per state variable)
args_po = ( record_from_solution = (x, p; k...) -> begin
xtt = get_periodic_orbit(p.prob, x, p.p)
return (
max_E = maximum(xtt[1,:]),
min_E = minimum(xtt[1,:]),
max_x = maximum(xtt[2,:]),
min_x = minimum(xtt[2,:]),
max_u = maximum(xtt[3,:]),
min_u = minimum(xtt[3,:]),
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 = "E", arg..., k...)
plot!(xtt.t, xtt[2,:]; label = "x", arg..., k...)
plot!(xtt.t, xtt[3,:]; label = "u", arg..., k...)
plot!(br; subplot = 1, putspecialptlegend = false)
end,
normC = norminf)
opts_po_cont = ContinuationPar(opts_br, ds = 0.001, dsmin = 0.0001, dsmax = 0.1, max_steps = 110, tol_stability = 1e-05)
hopf_indices = Int[]
for (i, sp) in enumerate(br.specialpoint)
sp.type == :hopf && push!(hopf_indices, i)
end
if !isempty(hopf_indices)
hopf_indices = [hopf_indices[2]]
end
po_branches = Any[]
for hopf_idx in hopf_indices
try
br_po = continuation(
br, hopf_idx, opts_po_cont,
PeriodicOrbitOCollProblem(50, 4, meshadapt = true);
plot = false,
args_po...,
linear_algo = COPBLS(),
verbosity = 0,
)
push!(po_branches, br_po)
catch e
@warn "PO continuation from Hopf $hopf_idx failed" exception=(e, catch_backtrace())
end
end
po_results = (hopf_indices = hopf_indices, branches = po_branches)
result = exp.run('bifurcationkit.jl')
result.plot()Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython

Click to expand: Generated Julia code for collocation method
print(exp.render_code('bifurcationkit.jl'))using BifurcationKit
using OrdinaryDiffEq
function TsodyksMarkram!(dx, _x, p, t = 0)
(;J, alpha, E0, tau, tauD, tauF, U0) = p
E, x, u = _x
SS0 = E0 + E .* J .* u .* x
SS1 = alpha .* log(1 + exp(SS0 ./ alpha))
dx[1] = (SS1 - E) ./ tau
dx[2] = (1 - x) ./ tauD - E .* u .* x
dx[3] = (U0 - u) ./ tauF + E .* U0 .* (1 - u)
dx
end
# Parameter values
p = (J = 3.07, alpha = 1.4, E0 = -2.0, tau = 0.013, tauD = 0.2, tauF = 1.5, U0 = 0.3)
# Override continuation parameter to start within [p_min, p_max]
p = merge(p, (E0 = -2.0,))
# Initial conditions from model defaults
x0 = [
0.238616, # Initial value for E
0.982747, # Initial value for x
0.367876, # Initial value for u
]
# Wrapper: BifurcationKit expects f!(du, x, p) (no explicit time argument)
function TsodyksMarkram_vf!(du, x, p)
TsodyksMarkram!(du, x, p, 0.0) # pass dummy time
return du
end
# Find a steady state via time integration (more robust than raw Newton on x0)
function _find_steady_state(f!, x0, p; T=2000.0)
function ode_f!(du, u, _p, t)
f!(du, u, p, t)
end
prob_ode = ODEProblem{true, SciMLBase.FullSpecialize}(ode_f!, x0, (0.0, T), p)
sol = solve(prob_ode; abstol=1e-10, reltol=1e-10, save_everystep=false)
return sol[:, end]
end
x0_eq = _find_steady_state(TsodyksMarkram!, x0, p)
# Record named state variables for each continuation step
record_from_sol = (x, p; k...) -> (E = x[1], x = x[2], u = x[3],)
# Bifurcation Problem
prob = BifurcationProblem(TsodyksMarkram_vf!, x0_eq, p, (@optic _.E0);
record_from_solution = record_from_sol)
# ContinuationPar
opts_br = ContinuationPar(p_min = -2.0,
p_max = -1.0)
using Logging
prev_logger = current_logger()
global_logger(SimpleLogger(devnull, Logging.Error))
br = continuation(prob, PALC(), opts_br; normC = norminf, bothside = true)
global_logger(prev_logger)
bifurcation_result = br
# Record PO envelope (max/min per state variable)
args_po = ( record_from_solution = (x, p; k...) -> begin
xtt = get_periodic_orbit(p.prob, x, p.p)
return (
max_E = maximum(xtt[1,:]),
min_E = minimum(xtt[1,:]),
max_x = maximum(xtt[2,:]),
min_x = minimum(xtt[2,:]),
max_u = maximum(xtt[3,:]),
min_u = minimum(xtt[3,:]),
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 = "E", arg..., k...)
plot!(xtt.t, xtt[2,:]; label = "x", arg..., k...)
plot!(xtt.t, xtt[3,:]; label = "u", arg..., k...)
plot!(br; subplot = 1, putspecialptlegend = false)
end,
normC = norminf)
opts_po_cont = ContinuationPar(opts_br, ds = 0.001, dsmin = 0.0001, dsmax = 0.1, max_steps = 110, tol_stability = 1e-05)
hopf_indices = Int[]
for (i, sp) in enumerate(br.specialpoint)
sp.type == :hopf && push!(hopf_indices, i)
end
if !isempty(hopf_indices)
hopf_indices = [hopf_indices[2]]
end
po_branches = Any[]
for hopf_idx in hopf_indices
try
br_po = continuation(
br, hopf_idx, opts_po_cont,
PeriodicOrbitOCollProblem(50, 4, meshadapt = true);
plot = false,
args_po...,
linear_algo = COPBLS(),
verbosity = 0,
)
push!(po_branches, br_po)
catch e
@warn "PO continuation from Hopf $hopf_idx failed" exception=(e, catch_backtrace())
end
end
po_results = (hopf_indices = hopf_indices, branches = po_branches)
Method 2: Trapezoid (Finite Differences)
po_trapezoid = """
name: tm_po_trapezoid
dynamics: TsodyksMarkram
free_parameters:
- name: E0
domain: {lo: "-2", hi: "-1"}
bothside: false
branches:
- name: po_from_hopf
source_point: "hopf:2"
bothside: false
delta_p: 0.001
continuation:
name: tm_po_trapezoid_po_from_hopf
ds: 0.004
ds_min: 1.0e-4
ds_max: 0.1
max_steps: 80
newton_tol: 1.0e-7
tol_stability: 1.0e-7
discretization:
method: trapezoid
mesh_intervals: 250
"""
cont_trap = Continuation.from_string(po_trapezoid)
exp_trap = SimulationExperiment(dynamics=model, continuations=[cont_trap])
result_trap = exp_trap.run('bifurcationkit.jl')
result_trap.plot()
Method 3: Standard Shooting
Multiple ODE integrations:
po_shooting = """
name: tm_po_shooting
dynamics: TsodyksMarkram
free_parameters:
- name: E0
domain: {lo: "-2", hi: "-1"}
bothside: false
branches:
- name: po_from_hopf
source_point: "hopf:2"
bothside: false
continuation:
name: tm_po_shooting_po_from_hopf
ds: -0.0001
ds_min: 1.0e-4
ds_max: 0.1
max_steps: 110
tol_stability: 1.0e-4
discretization:
method: shooting
n_sections: 15
ode_solver:
method: Rodas5
abs_tol: 1e-11
rel_tol: 1e-9
linear_solver:
method: MatrixBLS
parameters:
- {name: parallel, value: true}
parameters:
- {name: max_norm_bound, value: 10}
"""
cont_shoot = Continuation.from_string(po_shooting)
exp_shoot = SimulationExperiment(dynamics=model, continuations=[cont_shoot])
print(exp_shoot.render_code('bifurcationkit.jl'))
result_shoot = exp_shoot.run('bifurcationkit.jl')
result_shoot.plot()using BifurcationKit
using OrdinaryDiffEq
function TsodyksMarkram!(dx, _x, p, t = 0)
(;J, alpha, E0, tau, tauD, tauF, U0) = p
E, x, u = _x
SS0 = E0 + E .* J .* u .* x
SS1 = alpha .* log(1 + exp(SS0 ./ alpha))
dx[1] = (SS1 - E) ./ tau
dx[2] = (1 - x) ./ tauD - E .* u .* x
dx[3] = (U0 - u) ./ tauF + E .* U0 .* (1 - u)
dx
end
# Parameter values
p = (J = 3.07, alpha = 1.4, E0 = -2.0, tau = 0.013, tauD = 0.2, tauF = 1.5, U0 = 0.3)
# Override continuation parameter to start within [p_min, p_max]
p = merge(p, (E0 = -2.0,))
# Initial conditions from model defaults
x0 = [
0.238616, # Initial value for E
0.982747, # Initial value for x
0.367876, # Initial value for u
]
# Wrapper: BifurcationKit expects f!(du, x, p) (no explicit time argument)
function TsodyksMarkram_vf!(du, x, p)
TsodyksMarkram!(du, x, p, 0.0) # pass dummy time
return du
end
# Find a steady state via time integration (more robust than raw Newton on x0)
function _find_steady_state(f!, x0, p; T=2000.0)
function ode_f!(du, u, _p, t)
f!(du, u, p, t)
end
prob_ode = ODEProblem{true, SciMLBase.FullSpecialize}(ode_f!, x0, (0.0, T), p)
sol = solve(prob_ode; abstol=1e-10, reltol=1e-10, save_everystep=false)
return sol[:, end]
end
x0_eq = _find_steady_state(TsodyksMarkram!, x0, p)
# Record named state variables for each continuation step
record_from_sol = (x, p; k...) -> (E = x[1], x = x[2], u = x[3],)
# Bifurcation Problem
prob = BifurcationProblem(TsodyksMarkram_vf!, x0_eq, p, (@optic _.E0);
record_from_solution = record_from_sol)
# ContinuationPar
opts_br = ContinuationPar(p_min = -2.0,
p_max = -1.0)
using Logging
prev_logger = current_logger()
global_logger(SimpleLogger(devnull, Logging.Error))
br = continuation(prob, PALC(), opts_br; normC = norminf)
global_logger(prev_logger)
bifurcation_result = br
# Record PO envelope (max/min per state variable)
args_po = ( record_from_solution = (x, p; k...) -> begin
xtt = get_periodic_orbit(p.prob, x, p.p)
return (
max_E = maximum(xtt[1,:]),
min_E = minimum(xtt[1,:]),
max_x = maximum(xtt[2,:]),
min_x = minimum(xtt[2,:]),
max_u = maximum(xtt[3,:]),
min_u = minimum(xtt[3,:]),
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 = "E", arg..., k...)
plot!(xtt.t, xtt[2,:]; label = "x", arg..., k...)
plot!(xtt.t, xtt[3,:]; label = "u", arg..., k...)
plot!(br; subplot = 1, putspecialptlegend = false)
end,
normC = norminf)
opts_po_cont = ContinuationPar(opts_br, ds = -0.0001, dsmin = 0.0001, dsmax = 0.1, max_steps = 110, tol_stability = 0.0001)
hopf_indices = Int[]
for (i, sp) in enumerate(br.specialpoint)
sp.type == :hopf && push!(hopf_indices, i)
end
if !isempty(hopf_indices)
hopf_indices = [hopf_indices[2]]
end
po_branches = Any[]
for hopf_idx in hopf_indices
try
prob_ode = ODEProblem(TsodyksMarkram!, copy(x0), (0.0, 1000.0), p; abstol = 1e-11, reltol = 1e-09)
br_po = continuation(
br, hopf_idx, opts_po_cont,
ShootingProblem(15, prob_ode, OrdinaryDiffEq.Rodas5(), parallel = true);
plot = false,
args_po...,
linear_algo = MatrixBLS(),
verbosity = 0,
callback_newton = BifurcationKit.cbMaxNorm(10.0),
)
push!(po_branches, br_po)
catch e
@warn "PO continuation from Hopf $hopf_idx failed" exception=(e, catch_backtrace())
end
end
po_results = (hopf_indices = hopf_indices, branches = po_branches)
┌ Warning: The precision on the Floquet multipliers is 2.7325737521308788e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 1.6608328073070823e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 6.0082349790657e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 9.880189533591978e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 3.0721707767302713e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 1.3692887806327293e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.0132061834608382e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.053749993407368e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 4.619286624211238e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 6.629710205322572e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.7429833284198744e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 8.543418545033322e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 9.352746726560644e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 1.5273626913157446e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 1.0217241889194383e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.4033044820767986e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 8.650176405149776e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.462513068246181e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 5.292521616683653e-8.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 2.981830153426688e-7.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 6.7424765105167595e-6.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 7.435102071965049e-5.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0018416937626528865.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0006300493108742717.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 1.5178653135453317e-5.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.00029068875963047153.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0011994743538063198.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.03654867173517135.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 5.173064841587385.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 3.3851362095468835.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 3.508758292012897.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 3.290534010435416.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 3.263381794732664.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 9.994243285299158.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 17.314820800964128.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80

Method 4: Poincaré Shooting
Reduced-dimension shooting:
po_poincare = """
name: tm_po_poincare
dynamics: TsodyksMarkram
free_parameters:
- name: E0
domain: {lo: "-2", hi: "-1"}
bothside: false
branches:
- name: po_from_hopf
source_point: "hopf:2"
bothside: false
continuation:
name: tm_po_poincare_po_from_hopf
ds: 0.0001
ds_max: 0.02
max_steps: 50
newton_tol: 1.0e-9
newton_max_iterations: 15
tol_stability: 1.0e-6
detect_bifurcation: 2
discretization:
method: poincare
n_sections: 5
ode_solver:
method: Rodas5
abs_tol: 1e-11
rel_tol: 1e-9
linear_solver:
method: MatrixBLS
parameters:
- {name: parallel, value: true}
parameters:
- {name: max_norm_bound, value: 1.0}
"""
cont_poinc = Continuation.from_string(po_poincare)
exp_poinc = SimulationExperiment(dynamics=model, continuations=[cont_poinc])
print(exp_poinc.render_code('bifurcationkit.jl'))
result_poinc = exp_poinc.run('bifurcationkit.jl')
result_poinc.plot()using BifurcationKit
using OrdinaryDiffEq
function TsodyksMarkram!(dx, _x, p, t = 0)
(;J, alpha, E0, tau, tauD, tauF, U0) = p
E, x, u = _x
SS0 = E0 + E .* J .* u .* x
SS1 = alpha .* log(1 + exp(SS0 ./ alpha))
dx[1] = (SS1 - E) ./ tau
dx[2] = (1 - x) ./ tauD - E .* u .* x
dx[3] = (U0 - u) ./ tauF + E .* U0 .* (1 - u)
dx
end
# Parameter values
p = (J = 3.07, alpha = 1.4, E0 = -2.0, tau = 0.013, tauD = 0.2, tauF = 1.5, U0 = 0.3)
# Override continuation parameter to start within [p_min, p_max]
p = merge(p, (E0 = -2.0,))
# Initial conditions from model defaults
x0 = [
0.238616, # Initial value for E
0.982747, # Initial value for x
0.367876, # Initial value for u
]
# Wrapper: BifurcationKit expects f!(du, x, p) (no explicit time argument)
function TsodyksMarkram_vf!(du, x, p)
TsodyksMarkram!(du, x, p, 0.0) # pass dummy time
return du
end
# Find a steady state via time integration (more robust than raw Newton on x0)
function _find_steady_state(f!, x0, p; T=2000.0)
function ode_f!(du, u, _p, t)
f!(du, u, p, t)
end
prob_ode = ODEProblem{true, SciMLBase.FullSpecialize}(ode_f!, x0, (0.0, T), p)
sol = solve(prob_ode; abstol=1e-10, reltol=1e-10, save_everystep=false)
return sol[:, end]
end
x0_eq = _find_steady_state(TsodyksMarkram!, x0, p)
# Record named state variables for each continuation step
record_from_sol = (x, p; k...) -> (E = x[1], x = x[2], u = x[3],)
# Bifurcation Problem
prob = BifurcationProblem(TsodyksMarkram_vf!, x0_eq, p, (@optic _.E0);
record_from_solution = record_from_sol)
# ContinuationPar
opts_br = ContinuationPar(p_min = -2.0,
p_max = -1.0)
using Logging
prev_logger = current_logger()
global_logger(SimpleLogger(devnull, Logging.Error))
br = continuation(prob, PALC(), opts_br; normC = norminf)
global_logger(prev_logger)
bifurcation_result = br
# Record PO envelope (max/min per state variable)
args_po = ( record_from_solution = (x, p; k...) -> begin
xtt = get_periodic_orbit(p.prob, x, p.p)
return (
max_E = maximum(xtt[1,:]),
min_E = minimum(xtt[1,:]),
max_x = maximum(xtt[2,:]),
min_x = minimum(xtt[2,:]),
max_u = maximum(xtt[3,:]),
min_u = minimum(xtt[3,:]),
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 = "E", arg..., k...)
plot!(xtt.t, xtt[2,:]; label = "x", arg..., k...)
plot!(xtt.t, xtt[3,:]; label = "u", arg..., k...)
plot!(br; subplot = 1, putspecialptlegend = false)
end,
normC = norminf)
opts_po_cont = ContinuationPar(opts_br, ds = 0.0001, dsmax = 0.02, max_steps = 50, tol_stability = 1e-06, detect_bifurcation = 2, newton_options = NewtonPar(tol = 1e-09, max_iterations = 15))
hopf_indices = Int[]
for (i, sp) in enumerate(br.specialpoint)
sp.type == :hopf && push!(hopf_indices, i)
end
if !isempty(hopf_indices)
hopf_indices = [hopf_indices[2]]
end
po_branches = Any[]
for hopf_idx in hopf_indices
try
prob_ode = ODEProblem(TsodyksMarkram!, copy(x0), (0.0, 1000.0), p; abstol = 1e-11, reltol = 1e-09)
br_po = continuation(
br, hopf_idx, opts_po_cont,
PoincareShootingProblem(5, prob_ode, OrdinaryDiffEq.Rodas5(), parallel = true);
plot = false,
args_po...,
linear_algo = MatrixBLS(),
verbosity = 0,
callback_newton = BifurcationKit.cbMaxNorm(1.0),
)
push!(po_branches, br_po)
catch e
@warn "PO continuation from Hopf $hopf_idx failed" exception=(e, catch_backtrace())
end
end
po_results = (hopf_indices = hopf_indices, branches = po_branches)
┌ Warning: The precision on the Floquet multipliers is 0.0017909760569191637.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0018828209805575177.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0020191811303651376.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.002224173828630299.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.002537209906612921.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.0030244330012906004.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.00379941752373453.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.005003853176015959.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.006903079664666693.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.00992039286214593.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.014688694739140175.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.02202096026559467.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.032548096533339954.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.04522347053831872.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.05160803258031889.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.04213113410655399.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: The precision on the Floquet multipliers is 0.038771208490223696.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: Verbosity toggle: max_iters
│ Interrupted. Larger maxiters is needed. If you are using an integrator for non-stiff ODEs or an automatic switching algorithm (the default), you may want to consider using a method for stiff equations. See the solver pages for more details (e.g. https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/#Stiff-Problems).
└ @ SciMLBase ~/.julia/packages/SciMLBase/eTBDr/src/integrator_interface.jl:679
┌ Warning: Verbosity toggle: max_iters
│ Interrupted. Larger maxiters is needed. If you are using an integrator for non-stiff ODEs or an automatic switching algorithm (the default), you may want to consider using a method for stiff equations. See the solver pages for more details (e.g. https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/#Stiff-Problems).
└ @ SciMLBase ~/.julia/packages/SciMLBase/eTBDr/src/integrator_interface.jl:679
┌ Warning: The precision on the Floquet multipliers is 0.03747986179125429.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Warning: Verbosity toggle: max_iters
│ Interrupted. Larger maxiters is needed. If you are using an integrator for non-stiff ODEs or an automatic switching algorithm (the default), you may want to consider using a method for stiff equations. See the solver pages for more details (e.g. https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/#Stiff-Problems).
└ @ SciMLBase ~/.julia/packages/SciMLBase/eTBDr/src/integrator_interface.jl:679
┌ Warning: The precision on the Floquet multipliers is 0.03699846553120567.
│ Either decrease `tol_stability` in the option ContinuationPar or use a different method than `FloquetQaD`.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/periodicorbit/Floquet.jl:80
┌ Error: Failure to converge with given tolerance = 1.0e-9.
│ Step = 18
│ You can decrease the tolerance or pass a different norm using the argument `normC`.
│ We reached the smallest value [dsmin] valid for ds, namely 0.0001.
│ Stopping continuation at continuation step 18.
└ @ BifurcationKit ~/.julia/packages/BifurcationKit/Y3DPO/src/continuation/Contbase.jl:73
