Takens-Bogdanov
The Takens-Bogdanov normal form x' = y, y' = β1 + β2 x + x² + s x y, where a saddle-node meets a Hopf.
- Name:
takens_bogdanov_form - Field:
mathematics/dynamical_systems - Formalism: ordinary differential equations
- References: Gros 2015; Dilão 2023
Factory
@register_model(
field='mathematics/dynamical_systems',
tags=('bifurcation', 'normal form', 'ode', 'codimension two'),
references=('Gros 2015', 'Dilão 2023'),
defaults={'until': 50.0, 'dt': 0.1},
)
def takens_bogdanov_form(
x: float = 0.2,
y: float = 0.0,
*,
beta1: float = 0.1,
beta2: float = -1.0,
sign: float = -1.0,
) -> System:
"""Return the Takens-Bogdanov normal form `x' = y`, `y' = β1 + β2 x + x² + s x y`, where a saddle-node meets a Hopf.
Args:
x:
The initial position.
y:
The initial velocity.
beta1:
The first unfolding parameter.
beta2:
The second unfolding parameter.
sign:
The sign `s` of the mixed term, `-1` or `1`.
Returns:
system:
The model, with the states `form.x` and `form.y`.
Examples:
>>> from skcomplex.models.mathematics.dynamical_systems import takens_bogdanov_form
>>> takens_bogdanov_form(beta1=0.0).elements[0].beta1
0.0
"""
return System(elements=[TakensBogdanovElement('form', x=x, y=y, beta1=beta1, beta2=beta2, sign=sign)])
Components
class TakensBogdanovElement(Element):
"""Normal form `x' = y`, `y' = beta1 + beta2 x + x^2 + sign x y` of the Takens-Bogdanov bifurcation.
Args:
label:
The label of the element.
visual:
How the element is drawn, or `None` for `default_visual_`.
x:
The initial first coordinate.
y:
The initial second coordinate.
beta1:
The first unfolding parameter.
beta2:
The second unfolding parameter.
sign:
The sign of the term `x y`, 1 or -1.
Examples:
>>> from skcomplex.models.mathematics.dynamical_systems import TakensBogdanovElement
>>> TakensBogdanovElement('form', beta1=0.0).beta1
0.0
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x: Annotated[object, StateSpec()] = 0.2,
y: Annotated[object, StateSpec()] = 0.0,
beta1: Annotated[object, ParameterSpec()] = 0.1,
beta2: Annotated[object, ParameterSpec()] = -1.0,
sign: Annotated[object, ParameterSpec()] = -1.0,
) -> None:
super().__init__(label, visual=visual)
self.x = x
self.y = y
self.beta1 = beta1
self.beta2 = beta2
self.sign = sign
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the rates of the two coordinates.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The laws of the element.
"""
return [RateLaw(s.x, s.y), RateLaw(s.y, s.beta1 + s.beta2 * s.x + s.x**2 + s.sign * s.x * s.y)]
Equations
form.x: diff(x_form(t), t) == y_form(t)
form.y: diff(y_form(t), t) == sign_form*x_form(t)*y_form(t) + beta2_form*x_form(t) + x_form(t)^2 + beta1_form