Lorenz-96
Lorenz-96 on a ring of sites around a latitude circle.
- Class:
Lorenz96System - Import:
from skcomplex.systems.physics.climate import Lorenz96System - Field:
physics/climate - Topics:
chaos,ode,atmosphere,spatiotemporal chaos,data assimilation - References: Lorenz 1996; Datseris and Parlitz 2022
Use this system
from skcomplex.core.engine.runtime import simulate
from skcomplex.systems.physics.climate import Lorenz96System
trajectory = simulate(Lorenz96System())
Parameters
| Parameter | Default |
|---|---|
n_sites |
20 |
F |
8.0 |
perturbation |
0.01 |
Tags
| Tag | Values |
|---|---|
| Time | continuous |
| Space | continuous |
| Laws | rate |
| Randomness | deterministic |
| Domains | vector |
| Structure | fixed |
Class
class Lorenz96System(BaseSystem):
"""Lorenz-96 on a ring of sites around a latitude circle.
Every site follows `dx_i/dt = (x_{i+1} - x_{i-2}) x_{i-1} - x_i + F`.
The sites start at the steady state `F`, and the first one is displaced by `perturbation`. For `F = 8` the steady
state is unstable and the ring is chaotic. The system has the values `ring.x` of all sites.
Args:
n_sites:
The number of sites, at least 4, the dimension of the state `x`.
F:
The constant forcing.
perturbation:
The displacement of the first site from the steady state.
label:
The label of the system, which names it when it is nested in another one.
Examples:
>>> from skcomplex.systems.physics.climate import Lorenz96System
>>> Lorenz96System(6).prepare().system_.space.n_dim
6
"""
field = 'physics/climate'
topics = ('chaos', 'ode', 'atmosphere', 'spatiotemporal chaos', 'data assimilation')
references = ('Lorenz 1996', 'Datseris and Parlitz 2022')
until = 20.0
dt = 0.05
def __init__(
self,
n_sites: int = 20,
*,
F: float = 8.0,
perturbation: float = 0.01,
label: str = 'system',
) -> None:
super().__init__(label)
self.n_sites = n_sites
self.F = F
self.perturbation = perturbation
def _build_system(self) -> System:
"""Return the parts of the system, built from its model parameters."""
values = np.full(self.n_sites, float(self.F))
values[0] += self.perturbation
return System(
self.label,
elements=[Lorenz96Element('ring', x=values, F=self.F)],
space=ContinuousSpace(n_dim=self.n_sites),
)
Components
Elements:
Lorenz96Element, fromElement
class Lorenz96Element(Element):
"""Ring of Lorenz-96 sites around a latitude circle.
The sites are advected by their neighbours, damped, and forced.
Every site follows `dx_i/dt = (x_{i+1} - x_{i-2}) x_{i-1} - x_i + F`, with the indices taken around the ring.
Args:
label:
The label of the ring.
visual:
How the element is drawn, or `None` for `default_visual_`.
x:
The initial values of all sites.
F:
The constant forcing.
Examples:
>>> from skcomplex.systems.physics.climate import Lorenz96Element
>>> Lorenz96Element('ring').F
8.0
"""
law_classes = (RateLaw,)
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x: Annotated[npt.ArrayLike, StateSpec(vector=True)] = 8.0,
F: Annotated[float, ParameterSpec()] = 8.0,
) -> None:
super().__init__(label, visual=visual)
self.x = x
self.F = F
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the advection, damping, and forcing of every site of the ring.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The rate law of the values of all sites.
"""
x = s.x
n_sites = len(x)
rates = [(x[(i + 1) % n_sites] - x[i - 2]) * x[i - 1] - x[i] + s.F for i in range(n_sites)]
return [RateLaw(s.x, vector(SR, rates))]