Profiles of mean geostrophic velocities from CPIES (they compare well with LADCP measurementes). From Teri:
"The basic structure is the same for LADCP and GEM-derived currents. See figure 12 in Yvonne Firing's JAOT paper for specifics. http://dx.doi.org/10.1175/JTECH-D-13-00142.1 "
In [1]:
import numpy as np
from numpy import pi, cos, sin
import matplotlib.pyplot as plt
%matplotlib inline
import scipy as sp
import scipy.integrate
from my_modes import *
In [2]:
data = np.load('fields2stability.npz')
lat = -58
beta = 2*7.29e-5*cos(lat*pi/180.)/6371.e3
f0 = 2*7.29e-5*sin(lat*pi/180.)
i1 = 3
dec = 1
N2 = data['N2'][i1::dec]
U = data['U'][i1::dec]
V = data['V'][i1::dec]
z = data['z'][i1::dec]
zp = (z[1:]+z[:-1])/2.
v, w = pmodes(N2,z,lat,nm=100)
In [3]:
fig = plt.figure(figsize=(14,7))
ax1 = fig.add_subplot(121)
ax1.plot(v[...,0],z)
ax1.plot(-v[...,1],z)
ax1.plot(v[...,2],z)
ax1.plot(v[...,3],z)
ax1.set_ylim(3500,0)
ax1.set_xlim(-2,2)
ax1.set_xlabel('Standard modes')
ax1.set_ylabel('Depth [m]')
Out[3]:
In [4]:
def calc_QyQx(N2,z,U,V,lat):
""" Calculates QGPV gradients """
f0 = 2*7.29e-5*sin(lat*pi/180.)
beta = 2*7.29e-5*cos(lat*pi/180.)/6371.e3
S = f0**2 / N2
nz = S.size
dz = abs(z[1]-z[0])
dz2 = dz**2
# assemble strecthing matrix (standard staggered grid second order FD)
SM = np.zeros((nz-1,nz-1))
for i in range(nz-1):
if i == 0:
SM[0,0], SM[0,1] = -S[1]-2*S[0],S[1]
elif i==nz-2:
SM[-1,-2], SM[-1,-1] = S[-2], -S[-2]-2*S[-1]
else:
SM[i,i-1], SM[i,i], SM[i,i+1] = S[i], -(S[i+1]+S[i]), S[i+1]
SM = SM/dz2
# recall staggered stencil in the interior
Up = (U[:-1]+U[1:])/2.
Vp = (V[:-1]+V[1:])/2.
zp = (z[:-1]+z[1:])/2.
# calculate the base state PV gradients
LU = np.einsum('ij,j->i',SM,Up)
LV = np.einsum('ij,j->i',SM,Vp)
# this solves for the ghost point (involves U[0], but solves U[1/2]...)
LU[0] += 2*S[0]*U[0]/dz2
LU[-1] += 2*S[-1]*U[-1]/dz2
LV[0] += 2*S[0]*V[0]/dz2
LV[-1] += 2*S[-1]*V[-1]/dz2
Qx = LV
Qy = (beta-LU)
return Qx, Qy
In [5]:
Qx,Qy = calc_QyQx(N2,-z,U,V,lat=lat)
In [6]:
def calc_QyQx_modal(w,Un,Vn,v,N,beta):
LUg = -(np.einsum("i,ji->j",(w[:N+1]*Un),v[...,:N+1]))
LVg = -(np.einsum("i,ji->j",(w[:N+1]*Vn),v[...,:N+1]))
return LVg, (beta-LUg)
In [7]:
v2 = (v[1:]+v[:-1])/2.
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [8]:
Un,_, _ = project(v,U)
Vn,_, _ = project(v,V)
In [9]:
N = 1
Un1,Ug, errorUg = project(v[...,:N+1],U)
Vn1,Vg, errorVg = project(v[...,:N+1],V)
_,Qggx,_ = project(v2,Qx)
_,Qggy,_ = project(v2,Qy)
In [10]:
Qgx, Qgy = calc_QyQx_modal(w,Un1,Vn1,v,N,beta)
In [ ]:
In [11]:
fig = plt.figure(figsize=(14,7))
ax1 = fig.add_subplot(121)
ax1.plot(U,z,'b',label=r'$\mathsf{U}$: Zonal')
ax1.plot(V,z,'g',label=r'$\mathsf{V}$: Meridional')
ax1.plot(Ug,z,'b--',label=r'$\mathsf{U}_1 = \breve{U}_0 \mathsf{p}_0 + \breve{U}_1 \mathsf{p}_1$')
ax1.plot(Vg,z,'g--',label=r'$\mathsf{V}_1 = \breve{V}_0 \mathsf{p}_0 + \breve{V}_1 \mathsf{p}_1$')
ax1.set_ylim(3500,0)
ax1.set_xlabel('Velocity')
ax1.set_ylabel('Depth [m]')
ax1.legend(loc=4)
ax1 = fig.add_subplot(122)
ax1.plot(N2/np.abs(f0**2),z)
ax1.set_ylim(3500,0)
ax1.set_xlabel(r'$N^2/f_0^2$')
ax1.set_ylabel('Depth [m]')
ax1.legend(loc=4)
plt.tight_layout()
In [12]:
fig = plt.figure(figsize=(7,7))
ax1 = fig.add_subplot(111)
ax1.plot(Qy/beta,zp,'b',label=r'$Q_y = \beta - \mathsf{L}\mathsf{U}$')
ax1.plot(Qx/beta,zp,'g',label=r'$Q_x = \mathsf{L} \mathsf{V}$')
ax1.plot(Qgy.squeeze()/beta,z,'b--',label=r'$Qg_y = \beta - \mathsf{L}\mathsf{U_1}$')
ax1.plot(Qgx.squeeze()/beta,z,'g--',label=r'$Qg_x = \mathsf{L}\mathsf{V_1}$')
#ax1.plot(Qggy/beta,z,'b-+',label=r'$Qg_y = \beta - \mathsf{L}\mathsf{U_1}$')
#ax1.plot(Qggx/beta,z,'g-+',label=r'$Qg_y = \beta - \mathsf{L}\mathsf{U_1}$')
ax1.set_ylim(3500,0)
ax1.set_xlim(-250,250)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
ax1.legend(loc=4)
plt.grid()
In [13]:
Un2,Ug2, errorUg2 = project(v[...,:3],U)
Vn2,Vg2, errorVg2 = project(v[...,:3],V)
Qg2x,Qg2y = calc_QyQx(N2,-z,Ug2.squeeze(),Vg2.squeeze(),lat=lat)
Qg2x, Qg2y = calc_QyQx_modal(w,Un2,Vn2,v,2,beta)
_,Qgg2x,_ = project(v2[...,:2+1],Qx)
_,Qgg2y,_ = project(v2[...,:2+1],Qy)
Un3,Ug3, errorUg3 = project(v[...,:5],U)
Vn3,Vg3, errorVg3 = project(v[...,:5],V)
Qg3x, Qg3y = calc_QyQx_modal(w,Un3,Vn3,v,4,beta)
_,Qgg3x,_ = project(v2[...,:5],Qx)
_,Qgg3y,_ = project(v2[...,:5],Qy)
In [ ]:
In [14]:
Un7,Ug7, errorUg7 = project(v[...,:8],U)
Vn7,Vg7, errorVg7 = project(v[...,:8],V)
Qg7x, Qg7y = calc_QyQx_modal(w,Un7,Vn7,v,7,beta)
_,Qgg7x,_ = project(v2[...,:7+1],Qx)
_,Qgg7y,_ = project(v2[...,:7+1],Qy)
Un25,Ug25, errorUg25 = project(v[...,:26],U)
Vn25,Vg25, errorVg25 = project(v[...,:26],V)
Qg25x, Qg25y = calc_QyQx_modal(w,Un25,Vn25,v,25,beta)
_,Qgg25x,_ = project(v2[...,:26],Qx)
_,Qgg25y,_ = project(v2[...,:26],Qy)
Un100,Ug100, errorUg100 = project(v[...,:100],U)
Vn100,Vg100, errorVg100 = project(v[...,:100],V)
Qg100x, Qg100y = calc_QyQx_modal(w,Un100,Vn100,v,99,beta)
_,Qgg100x,_ = project(v2[...,:100],Qx)
_,Qgg100y,_ = project(v2[...,:100],Qy)
In [15]:
fig = plt.figure(figsize=(14,7))
ax1 = fig.add_subplot(121)
ax1.plot(Qy/beta,zp,label=r'Full')
ax1.plot(Qgy/beta,z,'--',label=r'$N=1$')
ax1.plot(Qg2y/beta,z,'--',label=r'$N=2$')
#ax1.plot(Qgg2y/beta,z,'-+',label=r'$N=2$')
ax1.plot(Qg3y/beta,z,'m--',label=r'$N=3$')
#ax1.plot(Qgg3y/beta,z,'m-+',label=r'$N=3$')
ax1.plot(Qg7y/beta,z,'k--',label=r'$N=7$')
#ax1.plot(Qgg7y/beta,z,'k-+',label=r'$N=7$')
#ax1.plot(Qg25y/beta,z,'y--',label=r'$N=25$')
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
ax1.legend(loc=4,)
plt.grid()
ax1 = fig.add_subplot(122)
ax1.plot(U,z,'-',label='Full')
ax1.plot(Ug,z,'--',label=r'$N=1$')
ax1.plot(Ug2,z,'--',label=r'$N=1$')
ax1.plot(Ug3,z,'m--',label=r'$N=3$')
ax1.plot(Ug7,z,'k--',label=r'$N=7$')
#ax1.plot(Ug25,z,'y--',label=r'$N=25$')
ax1.set_ylim(3500,0)
ax1.set_xlim(.1,.4)
ax1.set_xlabel(r'U [m s$^{-1}$]')
ax1.set_ylabel('Depth [m]')
plt.grid()
In [16]:
np.array([errorUg,errorUg2,errorUg3])/U.std()
Out[16]:
The results are indistinguishable with N=1 and N=2, but wildly different with N>=3. Below, the solid lines represent the Qy obtained by term-by-term differentiating the series U and the dashed lines represent Qy calculated by projecting the finite-difference approximation of (beta - LU) onto N baroclinic modes. Blue solid line is Qy calculated by finite-difference approx. of (beta-LU).
In [17]:
fig = plt.figure(figsize=(14,7))
ax1 = fig.add_subplot(231)
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.plot(Qgy/beta,z,'k-',label=r'$N=1$')
ax1.plot(Qggy/beta,zp,'k--')
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=1')
ax1 = fig.add_subplot(232)
ax1.plot(Qg2y/beta,z,'k-',label=r'$N=2$')
ax1.plot(Qgg2y/beta,zp,'k--')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=2')
ax1 = fig.add_subplot(233)
ax1.plot(Qg3y/beta,z,'k-',label=r'$N=3$')
ax1.plot(Qgg3y/beta,zp,'k--')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=3')
ax1 = fig.add_subplot(234)
ax1.plot(Qg7y/beta,z,'k-',label=r'$N=7$')
ax1.plot(Qgg7y/beta,zp,'k--')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=7')
ax1 = fig.add_subplot(235)
ax1.plot(Qg25y/beta,z,'k-',label=r'$N=25$')
ax1.plot(Qgg25y/beta,zp,'k--')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=25')
ax1 = fig.add_subplot(236)
ax1.plot(Qg100y/beta,z,'k-',label=r'$N=25$')
ax1.plot(Qgg100y/beta,zp,'k--')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=100')
plt.tight_layout()
The strong shear near the "bottom" precudes an accurate estimation of the PV gradients based differention of the Galerkin series for U and V. To overcome this difficulty, we decompose the velocity field
$$ U = U_s(z) + U_i(z)$$$$ V = V_s(z) + V_i(z)$$where $U_i$ and $V_i$ is a satisfiy homogeneous Neumann boundary conditions, and $U_s$ and $V_s$ contains the satisfy inhomogeneous boundary conditions: $U_s'(0)=U'(0)$, etc.
In [18]:
def decomp_vel(z,N2,U,f2 = 1.e-2):
h = z[-1]-z[0]
h2 = h**2
dz = z[1]-z[0]
Up0 = (U[0]-U[1])/dz
Uph = (U[-2]-U[-1])/dz
zs = -z+z[0]
I1,I2 = np.empty_like(z), np.empty_like(z)
Us = np.empty_like(z)
N2s = N2
for i in range(I1.size):
I1[i] = sp.integrate.simps(N2s[:i+1]*(zs[:i+1]+h),zs[:i+1])
I2[i] = sp.integrate.simps(N2s[:i+1]*zs[:i+1],zs[:i+1])
A = -sp.integrate.simps(-I1*Up0/N2s[0]/h2 + I2*Uph/N2s[-1]/h2,zs)
Us = I1*Up0/N2s[0]/h -I2*Uph/N2s[-1]/h + A
Up = U - Us
LUs = (f2/N2s[0])*Up0/h - (f2/N2s[-1])*Uph/h
return Us,Up, LUs
Us, Up, LUs = decomp_vel(z,N2,U,f2=f0**2)
Vs, Vp, LVs = decomp_vel(z,N2,V,f2=f0**2)
In [24]:
#plt.plot(Vs,z)
#plt.plot(V,z)
#plt.plot(Vp,z)
plt.plot(Us,z,'b--',label=r'$U_s$')
plt.plot(U,z,'g--',label=r'$U$')
plt.plot(Up,z,'r--',label=r'$U_i$')
plt.ylim(3500,0)
plt.xlim(-.15,.45)
plt.legend()
Out[24]:
In [78]:
Un,Ug, errorUg = project(v[...,:2],Up)
Vn,Vg, errorVg = project(v[...,:2],Vp)
Qgx, Qgy = calc_QyQx_modal(w,Un,Vn,v,1,beta)
Qgx += LVs
Qgy -= LUs
Un2,Ug2, errorUg2 = project(v[...,:3],Up)
Vn2,Vg2, errorVg2 = project(v[...,:3],Vp)
Qg2x, Qg2y = calc_QyQx_modal(w,Un2,Vn2,v,2,beta)
Qg2x += LVs
Qg2y -= LUs
Un3,Ug3, errorUg4 = project(v[...,:5],Up)
Vn3,Vg3, errorVg4 = project(v[...,:5],Vp)
Qg3x, Qg3y = calc_QyQx_modal(w,Un3,Vn3,v,4,beta)
Qg3x += LVs
Qg3y -= LUs
Un5,Ug5, errorUg5 = project(v[...,:6],Up)
Vn5,Vg5, errorVg5 = project(v[...,:6],Vp)
Qg5x, Qg5y = calc_QyQx_modal(w,Un5,Vn5,v,5,beta)
Qg5x += LVs
Qg5y -= LUs
Un6,Ug6, errorUg6 = project(v[...,:7],Up)
Vn6,Vg6, errorVg6 = project(v[...,:7],Vp)
Qg6x, Qg6y = calc_QyQx_modal(w,Un6,Vn6,v,6,beta)
Qg6x += LVs
Qg6y -= LUs
Un7,Ug7, errorUg7 = project(v[...,:8],Up)
Vn7,Vg7, errorVg7 = project(v[...,:8],Vp)
Qg7x, Qg7y = calc_QyQx_modal(w,Un7,Vn7,v,7,beta)
Qg7x += LVs
Qg7y -= LUs
Un25,Ug25, errorUg25 = project(v[...,:26],Up)
Vn25,Vg25, errorVg25 = project(v[...,:26],Vp)
Qg25x, Qg25y = calc_QyQx_modal(w,Un25,Vn25,v,25,beta)
Qg25x += LVs
Qg25y -= LUs
Un100,Ug100, errorUg100 = project(v[...,:101],Up)
Vn100,Vg100, errorVg100 = project(v[...,:101],Vp)
Qg100x, Qg100y = calc_QyQx_modal(w,Un100,Vn100,v,100,beta)
Qg100x += LVs
Qg100y -= LUs
In [79]:
Qgy.shape, zp.size
Out[79]:
In [80]:
fig = plt.figure(figsize=(14,7))
ax1 = fig.add_subplot(231)
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.plot(Qgy/beta,z,'k-',label=r'$N=1$')
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=1')
ax1 = fig.add_subplot(232)
ax1.plot(Qg2y/beta,z,'k-',label=r'$N=2$')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=2')
ax1 = fig.add_subplot(233)
ax1.plot(Qg3y/beta,z,'k-',label=r'$N=4$')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=4')
ax1 = fig.add_subplot(234)
ax1.plot(Qg7y/beta,z,'k-',label=r'$N=7$')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=7')
ax1 = fig.add_subplot(235)
ax1.plot(Qg25y/beta,z,'k-',label=r'$N=25$')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=25')
ax1 = fig.add_subplot(236)
ax1.plot(Qg100y/beta,z,'k-',label=r'$N=100$')
ax1.plot(Qy/beta,zp,'b',linewidth=1.)
ax1.set_ylim(3500,0)
ax1.set_xlim(-100,100)
ax1.set_xlabel(r'QGPV gradient normalized by $\beta$ [unitless]')
ax1.set_ylabel('Depth [m]')
plt.grid()
plt.title('N=100')
plt.tight_layout()
In [81]:
U1 = Ug + Us
U2 = Ug2 + Us
U3 = Ug3 + Us
U5 = Ug5 + Us
U6 = Ug6 + Us
U7 = Ug7 + Us
U25 = Ug25 + Us
U100 = Ug100 + Us
In [82]:
def rel_error(A,B):
return (A-B).std()/A.std()
In [85]:
e1 = rel_error(U,U1)
e2 = rel_error(U,U2)
e3 = rel_error(U,U3)
e5 = rel_error(U,U5)
e6 = rel_error(U,U6)
e7 = rel_error(U,U7)
e6
Out[85]:
In [84]:
fig = plt.figure(figsize=(12,7))
ax1 = fig.add_subplot(122)
ax1.plot(U,z,'-',label='Full')
ax1.plot(Ug+Us,z,'--',label=r'$N=1$')
ax1.plot(Ug2+Us,z,'--',label=r'$N=1$')
ax1.plot(Ug3+Us,z,'m--',label=r'$N=3$')
ax1.plot(Ug7+Us,z,'k--',label=r'$N=7$')
#ax1.plot(Ug25,z,'y--',label=r'$N=25$')
plt.legend(loc=4)
ax1.set_ylim(3500,0)
ax1.set_xlim(.1,.4)
ax1.set_xlabel(r'U [m s$^{-1}$]')
ax1.set_ylabel('Depth [m]')
plt.grid()
In [86]:
plt.plot(Qg2y/beta,z,'g')
plt.plot(Qg6y/beta,z,'m')
plt.grid()
plt.ylim(3500,0)
Out[86]:
In [27]:
beta
Out[27]:
In [ ]: