Lorenz96

Lorenz96(
    var_name='lorenz96',
    n=40,
    J=0,
    F=8.0,
    h=1.0,
    b=10.0,
    c=10.0,
    exact_rhs=False,
    state_variables=None,
    diagnostic_variables=None,
    *args,
    **kwargs,
)

Lorenz (1996) single-scale and two-scale atmospheric model.

A periodic ring of n slow-scale variables with quadratic advection and constant forcing:

dX_k/dt = (X_{k+1} - X_{k-2}) * X_{k-1} - X_k + F

When J > 0 a second, faster Y layer of n × J variables is coupled to the slow layer (the two-scale system of Lorenz & Emanuel 1998):

dX_k/dt = ... - (h*c/b) * sum_j Y_{j,k}
dY_{j,k}/dt = -c*b * Y_{j+1,k} * (Y_{j+2,k} - Y_{j-1,k}) - c*Y_{j,k} + (h*c/b)*X_k

Parameters

var_name : str = 'lorenz96'

Label for the model output. Default 'lorenz96'.

n : int = 40

Number of slow-scale variables. Default 40.

J : int = 0

Fast variables per slow variable. J=0 (default) gives the single-scale system; J>0 activates the two-scale system.

F : float or callable or cc.Forcing = 8.0

Slow-scale forcing amplitude. Default 8.0. Pass a time-varying signal via model.register_forcing('F', forcing_obj).

h : float = 1.0

Coupling coefficient between X and Y layers (two-scale only). Default 1.0.

b : float = 10.0

Amplitude ratio Y/X (two-scale only). Default 10.0.

c : float = 10.0

Timescale ratio Y/X (two-scale only). Default 10.0.

exact_rhs : bool = False

If True, use global np.roll on the flattened Y vector, matching the original L96_model.py reference implementation. Default False (per-block loop, identical results).

Notes

For the two-scale system (J>0) use method='rk4' with a small fixed time step passed directly to integrate::

output = model.integrate(t_span=..., y0=..., method='rk4',
                         dt=0.005, kwargs={'si': 0.05})

Adaptive solvers (RK45) call dydt at unpredictable sub-steps; the fixed-step RK4 avoids this problem. Plain Euler is too coarse to resolve the fast Y dynamics.

References

Lorenz, E. N. (1996). Predictability: A problem partly solved. Lorenz, E. N., & Emanuel, K. A. (1998). J. Atmos. Sci., 55, 399–414.

Examples

import matplotlib.pyplot as plt
import numpy as np
import climatecritters as cc
from climatecritters.model_critters.lorenz import Lorenz96

# Single-scale system
model = Lorenz96(n=40, F=8.0)
y0 = np.random.randn(40) + 8.0
output = model.integrate(t_span=(0, 10), y0=y0, method='rk4', dt=0.01)
ts = output.to_pyleo(var_names=['x0'])

# Two-scale system
K, J = 36, 10
model2 = Lorenz96(n=K, J=J, F=10.0)
y0_2 = np.concatenate([np.random.randn(K) + 10.0,
                        np.random.randn(K * J) * 0.01])
output2 = model2.integrate(t_span=(0, 10), y0=y0_2,
                           method='rk4', dt=0.005,
                           kwargs={'si': 0.05})
ts = output.to_pyleo(var_names=['x0'])
ts.plot()
plt.savefig('docs/reference/figures/Lorenz96_example.png',
            dpi=150, bbox_inches='tight')

Lorenz96 example output