-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathL96.py
60 lines (55 loc) · 2.47 KB
/
L96.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
"""Lorenz 1996 model (with zonally varying damping)
Lorenz E., 1996. Predictability: a problem partly solved. In
Predictability. Proc 1995. ECMWF Seminar, 1-18."""
import numpy as np
class L96:
def __init__(self,members=1,n=40,dt=0.05,diff_max=1.0,diff_min=1.0,F=8,deltaF=0,Fcorr=1.,rs=None):
self.n = n; self.dt = dt
self.diff_max = diff_max; self.diff_min = diff_min
self.F = F; self.members = members
self.deltaF = deltaF; self.Fcorr = Fcorr
if rs is None:
rs = np.random.RandomState()
self.rs = rs
self.x = F+0.1*self.rs.standard_normal(size=(members,n))
self.blend = np.cos(np.linspace(0,np.pi,n))**4
self.xwrap = np.zeros((self.members,self.n+3), np.float)
if self.deltaF == 0:
self.forcing = self.F
else:
self.forcing = self.rs.gamma(self.F/self.deltaF, self.deltaF, size=(self.members,self.n))
def shiftx(self):
xwrap = self.xwrap
xwrap[:,2:self.n+2] = self.x; xwrap[:,1]=self.x[:,-1]
xwrap[:,0]=self.x[:,-2]; xwrap[:,-1]=self.x[:,0]
xm2=xwrap[:,0:self.n]; xm1=xwrap[:,1:self.n+1]; xp1=xwrap[:,3:self.n+3]
return xm2,xm1,xp1
def dxdt(self):
xm2,xm1,xp1 = self.shiftx()
return (xp1-xm2)*xm1 - \
(self.diff_min+(self.diff_max-self.diff_min)*self.blend)*self.x + self.forcing
def advance(self):
# gamma distributed forcing with mean = self.F. Approaches constant
# value self.F as deltaF approaches zero, more variability as deltaF
# increases. Forcing is random at every grid point, but correlated
# in time with lag-1 correlation of self.Fcorr. Forcing
# is assumed constant over one time step (does not vary inside RK4).
# standard deviation is sqrt(F*deltaF)
if self.deltaF == 0:
self.forcing = self.F
else:
# adjust deltaF to preserve expected variance.
deltaF = self.deltaF/(1.-np.sqrt(self.Fcorr))
forcing = self.Fcorr*self.forcing + (1.-self.Fcorr)*self.rs.gamma(self.F/deltaF, deltaF, size=(self.members,self.n))
self.forcing = forcing
h = self.dt; hh = 0.5*h; h6 = h/6.
x = self.x
dxdt1 = self.dxdt()
self.x = x + hh*dxdt1
dxdt2 = self.dxdt()
self.x = x + hh*dxdt2
dxdt = self.dxdt()
self.x = x + h*dxdt
dxdt2 = 2.0*(dxdt2 + dxdt)
dxdt = self.dxdt()
self.x = x + h6*(dxdt1 + dxdt + dxdt2)