Lorenz
The Lorenz-63 model of convection, chaotic on a butterfly-shaped attractor for its standard parameters.
- Name:
lorenz - Field:
mathematics/dynamical_systems - Formalism: ordinary differential equations
- References: Lorenz 1963; Datseris and Parlitz 2022
Factory
@register_model(
field='mathematics/dynamical_systems',
tags=('chaos', 'ode', 'strange attractor'),
references=('Lorenz 1963', 'Datseris and Parlitz 2022'),
defaults={'until': 50.0, 'dt': 0.01},
)
def lorenz(
x: float = 1.0,
y: float = 1.0,
z: float = 1.0,
*,
sigma: float = 10.0,
rho: float = 28.0,
beta: float = 8 / 3,
) -> System:
"""Return the Lorenz-63 model of convection, chaotic on a butterfly-shaped attractor for its standard parameters.
Args:
x:
The initial convection intensity.
y:
The initial temperature difference between rising and falling currents.
z:
The initial deviation of the vertical temperature profile.
sigma:
The Prandtl number.
rho:
The Rayleigh number relative to its critical value.
beta:
The geometric factor.
Returns:
system:
The model, with the states `lorenz.x`, `lorenz.y`, and `lorenz.z`.
Examples:
>>> from skcomplex.models.mathematics.dynamical_systems import lorenz
>>> lorenz(rho=20.0).elements[0].rho
20.0
"""
return System(elements=[LorenzElement('lorenz', x=x, y=y, z=z, sigma=sigma, rho=rho, beta=beta)])
Components
class LorenzElement(Element):
"""Lorenz flow `x' = sigma (y - x)`, `y' = x (rho - z) - y`, `z' = x y - beta z`.
A subclass that declares the states with a fractional `StateSpec(order=q)` gives the fractional Lorenz flow with
Caputo derivatives of order `q`.
Args:
label:
The label of the element.
visual:
How the element is drawn, or `None` for `default_visual_`.
x:
The initial convection intensity.
y:
The initial temperature difference between rising and falling currents.
z:
The initial deviation of the vertical temperature profile.
sigma:
The Prandtl number.
rho:
The Rayleigh number relative to its critical value.
beta:
The geometric factor.
Examples:
>>> from skcomplex.core.system import System
>>> from skcomplex.engine.runtime import Simulation
>>> from skcomplex.models.mathematics.common.flows import LorenzElement
>>> system = System(elements=[LorenzElement('lorenz', x=0.0, y=0.0, z=2.0, beta=0.5)])
>>> trajectory = Simulation(system, dt=0.5).check().prepare().run(until=1.0).trajectory_
>>> [round(float(value), 4) for value in trajectory.values('lorenz.z')]
[2.0, 1.5576, 1.2131]
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x: Annotated[float, StateSpec()] = 1.0,
y: Annotated[float, StateSpec()] = 1.0,
z: Annotated[float, StateSpec()] = 1.0,
sigma: Annotated[float, ParameterSpec()] = 10.0,
rho: Annotated[float, ParameterSpec()] = 28.0,
beta: Annotated[float, ParameterSpec()] = 8 / 3,
) -> None:
super().__init__(label, visual=visual)
self.x = x
self.y = y
self.z = z
self.sigma = sigma
self.rho = rho
self.beta = beta
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the rates of the three modes.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The rates of `x`, `y`, and `z`.
"""
return [
RateLaw(s.x, s.sigma * (s.y - s.x)),
RateLaw(s.y, s.x * (s.rho - s.z) - s.y),
RateLaw(s.z, s.x * s.y - s.beta * s.z),
]
Equations
lorenz.x: diff(x_lorenz(t), t) == -sigma_lorenz*(x_lorenz(t) - y_lorenz(t))
lorenz.y: diff(y_lorenz(t), t) == (rho_lorenz - z_lorenz(t))*x_lorenz(t) - y_lorenz(t)
lorenz.z: diff(z_lorenz(t), t) == x_lorenz(t)*y_lorenz(t) - beta_lorenz*z_lorenz(t)