Skip to content

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)