Example #1
0
def backrotate_phase(data):
    import gsw
    data['ang'] = np.arctan2(data.v_resid, data.u_resid)

    ref_time = pd.to_datetime('1/1/2016')
    timestamp = pd.to_datetime(data.time.values)

    Tf = 2 * np.pi / gsw.f(40)
    dt = (timestamp - ref_time) / pd.to_timedelta(1, unit='s') % Tf

    phase_add = (dt.values * gsw.f(40)).astype('float')
    phase_add[phase_add > np.pi] = phase_add[phase_add > np.pi] - 2 * np.pi

    data['ang_br'] = data['ang'] + phase_add
    data['ang_br'] = xr.where(
        data.ang_br > np.pi,
        (data['ang_br'].where(data.ang_br > np.pi) - np.pi), data['ang_br'])
    data['ang_br'] = xr.where(
        data.ang_br < -np.pi,
        2 * np.pi + (data['ang_br'].where(data.ang_br > np.pi)),
        data['ang_br'])

    data['ang'] = np.degrees(data['ang'])
    data['ang_br'] = np.degrees(data['ang_br'])
    return data
Example #2
0
def backrotate_phase(ang):
    ref_time = pd.to_datetime('28/12/1988')
    timestamp = pd.to_datetime(ang.time.values)
    Tf =2 * np.pi / gsw.f(40.7)
    dt = (timestamp - ref_time) / pd.to_timedelta(1, unit='s') % Tf
    phase_add = (dt.values * gsw.f(40.7)).astype('float')
    ang_br = ang + phase_add*180/np.pi

    return wrap(ang_br)
Example #3
0
def bandpass_filter_variables(data, resample_period, order):
    '''
    apply bandpass filter to multiple variables
    '''
    sampling_period = np.int(resample_period.split('h')[0])
    fs = 1 / (3600 * sampling_period)  # sample rate, Hz
    f = gsw.f(40)  # inertial frequency
    highcut = 1.2 * f
    lowcut = 0.8 * f

    # loop over depths
    bucket = []
    for z in range(len(data.z)):
        dat = data.isel(z=z).dropna(dim='time')
        # temp = dat[var].fillna(0)
        if dat.count() > 27:
            filtered = butter_bandpass_filter(dat, lowcut, highcut, fs, order)
            bucket.append(
                xr.DataArray(filtered, coords=[dat.time], dims=['time']))
        else:
            bucket.append(
                xr.DataArray(np.ones(dat.time.size) * np.nan,
                             coords=[dat.time],
                             dims=['time']))
    ds = xr.concat(bucket, data.z)
    return ds
Example #4
0
def latitude_correction(f, N):
    r"""
    Latitudinal correction term

    Parameters
    ----------
    f : float
        Coriolis parameter
    N : float
        Buoyancy frequency

    Returns
    -------
    L : float
        Latitudinal correction

    Notes
    -----
    Calculates the latitudinal dependence term as described in Gregg et al.
    (2003) :cite:`Gregg2003`:

    .. math::

        L(\theta, N) = \frac{f \cosh^{-1}(N/f)}{f_{30^{\circ}} \cosh^{-1}(N_0/f_{30^\circ})}

    with Coriolis parameter at 30° latitude :math:`f_{30^\circ}` and reference
    GM buoyancy frequency :math:`N_0=5.24\times10^{-3}\,\mathrm{s}^{-1}`.
    """
    # Coriolis parameter at 30 degrees latitude
    f30 = gsw.f(30)  # rad s-1
    # GM model reference stratification:
    N0 = 5.24e-3  # rad s-1
    f = np.abs(f)
    return f * np.arccosh(N / f) / (f30 * np.arccosh(N0 / f30))
Example #5
0
def compute_iso_disp(raw):
    f = gsw.f(40.7)/(2*np.pi)
    raw = lowpass_variable(raw,'rho0', 0.6*f, 1.25*f)
    raw['rho_ref'] = raw.rho0LOW

    raw['sigma'] = raw.rho0 -1000
    raw['sigma_ref'] = raw.rho_ref -1000

    raw['sigma'] = xr.where(raw['sigma']<20, np.nan, raw['sigma'])
    raw['sigma_ref'] = xr.where(raw['sigma_ref']<20, np.nan, raw['sigma_ref'])
    new_min = raw.sigma.min()
    new_max = raw.sigma.max()
    #return raw

    sigma_coords = get_new_coodinates(raw,'sigma', new_min, new_max)
    sigma_ref_coords = get_new_coodinates(raw,'sigma_ref', new_min, new_max)

    ds_z = remap_variable(raw,'sigma',sigma_coords).rename({'remapped':'sigma'})
    ds_z_ref = remap_variable(raw,'sigma_ref',sigma_ref_coords).rename({'remapped':'sigma'})
    eta_sigma = (ds_z_ref-ds_z).transpose() # this is in sigma space

    z_values = xr.DataArray(raw.z.values, coords=[('z', raw.z.values)]) # define the new z grid
    z_coord = linear_interpolation_regrid(ds_z.sigma, ds_z.transpose(), z_values, target_value_dim='z')
    eta = linear_interpolation_remap(eta_sigma.sigma, eta_sigma, z_coord).transpose()
    raw['eta'] = eta.rename({'remapped':'z'}) #.transpose()

    if raw.z.max()>0:
        raw.coords['z'] = -raw.z
    return raw
Example #6
0
def lowpass_filter_variables(data, resample_period, filter_period, order):
    '''
    apply lowpass filter to multiple variables
    '''

    sampling_period = np.int(resample_period.split('h')[0])
    fs = 1 / (3600 * sampling_period)  # sample rate, Hz
    f = gsw.f(40)  # inertial frequency
    Tf = 2 * np.pi / f  # inertial period
    # desired cutoff frequency of the filter, Hz
    cutoff = 1 / (Tf * filter_period)
    # loop over depths
    bucket = []
    for z in range(len(data.z)):
        dat = data.isel(z=z).dropna(dim='time')
        # temp = dat[var].fillna(0)
        if dat.count() > 21:
            filtered = butter_lowpass_filter(dat, cutoff, fs, order)
            bucket.append(
                xr.DataArray(filtered, coords=[dat.time], dims=['time']))
        else:
            bucket.append(
                xr.DataArray(np.ones(dat.time.size) * np.nan,
                             coords=[dat.time],
                             dims=['time']))
    ds = xr.concat(bucket, data.z)
    return ds
Example #7
0
def least_square_method(x0, y0, u0, v0, method):
    '''
    Least square method to estimate velocity gradients
    '''
    import numpy as np
    import scipy.linalg as la
    import gsw
    ncc = x0.size
    dlon = (x0 - np.nanmean(x0)) * 1000
    dlat = (y0 - np.nanmean(y0)) * 1000
    f = gsw.f(17)

    R = np.mat(np.vstack((np.ones((ncc, )), dlon, dlat)).T)
    u0 = np.mat(u0).T - np.nanmean(u0)
    v0 = np.mat(v0).T - np.nanmean(v0)

    if method is 'lstsq':
        A, _, _, _ = la.lstsq(R, u0)
        B, _, _, _ = la.lstsq(R, v0)
    elif method is 'inv':
        A = np.linalg.inv(R.T * R) * R.T * u0
        B = np.linalg.inv(R.T * R) * R.T * v0
    elif method is 'solve':
        A = np.linalg.solve(R, u0)
        B = np.linalg.solve(R, v0)

    vort = (B[1] - A[2]) / f
    strain = np.sqrt((A[1] - B[2])**2 + (B[1] + A[2])**2) / f
    div = (A[1] + B[2]) / f

    return vort, strain, div
Example #8
0
def backrotate_rc(phase0):
    f= gsw.f(40.7)
    ref_time = pd.to_datetime('28/12/1988')
    timestamp = pd.to_datetime(phase0.time.values)
    dt = (timestamp - ref_time) / pd.to_timedelta(1, unit='s')
    backrotate = np.arctan2(np.sin(f*dt.values),np.cos(f*dt.values))*180/np.pi

    return wrap(phase0 + backrotate)
Example #9
0
File: phase.py Project: sessink/NIW
    def backrotate(data, var):
        newvar = var + '_br'
        ref_time = pd.to_datetime('1/1/2016')
        timestamp = pd.to_datetime(data.time.values)
        Tf = 2 * np.pi / gsw.f(40)
        dt = (timestamp - ref_time) / pd.to_timedelta(1, unit='s') % Tf

        phase_add = (dt.values * gsw.f(40)).astype('float')
        phase_add[phase_add > np.pi] = phase_add[phase_add > np.pi] - 2 * np.pi

        data[newvar] = data[var] + phase_add
        data[newvar] = xr.where(
            data[newvar] > np.pi,
            (data[newvar].where(data[newvar] > np.pi) - np.pi), data[newvar])
        data[newvar] = xr.where(
            data[newvar] < -np.pi,
            2 * np.pi + (data[newvar].where(data[newvar] > np.pi)),
            data[newvar])
        return data
Example #10
0
def jAndDerivatives(N, f, Q, dQdz):
    g = 9.81
    f = f
    Q = Q
    f0 = gsw.f(30)
    N0 = 5.2 * (10**-3)
    C0 = np.arccosh(N0 / f0)
    j = (f / (f0 * C0)) * np.arccosh(N / f)
    djdz = (f / (f0 * C0)) * ((((g * Q) / (f**3)) - 1)**(-1 / 2))
    d2jdz2 = -(g / (2 * f0 * C0 * (f**2))) * dQdz * ((((g * Q) /
                                                       (f**3)) - 1)**(-3 / 2))
    return j, djdz, d2jdz2
 def Burger(self, data, H, L):
     '''
     Bu = NH/fL   in which
            N is the buoyancy frequency,
            f is the Coriolis parameter
            H characteristic vertical length scale
            L characteristic horizontal length scale
     '''
     sal, CT, pres, lat = data
     N2 = gsw.Nsquared(sal, CT, pres, lat=lat)
     f = gsw.f(lat)
     Bu = (np.sqrt(N2) * H) / (f * L)
     return Bu
def u_model(params, pfl, zlim, deg):

    phi_0, X, Z, phase_0 = params
    zmin, zmax = zlim
    nope = np.isnan(pfl.zef) | (pfl.zef < zmin) | (pfl.zef > zmax)

    t = 60*60*24*(pfl.UTCef - np.nanmin(pfl.UTCef))
    x = 1000.*(pfl.dist_ef - np.nanmin(pfl.dist_ef))
    k = 2*np.pi/X
    l = 0.
    m = 2*np.pi/Z
    f = gsw.f(pfl.lat_start)
    N = np.mean(np.sqrt(pfl.N2_ref[~nope]))

    om = gw.omega(N, k, m, l, f)

    u = gw.u(x, 0., pfl.zef, t, phi_0, k, l, m, om, phase_0=phase_0)

    return u[~nope] - utils.nan_detrend(pfl.zef[~nope], pfl.U[~nope], deg)
def w_model(params, pfl, zlim, deg):

    phi_0, X, Z, phase_0 = params
    zmin, zmax = zlim
    nope = np.isnan(pfl.z) | (pfl.z < zmin) | (pfl.z > zmax)

    t = 60*60*24*(pfl.UTC - np.nanmin(pfl.UTC))
    x = 1000.*(pfl.dist_ctd - np.nanmin(pfl.dist_ctd))

    k = 2*np.pi/X
    l = 0.
    m = 2*np.pi/Z
    f = gsw.f(pfl.lat_start)
    N = np.mean(np.sqrt(pfl.N2_ref[~nope]))
    om = gw.omega(N, k, m, l, f)

    w = gw.w(x, 0., pfl.z, t, phi_0, k, l, m, om, N, phase_0=phase_0)

    return w[~nope] - pfl.Ww[~nope]
Example #14
0
def momentumFluxes(kh, m, N2,ladcp, z_ctd, bin_size=512, h0=1000):
    """
    Calculating vertical and horizontal momentum fluxes of internal waves within
    safe range
    """

    dshift = doppler_shifts(kh, ladcp)

    # Test whether K*U is between N and f
    f = (np.nanmean(gsw.f(lat)))

    dshiftTest = np.full_like(kh, np.nan)

    for i, dump in enumerate(kh.T):
        N2mean = np.nanmean(N2[:,i])
        dshiftTest[:,i] = np.logical_and(dshift[:,i]**2 >= f**2, dshift[:,i]**2<= N2mean)

    dshiftTest2 = dshiftTest == 0
    kh[dshiftTest2] = np.nan

    maxDepth = 4000
    idx_ladcp = z[:,-1] <= maxDepth
    idx_ctd = z_ctd[:,-1] <= maxDepth
    z = z[idx_ladcp,:]
    U = U[idx_ladcp,:]
    V = V[idx_ladcp,:]
    rho = rho_neutral[idx_ctd,:]
    bins = oc.binData(U, z[:,0], bin_size)
    Umean = np.vstack([np.nanmean(U[binIn,:], axis=0) for binIn in bins])
    Vmean = np.vstack([np.nanmean(V[binIn,:], axis=0) for binIn in bins])
    Umag = np.sqrt(Umean**2 + Vmean**2)

    bins = oc.binData(rho, z_ctd[:,0], bin_size)
    rho0 = np.vstack([np.nanmean(rho[binIn,:], axis=0) for binIn in bins])



    tau = .5*kh*rho0*Umag*np.sqrt((N2/Umag**2)-kh**2)

    np.savetxt('wave_momentum.csv', tau)
Example #15
0
def calcFQ(surfaces, k, found, scales, kpvs, distances, debug=False):
    dqdx = fetchWithFallback(surfaces, k, "dqdx", found)
    dqdy = fetchWithFallback(surfaces, k, "dqdy", found)
    dqdz = fetchWithFallback(surfaces, k, "dqdz", found)
    d2qdz2 = fetchWithFallback(surfaces, k, "d2qdz2", found)
    d2qdx2 = fetchWithFallback(surfaces, k, "d2qdx2", found)
    d2qdy2 = fetchWithFallback(surfaces, k, "d2qdy2", found)
    dqnotdx = fetchWithFallback(surfaces, k, "dqnotdx", found)
    dqnotdy = fetchWithFallback(surfaces, k, "dqnotdy", found)
    ddiffkrdz = fetchWithFallback(surfaces, k, "ddiffkrdz", found)
    d2diffkrdz2 = fetchWithFallback(surfaces, k, "d2diffkrdz2", found)
    khpdz = fetchWithFallback(surfaces, k, "khpdz", found)
    f = gsw.f(surfaces[k]["lats"][found])
    pv = fetchWithFallback(surfaces, k, "pv", found)

    missingpiece = -(2 * (dqnotdx * dqdx + dqnotdy * dqdy) / pv) * scales["kh"]
    if debug:
        print("#" * 5)
        print("diffkr: ", surfaces[k]["data"]["diffkr"][found])
        print("q: ", pv)
        print("Qkvterm part 1: ",
              surfaces[k]["data"]["diffkr"][found] * d2qdz2)
        print("Qkvterm part 2: ", 2 * ddiffkrdz * dqdz)
        print("Qkvterm part 3: ", d2diffkrdz2 * pv)
        print("Qkhterm part 1 : ", f * khpdz)
        print("Qkhterm part 2 : ",
              surfaces[k]["data"]["kapgm"][found] * (missingpiece))
        print("kapgm: ", surfaces[k]["data"]["kapgm"][found])
        print("kapredi: ", surfaces[k]["data"]["kapredi"][found])
    FQ = surfaces[k]["data"]["diffkr"][found]*d2qdz2 +\
            2*ddiffkrdz*dqdz+ d2diffkrdz2*pv +  \
            f*khpdz+\
            surfaces[k]["data"]["kapgm"][found]*(missingpiece) +\
            surfaces[k]["data"]["kapredi"][found]*(d2qdx2+d2qdy2)

    if np.isnan(FQ):
        FQ = 0
    surfaces[k]["data"]["FQ"][found] = FQ
    return FQ
Example #16
0
# interpolate flow velocities from u,v measurements
ui = griddata((x[mask], y[mask]),
              dict['u'][plev_adcp, 120:-120][mask], (xxi, yyi),
              method='linear')
vi = griddata((x[mask], y[mask]),
              dict['v'][plev_adcp, 120:-120][mask], (xxi, yyi),
              method='linear')

# relative vorticity
dvdx = np.gradient(vi)[1] / np.gradient(xxi)[1]
dudy = np.gradient(ui)[0] / np.gradient(yyi)[0]
zeta = dvdx - dudy

# planetary/ absolute vorticity
fcor = f(lti)
eta = fcor + zeta

# continuity/ horizontally divergence free
dudx = np.gradient(ui)[0] / np.gradient(xxi)[1]
dvdy = np.gradient(vi)[1] / np.gradient(yyi)[0]
divH = dudx + dvdy

### PLOT


def subp_figure(x,
                y,
                zz,
                x2=None,
                y2=None,
Example #17
0
def nepbCTDExtractInterpSurfaces(fname,calcDeriv = False):
    ctddata = sio.loadmat(fname)
    ##note: any x,y gradients wont be equivalent because of grid,
    ##			advisable to look at total gradient probably
    quantmap = {"CT_s":"t","S_s":"s","dQdz_s":"dqdz","dSdz_s":"dsdz",\
    "d2CTdS2_s":"d2thetads2","alpha_s":"alpha","beta_s":"beta",\
    "P_s":"pres","Q_s":"pv","d2Qdx2_s":"d2qdx2","d2Qdy2_s":"d2qdy2",\
    "d2Qdz2_s":"d2qdz2","d2Sdx2_s":"d2sdx2","d2Sdy2_s":"d2sdy2",\
    "aT":"dalphadtheta","aP":"dalphadp","A_s":"psi",\
    "lat_field":"khp","dCTdS_s":"dthetads","Sx":"dsdx",\
    "Sy":"dsdy","CTx":"dtdx","CTy":"dtdy","dCTdz_s":"dtdz",\
    "Qx":"dqdx","Qy":"dqdy","Hvar":"bathvar",\
    "Q0x":"dqnotdx","Q0y":"dqnotdy"}

    latlist = range(20,60,2)
    lonlist = list(range(170,180,2))
    lonlist = lonlist+list(range(-180,-120,2))

    ns = np.asarray(ctddata["P_gref"])

    surfaces = {}

    for field in ctddata.keys():
        if field in list(quantmap.keys())+["F_Ssmooth",\
                "F_CTsmooth","F_Qsmooth","F_N2smooth"]:
            if ctddata[field].shape == (20, 35, 30):
                ctddata[field] = np.transpose(ctddata[field],(2,0,1))
            if ctddata[field].shape == (41, 71, 30):
                ctddata[field] = np.transpose(ctddata[field],(2,0,1))

    for k in Bar("surface").iter(range(len(ns))):
        tempSurf = nstools.emptySurface()
        for j in quantmap.values():
            tempSurf["data"][j]=[]
        tempSurf["data"]["dsdx"]=[]
        tempSurf["data"]["dsdy"]=[]
        tempSurf["data"]["dtdx"]=[]
        tempSurf["data"]["dtdy"]=[]
        tempSurf["data"]["dqdx"]=[]
        tempSurf["data"]["dqdy"]=[]
        tempSurf["data"]["dqnotdx"]=[]
        tempSurf["data"]["dqnotdy"]=[]
        tempSurf["data"]["bathvar"]=[]

        for j in range(len(latlist)):
            for l in range(len(lonlist)):
                tempSurf["lats"].append(latlist[j])
                tempSurf["lons"].append(lonlist[l])
                tempSurf["ids"].append(j*30+l)
                for field in ctddata.keys():
                    if field in quantmap.keys():
                        if field == "Hvar":
                            tempSurf["data"]["bathvar"].append(ctddata[field][j*2][l*2])
                        else:
                            if calcDeriv and (field not in ["CTx","CTy",\
                                    "Sx","Sy","Qx","Qy","Q0x","Q0y"]):
                                tempSurf["data"][quantmap[field]].append(ctddata[field][k][j][l])
                            elif not calcDeriv:
                                tempSurf["data"][quantmap[field]].append(ctddata[field][k][j][l])

                    if calcDeriv and field == "F_Ssmooth":

                        if j == len(latlist)-1 or l == len(lonlist)-1: 
                            ydist = ((latlist[j] - latlist[j-1])/2.0)*111.0*1000.0
                            xdist = ydist *np.cos(np.deg2rad(latlist[j]+1))
                        else: 
                            ydist = ((latlist[j+1] - latlist[j])/2.0)*111.0*1000.0
                            xdist =ydist * np.cos(np.deg2rad(latlist[j]+1))

                        dx = ctddata[field][k][j*2][l*2+1] -  ctddata[field][k][j*2][l*2]
                        dx += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2+1][l*2]
                        dy = ctddata[field][k][j*2+1][l*2] -  ctddata[field][k][j*2][l*2]
                        dy += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2][l*2+1]

                        tempSurf["data"]["dsdx"].append(dx/(2*xdist))
                        tempSurf["data"]["dsdy"].append(dy/(2*ydist))


                    if calcDeriv and field == "F_CTsmooth":

                        if j == len(latlist)-1 or l == len(lonlist)-1: 
                            ydist = ((latlist[j] - latlist[j-1])/2.0)*111.0*1000.0
                            xdist = ydist *np.cos(np.deg2rad(latlist[j]+1))
                        else: 
                            ydist = ((latlist[j+1] - latlist[j])/2.0)*111.0*1000.0
                            xdist =ydist * np.cos(np.deg2rad(latlist[j]+1))

                        dx = ctddata[field][k][j*2][l*2+1] -  ctddata[field][k][j*2][l*2]
                        dx += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2+1][l*2]
                        dy = ctddata[field][k][j*2+1][l*2] -  ctddata[field][k][j*2][l*2]
                        dy += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2][l*2+1]

                        tempSurf["data"]["dtdx"].append(dx/(2*xdist))
                        tempSurf["data"]["dtdy"].append(dy/(2*ydist))

                    if calcDeriv and field == "F_Qsmooth":

                        if j == len(latlist)-1 or l == len(lonlist)-1: 
                            ydist = ((latlist[j] - latlist[j-1])/2.0)*111.0*1000.0
                            xdist = ydist *np.cos(np.deg2rad(latlist[j]+1))
                        else: 
                            ydist = ((latlist[j+1] - latlist[j])/2.0)*111.0*1000.0
                            xdist =ydist * np.cos(np.deg2rad(latlist[j]+1))

                        dx = ctddata[field][k][j*2][l*2+1] -  ctddata[field][k][j*2][l*2]
                        dx += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2+1][l*2]
                        dy = ctddata[field][k][j*2+1][l*2] -  ctddata[field][k][j*2][l*2]
                        dy += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2][l*2+1]

                        tempSurf["data"]["dqdx"].append(dx/(2*xdist))
                        tempSurf["data"]["dqdy"].append(dy/(2*ydist))

                    if calcDeriv and field == "F_N2smooth":

                        if j == len(latlist)-1 or l == len(lonlist)-1: 
                            ydist = ((latlist[j] - latlist[j-1])/2.0)*111.0*1000.0
                            xdist = ydist *np.cos(np.deg2rad(latlist[j]+1))
                        else: 
                            ydist = ((latlist[j+1] - latlist[j])/2.0)*111.0*1000.0
                            xdist =ydist * np.cos(np.deg2rad(latlist[j]+1))

                        dx = ctddata[field][k][j*2][l*2+1] -  ctddata[field][k][j*2][l*2]
                        dx += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2+1][l*2]
                        dy = ctddata[field][k][j*2+1][l*2] -  ctddata[field][k][j*2][l*2]
                        dy += ctddata[field][k][j*2+1][l*2+1] -  ctddata[field][k][j*2][l*2+1]

                        tempSurf["data"]["dqnotdx"].append(gsw.f(latlist[j])*dx/(9.81*2*xdist))
                        tempSurf["data"]["dqnotdy"].append(gsw.f(latlist[j])*dy/(9.81*2*ydist))


        surfaces[ns[k][0]] = tempSurf

    return surfaces
Example #18
0
    def run(self,
            tstep=30,
            duration=5,
            lonpad=1.5,
            latpad=1.5,
            tpad=7,
            direction='forward',
            bottom=3000,
            rho0=1030,
            clearance=.5,
            shear=-.001,
            fname='ray_trace.csv',
            strain=True,
            stops=True,
            vertspeed=True,
            time_constant=False,
            save_data=False,
            progress_bar=False):
        """
        INSTRUCTIONS:
        TSTEP: TIMESTEP IN SECONDS (DEFAULT 30 SECONDS)
        DURATION: DURATION (IN DAYS) - DEFAULT 5
        IGNORE LONPAD AND LATPAD (DIDNT CHANGE FROM OLDER VERSION)
        DIRECTION: "forward" and "reverse"  (SETS INTEGRATION TIME DIRECTION)
        BOTTOM:  can set default bottom instead of using bathymetry file
        
        Setup for midpoint method integration:
        1. Get field values 
        2. Get Cg @ t_n, X_n
        3. Get field values at t_n+dt/2, X_n + (dt/2)(Cg_n)
        4. Calculate Cg  @(t_n+dt/2, X_n + (dt/2)(Cg_n))
        5. X_(n+1) = X_n +  [dt * Cg  @(t_n+dt/2, X_n + (dt/2)(Cg_n))]
        
        """

        if direction == 'forward':
            # convert duration in hours to seconds
            T = np.arange(0, duration * 60 * 60, tstep)
        else:
            T = np.arange(0, -duration * 60 * 60, -tstep)
            tstep = -tstep

        Xall = []
        Kall = []
        amplitudes = []
        energy = []

        # names of all the columns in results frame
        names = ('Lon', 'Lat', 'depth', 'distance', 'bottom_depth', 'k', 'l',
                 'm', 'omega', 'N2', 'U', 'V', 'dudx', 'dvdx', 'dndx', 'dudy',
                 'dvdy', 'dndy', 'dudz', 'dvdz', 'dndz', 'cgx', 'cgy', 'cgz',
                 'x', 'y', 'z', 'u0', 'v0', 'w0', 'u', 'v', 'w', 'b', 'energy',
                 'u_momentum', 'v_momentum', 'horiz_momentum', 'time')
        cg = []
        steps = []
        localfield = []
        X = self.X0[:]
        lon0 = X[0]
        lat0 = X[1]
        K = self.K0[:]
        t0 = self.t0
        allbottom = []
        if progress_bar:
            pbar = FloatProgress(min=0, max=T.shape[0])
            pbar.value
            display(pbar)

        if not hasattr(self.F, 'dudx'):
            lonlim, latlim, tlim = self.F.createFuncs(X, lonpad, latpad, tpad)

        for ii, t1 in enumerate(T):
            # Get field values
            if progress_bar:
                pbar.value = float(ii)
            t = t0 + t1 / (24 * 60 * 60)
            if X[2] > 6000:
                zi1 = 2499
            else:
                zi1 = X[2]

            f = gsw.f(X[1])
            if time_constant:
                t = np.copy(t0)
            xi = (X[0], X[1], zi1, t)
            field = self.F.getfield(xi)

            f = gsw.f(X[1])

            # Step 1
            dy1 = self._cgy(field[0], K[3], K, field[2], f) * tstep / 2
            dz1 = self._cgz(field[0], K[3], K, f) * tstep / 2
            dx1 = self._cgx(field[0], K[3], K, field[1], f) * tstep / 2

            # midpoint position

            lon2, lat2 = inverse_hav(dx1, dy1, X[0], X[1])
            if X[2] + dz1 > 6000:
                zi = 2499
            else:
                zi = X[2] + dz1
            xi2 = (lon2, lat2, zi, t + tstep / (24 * 60 * 60 * 2))
            if time_constant:
                xi2 = (lon2, lat2, zi, t)
            field1 = self.F.getfield(xi2)
            f2 = gsw.f(lat2)

            # Update Wave properties at midpoint (midpoint refraction)
            dK = self._dKdt(field1, K, xi, xi2, tstep / 2)

            if not np.all(np.isfinite(dK)):

                K1 = K[:]
            else:

                if strain:

                    K1 = [
                        K[0] + dK[0], K[1] + dK[1], K[2] + dK[2], K[3] + dK[3]
                    ]
                else:
                    K1 = [
                        K[0], K[1],
                        K[2] + (tstep / 2) * (-(shear) * (K[0] + K[1])),
                        K[3] + dK[3]
                    ]

            # Step2
            dx2 = self._cgx(field1[0], K1[3], K1, field1[1], f2) * tstep
            dy2 = self._cgy(field1[0], K1[3], K1, field1[2], f2) * tstep
            dz2 = self._cgz(field1[0], K1[3], K1, f2) * tstep

            lon3, lat3 = inverse_hav(dx2, dy2, X[0], X[1])

            lonr = np.expand_dims(np.array([lon0, lon3]), axis=1)
            latr = np.expand_dims(np.array([lat0, lat3]), axis=1)
            distance = gsw.distance(lonr, latr, axis=0)

            if X[2] + dz2 > 6000:
                zi = 2499

            bathypad = np.linspace(-.01, .01, num=5)
            loncheck = bathypad + X[0]
            latcheck = bathypad + X[1]
            loncheck, latcheck = np.meshgrid(loncheck, latcheck)
            tester = np.array([loncheck.flatten(), latcheck.flatten()])
            bottom = np.nanmax([-self.F.bathy((p1[0], p1[1])) \
                                    for p1 in tester.T])
            # bottom = -self.F.bathy((X[0], X[1]))
            X1 = [lon3, lat3, X[2] + dz2, distance, bottom]

            steps.append([dx2, dy2, -dz2])
            cg.append([dx2 / tstep, dy2 / tstep, -dz2 / tstep])
            localfield.append(field)
            Kall.append(K1)
            K = K1
            Xall.append(X1)
            X = X1

            dist_so_far = np.cumsum(steps, axis=0)
            # print(dK[3])
            # print(K[3]**2)
            k = np.copy(K1[0])
            l = np.copy(K1[1])
            m = np.copy(K1[2])
            omega = np.copy(K1[3])
            f = gsw.f(lat3)
            w0 = (self.p0 * (-m * omega) / (field[0] - omega**2))

            # Perturbation amplitudes
            u0 = (self.p0 * (k * omega + l * f * 1j) / (omega**2 - f**2))
            v0 = (self.p0 * (l * omega - k * f * 1j) / (omega**2 - f**2))
            b0 = (self.p0 * (-1j * m * field[0]) / (field[0] - omega**2))

            # total distance so far
            xx = np.copy(dist_so_far[ii, 0])
            yy = np.copy(dist_so_far[ii, 1])
            zz = np.copy(dist_so_far[ii, 2])
            phase = k * xx + l * yy \
                    + m * zz - omega * t1

            # INtegration Limits
            period = np.abs(2 * np.pi / omega)
            t11 = t1 - period / 2
            t22 = t1 + period / 2

            # mean value theorem to get average over one wave period
            u2 = .5 * np.real(w0)**2
            v2 = .5 * np.real(v0)**2
            w2 = .5 * np.real(w0)**2
            b2 = .5 * np.real(b0)**2

            u = (quad(self._planewave,
                      t11,
                      t22,
                      args=(u0, xx, yy, zz, k, l, m, omega))[0])
            v = (quad(self._planewave,
                      t11,
                      t22,
                      args=(v0, xx, yy, zz, k, l, m, omega))[0])
            w = (quad(self._planewave,
                      t11,
                      t22,
                      args=(w0, xx, yy, zz, k, l, m, omega))[0])

            b = (quad(self._planewave,
                      t11,
                      t22,
                      args=(b0, xx, yy, zz, k, l, m, omega))[0])

            amplitudes.append([u0, v0, w0, u, v, w, b])

            # Calculate U and V momentum
            Umom = rho0 * (u * w) / period
            Vmom = rho0 * (v * w) / period

            # Calculate momentum flux
            mFlux = np.sqrt(((u * w) / period)**2 + ((v * w) / period)**2)

            # b = -(field[0] /omega / 9.8) * rho0 * w0 * np.sin(phase)
            # Internal wave energy
            E = .5 * rho0 * (u2 + v2 + w2) \
                + .5 *rho0* b2 * np.sqrt(field[0])**-2
            # E =E/rho0

            energy.append([E, Umom, Vmom, mFlux])

            if stops:
                # check if vertical speed goes to zero
                if vertspeed:
                    if np.abs(dz2 / tstep) < 1e-4:
                        print(
                            'Vertical Group speed = zero {} meters from bottom'
                            .format(bottom - X[2]))
                        break
                    if np.abs(E) > 1000:
                        # this checks if energy has gone to some unrealistic asymptote like behavior
                        print('ENERGY ERROR')
                        break

                    if ii > 3:

                        if np.abs(E - energy[ii - 2][0]) > .8 * E:
                            print('Non Linear')
                            break

                # data Boundary checks
                if not self.lonlim[0] <= X[0] <= self.lonlim[1]:
                    print('lon out of bounds')
                    break

                if not self.latlim[0] <= X[1] <= self.latlim[1]:
                    print('lat out of bounds')
                    break

                if not self.tlim[0] <= t <= self.tlim[1]:
                    print('time out of bounds')
                    print(t)
                    print(self.tlim)
                    break

                #  Check if near the bottom or surface
                if X[2] + clearance * np.abs((2 * np.pi) / K1[2]) >= bottom:
                    print('Hit Bottom - {} meters from bottom'.format(bottom -
                                                                      X[2]))
                    break

                if X[2] <= 0:
                    print('Hit Surface')
                    break

                # Check if  frequency gets too high
                if K1[3]**2 >= self.F.N2(xi2):
                    print('frequency above Bouyancy frequency')
                    # print(K[3]**2)
                    # print(self.F.N2(xi2))
                    break

                if not np.isfinite(X1[0]):
                    print('X Update Error')

                    break

                if np.abs(u0) < 0.0001:
                    print('U amplitude zero')

                    break
                if np.abs(v0) < 0.0001:
                    print('v amplitude zero')

                    break
                if np.abs(w0) < 0.0001:
                    print('w amplitude zero')

                    break

                if not np.isfinite(dx1):
                    print('Field Error')

                    break

        # Save data in pandas data
        data = pd.DataFrame(np.concatenate(
            (np.real(np.stack(Xall)), np.real(np.stack(Kall)),
             np.real(np.stack(localfield)), np.real(
                 np.stack(cg)), np.real(np.stack(np.cumsum(steps, axis=0))),
             np.real(np.stack(amplitudes)), np.real(np.stack(energy)),
             np.real(np.expand_dims(T[:ii + 1], axis=1))),
            axis=1),
                            columns=names)

        if save_data:
            data.to_csv(fname)

        return data
fig = plt.figure(figsize=(6.5, 3))

gs = gridspec.GridSpec(1, 5, width_ratios=[3, 1, 1, 1, 1])
gs.update(wspace=0.9)
axs = [plt.subplot(gs[0]), plt.subplot(gs[1]), plt.subplot(gs[2]),
       plt.subplot(gs[3]), plt.subplot(gs[4])]
#for ax in axs[1:]:
#    ax.yaxis.tick_right()
#    ax.yaxis.set_ticks_position('both')
#    ax.yaxis.set_label_position('right')

colors = ['blue', 'green', 'grey']

N = 2.2e-3
f = gsw.f(-57.5)

for i, M in enumerate(Ms):

    phi_0 = M.trace('phi_0')[:]
    k = np.pi*2./M.trace('X')[:]
    l = np.pi*2./M.trace('Y')[:]
    m = np.pi*2./M.trace('Z')[:]
    print("complete wavelength = {}".format(np.mean(np.pi*2/np.sqrt(k**2 + l**2 + m**2))))
    om = gw.omega(N, k, m, l, f)
    print("om/N = {}".format(np.mean(om/N)))
    w_0 = gw.W_0(phi_0, m, om, N)
    Edens = gw.Edens(w_0, k, m, l)
    Efluxz = gw.Efluxz(w_0, k, m, N, l, f)
    Mfluxz = gw.Mfluxz(phi_0, k, l, m, om, N)
Example #20
0
ds

# %%
IDs = np.unique(ds.ID.values[np.isfinite(ds.ID.values)])
fig, axs = plt.subplots(1, 2)
axs[0].plot(IDs, '.')
axs[1].hist(IDs[IDs > 5e7])

print(IDs[IDs > 5e7][::20])

# %%
ds_ = ds.isel(TIME=ds.BID == 64734970.)
ds_

# %%
fcor = gsw.f(ds_.LAT.min())  # minimum coriolis
Tcor = 2 * np.pi / np.abs(fcor)
Ts = 60. * 60.  # Sampling period
Tlpf = 1.1 * Tcor  # Low pass period

ul = utils.butter_filter(ds_.U, 1 / Tlpf, 1 / Ts)
vl = utils.butter_filter(ds_.V, 1 / Tlpf, 1 / Ts)

fig, ax = plt.subplots(1, 1)
ax.plot(ds_.LON, ds_.LAT)
ax.plot(ds_.LON[0], ds_.LAT[0], "go")
ax.plot(ds_.LON[-1], ds_.LAT[-1], "ro")

fig, axs = plt.subplots(3, 1, sharex=True, figsize=(6, 9))
axs[0].plot(ds_.TIME, ds_.U)
axs[0].plot(ds_.TIME, ul)
def wave_components_with_strain(ctd, ladcp, strain,
                                rho0=default_params['rho0'],
                                ctd_bin_size=1024, ladcp_bin_size=1024,
                                wl_min=300, wl_max=1000,
                                nfft=default_params['nfft'],
                                plots=default_params['plots'], save_data=False):

    """
    Calculating Internal Wave Energy

    Internal wave energy calcuations following methods in waterman et al 2012.

    """
    


    # Load Hydrographic Data
    g = 9.8
    U, V, p_ladcp = oc.loadLADCP(ladcp)
    S, T, p_ctd, lat, lon = oc.loadCTD(ctd)
    SA = gsw.SA_from_SP(S, p_ctd, lon, lat)
    CT = gsw.CT_from_t(SA, T, p_ctd)
    N2, dump = gsw.stability.Nsquared(SA, CT, p_ctd, lat)

    maxDepth = 4000
    idx_ladcp = p_ladcp[:, -1] <= maxDepth
    idx_ctd = p_ctd[:, -1] <= maxDepth

    strain = strain[idx_ctd, :]
    S = S[idx_ctd,:]
    T = T[idx_ctd,:]
    p_ctd = p_ctd[idx_ctd, :]
    U = U[idx_ladcp, :]
    V = V[idx_ladcp, :]
    p_ladcp = p_ladcp[idx_ladcp, :]
    rho = oc.rhoFromCTD(S, T, p_ctd, lon, lat)
    # Bin CTD data
    ctd_bins = oc.binData(S, p_ctd[:, 0], ctd_bin_size)
    # Bin Ladcp Data
    ladcp_bins = oc.binData(U, p_ladcp[:, 0], ladcp_bin_size)

    # Depth and lat/long grids
    depths = np.vstack([np.nanmean(p_ctd[binIn]) for binIn in ctd_bins])
    dist = gsw.distance(lon, lat)
    dist = np.cumsum(dist)/1000
    dist = np.append(0,dist)


    # Calculate Potential Energy
    z = -1*gsw.z_from_p(p_ctd, lat)
    PE, PE_grid, eta_psd, N2mean, pe_peaks = PE_strain(N2, z, strain,
                                             wl_min, wl_max, ctd_bins, nfft=2048)

    # Calculate Kinetic Energy
    z = -1*gsw.z_from_p(p_ladcp, lat)
    KE, KE_grid, KE_psd, Uprime, Vprime, ke_peaks = KE_UV(U, V, z, ladcp_bins,
                                wl_min, wl_max, lc=wl_min-50,
                                nfft=2048, detrend='constant')

    # Total Kinetic Energy
    Etotal = 1027*(KE + PE) # Multiply by density to get Joules

    # wave components
    f = np.nanmean(gsw.f(lat))

    # version 2 omega calculation
    omega = f*np.sqrt((KE+PE)/(KE-PE))

    # version 2 omega calculation
    omega2 = np.abs((f**2)*((KE+PE)/(KE-PE)))
    rw = KE/PE
    w0 = ((f**2)*((rw+1)/(rw-1)))
#    m = (2*np.pi)/np.mean((wl_min, wl_max))
    m = np.nanmean(ke_peaks, axis=1)
    m = ke_peaks[:,0]
    m = m.reshape(omega.shape)
    m = (2*np.pi)*m

    # version 1 kh calculation
    khi = m*np.sqrt(((f**2 - omega**2)/(omega**2 - N2mean)))

    # version 2 kh calculation
    kh = (m/np.sqrt(N2mean))*(np.sqrt(omega2 - f**2))
    mask = khi == 0
    khi[mask]= np.nan
    lambdaH = 1e-3*(2*np.pi)/khi

    # Get coherence of u'b' and v'b' and use to estimate horizontal wavenumber
    # components. This uses the previously binned data but now regrids velocity
    # onto the density grid so there are the same number of grid points
    b = (-g*rho)/rho0
    b_poly = []
    z = -1*gsw.z_from_p(p_ctd, lat)
    fs = 1/np.nanmean(np.diff(z, axis=0))
    for cast in b.T:
        fitrev = oc.vert_polyFit(cast, z[:, 0], 100, deg=1)
        b_poly.append(fitrev)

    b_poly = np.vstack(b_poly).T
    b_prime = b - b_poly

    dz = 1/fs  # This is the vertical spacing between measurements in metres.
    lc = wl_min-50  # This is the cut off vertical scale in metres, the filter will remove variability smaller than this.
    mc = 1./lc  # Cut off wavenumber.
    normal_cutoff = mc*dz*2.  # Nyquist frequency is half 1/dz.
    a1, a2 = sig.butter(4, normal_cutoff, btype='lowpass')  # This specifies you use a lowpass butterworth filter of order 4, you can use something else if you want
    for i in range(b_prime.shape[1]):
        mask = ~np.isnan(b_prime[:,i])
        b_prime[mask,i] = sig.filtfilt(a1, a2, b_prime[mask,i])

    ub = []
    vb = []

    for i in range(ctd_bins.shape[0]):

        Uf = interpolate.interp1d(p_ladcp[ladcp_bins[i,:]].squeeze(),
                                        Uprime[ladcp_bins[i, :], :],
                                        axis=0, fill_value='extrapolate')

        Vf = interpolate.interp1d(p_ladcp[ladcp_bins[i,:]].squeeze(),
                                        Vprime[ladcp_bins[i, :], :],
                                        axis=0, fill_value='extrapolate')
        new_z = p_ctd[ctd_bins[i,:],0]
        u_f, ub_i = sig.coherence(b_prime[ctd_bins[i,:],:],
                                   Uf(new_z), nfft=nfft, fs=fs, axis=0)
        v_f, vb_i = sig.coherence(b_prime[ctd_bins[i,:],:],
                                   Vf(new_z), nfft=nfft, fs=fs, axis=0)

        ub.append(ub_i)
        vb.append(vb_i)

    ub = np.hstack(ub).T
    vb = np.hstack(vb).T


    # Random plots (only run if youre feeling brave)
    m_plot = np.array([(2*np.pi)/wl_max,
                       (2*np.pi)/wl_max, (2*np.pi)/wl_min,
                       (2*np.pi)/wl_min])

    if plots:
        plt.figure(figsize=[12,6])
        plt.subplot(121)
        plt.loglog(KE_grid, KE_psd.T, linewidth=.6, c='b', alpha=.1)
        plt.loglog(KE_grid, np.nanmean(KE_psd, axis=0).T, lw=1.5, c='k')
        ylims = plt.gca().get_ylim()
        ylim1 = np.array([ylims[0], ylims[1]])
        plt.plot(m_plot[2:], ylim1, lw=1,
                 c='k', alpha=.5,
                 linestyle='dotted')
        plt.plot(m_plot[:2], ylim1, lw=1,
                 c='k', alpha=.5,
                 linestyle='dotted')
        plt.ylim(ylims)
        plt.ylabel('Kinetic Energy Density')
        plt.xlabel('Vertical Wavenumber')
        plt.gca().grid(True, which="both", color='k', linestyle='dotted', linewidth=.2)
        plt.subplot(122)
        plt.loglog(PE_grid, .5*np.nanmean(N2)*eta_psd.T,
                   lw=.6, c='b', alpha=.1)
        plt.loglog(KE_grid, .5*np.nanmean(N2)*np.nanmean(eta_psd, axis=0).T,
                   lw=1.5, c='k')
        plt.plot(m_plot[2:], ylim1, lw=1,
                 c='k', alpha=.5,
                 linestyle='dotted')
        plt.plot(m_plot[:2], ylim1, lw=1,
                 c='k', alpha=.5,
                 linestyle='dotted')
        plt.ylim(ylims)
        plt.gca().grid(True, which="both", color='k', linestyle='dotted', linewidth=.2)
        plt.ylabel('Potential Energy Density')
        plt.xlabel('Vertical Wavenumber')

        plt.figure()
        Kemax = np.nanmax(KE_psd, axis=1)
        kespots = np.nanargmax(KE_psd, axis=1)
        ax = plt.gca()
        ax.scatter(KE_grid[kespots],Kemax , c='blue', alpha=0.3, edgecolors='none')
        ax.set_yscale('log')
        ax.set_xscale('log')

        plt.figure(figsize=[12,6])
        plt.subplot(121)
        plt.semilogx(u_f, ub.T, linewidth=.5, alpha=.5)
        plt.gca().grid(True, which="both", color='k', linestyle='dotted', linewidth=.2)
        plt.subplot(122)
        plt.semilogx(v_f, vb.T, linewidth=.5)
        plt.gca().grid(True, which="both", color='k', linestyle='dotted', linewidth=.2)
#        plt.xlim([10**(-2.5), 10**(-2)])

        plt.figure()
        ub_max = np.nanmax(ub, axis=1)
        kespots = np.argmax(ub, axis=1)
        ax = plt.gca()
        ax.scatter(u_f[kespots],ub_max , c='blue', alpha=0.3, edgecolors='none')
        ax.set_xscale('log')
        ax.set_xlim([1e-3, 1e-5])

        Kemax = np.nanmax(.5*np.nanmean(N2)*eta_psd.T, axis=1)
        kespots = np.nanargmax(.5*np.nanmean(N2)*eta_psd.T, axis=1)
        ax = plt.gca()
        ax.scatter(PE_grid[kespots],Kemax , c='red', alpha=0.3, edgecolors='none')
        ax.set_yscale('log')
        ax.set_xscale('log')


        # Peaks lots
        plt.figure()
        mask = np.isfinite(Etotal)
        Etotal[~mask]= 0
        distrev = np.tile(dist, [kh.shape[0],1])
        depthrev = np.tile(depths, [1, kh.shape[1]])
        plt.pcolormesh(distrev, depthrev, Etotal, shading='gouraud')
        plt.gca().invert_yaxis()

        plt.figure()
        plt.pcolormesh(dist, p_ladcp.squeeze(),
                       Uprime, cmap=cmocean.cm.balance,
                       shading='flat')
        levels = np.arange(np.nanmin(Etotal), np.nanmax(Etotal)+.5,.05)
        plt.contour(distrev, depthrev, Etotal)
        plt.gca().invert_yaxis()

    if save_data:

        file2save = pd.DataFrame(lambdaH)
        file2save.index = np.squeeze(depths)
        file2save.to_excel('lambdaH_dec24.xlsx')
        file2save = pd.DataFrame(Etotal)
        file2save.index = np.squeeze(depths)
        file2save.to_excel('E_total.xlsx')

    return PE, KE, omega, m, kh, lambdaH,\
            Etotal, khi, Uprime, Vprime, b_prime,\
            ctd_bins, ladcp_bins, KE_grid, PE_grid,\
            ke_peaks, pe_peaks, dist, depths, KE_psd,\
            eta_psd, N2, N2mean
Example #22
0
def shearstrain(
    depth,
    t,
    SP,
    lon,
    lat,
    ladcp_u=None,
    ladcp_v=None,
    ladcp_depth=None,
    m=None,
    depth_bin=None,
    window_size=None,
    m_include_sh=np.arange(4),
    m_include_st=np.arange(4),
    ladcp_is_shear=False,
    smooth="AL",
    sh_integration_limit=0.66,
    st_integration_limit=0.22,
    window="hamming",
    return_diagnostics=False,
):
    """
    Compute krho and epsilon from CTD/LADCP data via the shear/strain parameterization.

    Parameters
    ----------
    depth : array-like
        CTD depth [m]
    t : array-like
        CTD in-situ temperature [ITS-90, degrees C]
    SP : array-like
        CTD practical salinity [psu]
    lon : array-like or float
        Longitude
    lat : array-like or float
        Latitude
    ladcp_u : array-like, optional
        LADCP velocity east-west component [m/s]. If not provided, only the
        strain solution with a fixed shear/strain ratio of 3 will be computed.
    ladcp_v : array-like, optional
        LADCP velocity north-south component [m/s]
    ladcp_depth : array-like, optional
        LADCP depth vector [m]
    m : array-like, optional
        Wavenumber vector to interpolate spectra onto
    depth_bin : array-like, optional
        Centers of windows over which spectra are computed. Defaults to
        np.arange(75, max(depth), 150). Note that windows are half-overlapping so
        the 150 spacing above means each window is 300 m tall.
    window_size : float
        Size of depth window [m].
    m_include_sh : array-like, optional
        Wavenumber integration range for shear spectra. Array must consist of
        indices or boolans to index m. Defaults to first 4 wavenumbers.
    m_include_st : array-like, optional
        Wavenumber integration range for strain spectra. Array must consist of
        indices or boolans to index m. Defaults to first 4 wavenumbers.
    ladcp_is_shear : bool, optional
        Indicate whether LADCP data is velocity or shear.
        Defaults to False (velocity).
    smooth : {'AL', 'PF'}, optional
        Select type of N^2 smoothing and subsequent strain calculation. 'AL'
        selects the adiabatic leveling method as applied in
        `strain_adiabatic_leveling`. 'PF' selects second order polynomial fits
        to the buoyancy frequency in each window as applied in
        `strain_polynomial_fits`. Defaults to the adiabatic leveling method.
    sh_integration_limit : float, optional
        Shear variance level for determining integration cutoff wavenumber.
        Defaults to 0.66, compare Gargett (1990) :cite:`Gargett1990` and Gregg
        et al. (2003) :cite:`Gregg2003`.
    st_integration_limit : float, optional
        Strain variance level for determining integration cutoff wavenumber.
        Defaults to 0.22, compare Gargett (1990) :cite:`Gargett1990` and Gregg
        et al. (2003) :cite:`Gregg2003`.
    window : str or tuple, optional
        Window type. Defaults to 'hamming' (which corresponds to a sin square
        taper as used in various studies. See `scipy.signal.get_window` for
        details.
    return_diagnostics : bool, optional
        Default is False. If True, this function will return a dictionary
        containing variables such as shear spectra, shear/strain ratios,

    Returns
    -------
    eps_shst : array-like
        Epsilon calculated from both shear and strain spectra
    krho_shst : array-like
        krho calculated from both shear and strain spectra
    diag : dict, optional
        Dictionary of diagnostic variables, set return with the
        `return_diagnostics' argument. `diag` holds the following variables:

        ``"P_shear"``
            Matrix of shear spectra for each depth window (`array-like`).
        ``"P_strain"``
            Matrix of strain spectra for each depth window
        ``"Mmax_sh"``
            Cutoff wavenumber kc (`array-like`).
        ``"Mmax_st"``
            Cutoff wavenubmer used for strain only calculation (`array-like`).
        ``"Rwtot"``
            Shear/strain ratio used, computed from spectra unless specificed in
            input (`array-like`).
        ``"krho_st"``
            krho calculated from strain only (`array-like`).
        ``"eps_st"``
            Epsilon calculated from strain only (`array-like`).
        ``"m"``
            Wavenumber vector (`array-like`).
        ``"depth_bin"``
            Center points of depth windows (`array-like`).
        ``"strain"``
            Results from strain calculation (`dict`).
        ``"Int_sh"``
            Results from shear variance integration (`array-like`).
        ``"Int_st"``
            Results from strain variance integration (`array-like`).

    Notes
    -----
    Adapted from Jen MacKinnon and Amy Waterhouse.
    """
    # Average lon, lat into one value if they are vectors.
    lon = np.nanmean(lon)
    lat = np.nanmean(lat)

    depth = np.asarray(depth)
    t = np.asarray(t)
    SP = np.asarray(SP)

    # Make sure there are no NaNs in the input data
    notnan = np.isfinite(SP) & np.isfinite(t) & np.isfinite(depth)
    isnan = ~notnan
    if not isnan.sum() == 0:
        raise ValueError(
            "No NaNs allowed in CTD data. Consider using `nan_shearstrain` instead."
        )

    # Can we work with velocity data?
    calcsh = False if ladcp_u is None else True

    # No NaNs in velocity/shear data
    if calcsh:
        ladcp_u = np.asarray(ladcp_u)
        ladcp_v = np.asarray(ladcp_v)
        ladcp_depth = np.asarray(ladcp_depth)
        notnansh = (np.isfinite(ladcp_u) & np.isfinite(ladcp_v)
                    & np.isfinite(ladcp_depth))
        isnansh = ~notnansh
        if not isnansh.sum() == 0:
            raise ValueError(
                "No NaNs allowed in LADCP data. Consider using `nan_shearstrain` instead."
            )

    # Coriolis parameter for this latitude
    f = np.absolute(gsw.f(lat))

    if calcsh:
        depth_sh = ladcp_depth

        # Calculate shear if necessary
        if ladcp_is_shear is False:
            uz = helpers.calc_shear(ladcp_u, depth_sh)
            vz = helpers.calc_shear(ladcp_v, depth_sh)
        else:
            uz = ladcp_u
            vz = ladcp_v

    # Create an evenly spaced wavenumber vector if none was provided
    if m is None:
        m = wavenumber_vector(w=300)

    # Generate depth bin vector if none provided
    if depth_bin is None:
        depth_bin = np.arange(75, np.max(depth), 150)
    else:
        # cut out any bins that won't hold any data
        depth_bin = depth_bin[depth_bin < np.max(depth)]
    nz = np.squeeze(depth_bin.shape)
    # delz = np.mean(np.diff(depth_bin))

    # Calculate a smoothed N^2 profile and strain, either using 2nd order
    # polynomial fits to N^2 for each window (PF) or the adiabatic leveling
    # method (AL). Returns a list with data dict for each depth window.
    if smooth == "PF":
        straincalc = strain_polynomial_fits(depth, t, SP, lon, lat, depth_bin,
                                            window_size)
    elif smooth == "AL":
        straincalc = strain_adiabatic_leveling(
            depth,
            t,
            SP,
            lon,
            lat,
            bin_width=300,
            depth_bin=depth_bin,
            window_size=window_size,
        )

    # Convert wavenumber integration range to np.array in case it is something
    # else:
    m_include_sh = np.asarray(m_include_sh)
    m_include_st = np.asarray(m_include_st)

    N0 = 5.24e-3  # (3 cph)
    K0 = 0.05 * 1e-4
    eps0 = 7.8e-10  # Waterman et al. 2014
    # eps0 = 7.9e-10 # Polzin et al. 1995
    # eps0 = 6.73e-10 # Gregg et al. 2003

    P_shear = np.full((nz, m.size), np.nan)
    P_strain = P_shear.copy()
    Mmax_sh = np.full(nz, np.nan)
    Mmax_st = Mmax_sh.copy()
    Rwtot = np.full(nz, np.nan)
    krho_shst = np.full(nz, np.nan)
    krho_st = np.full(nz, np.nan)
    eps_shst = np.full(nz, np.nan)
    eps_st = np.full(nz, np.nan)
    Int_st = np.full(nz, np.nan)
    Int_sh = np.full(nz, np.nan)

    for iwin, (zi, sti) in enumerate(zip(depth_bin, straincalc)):
        assert zi == sti["depth_bin"]
        zw = depth_bin[iwin]

        # Shear spectra
        if calcsh:
            iz = (depth_sh >=
                  (zw - window_size / 2)) & (depth_sh <=
                                             (zw + window_size / 2))
            # Buoyancy-normalize shear
            shear_un = uz[iz] / np.real(np.sqrt(sti["N2mean"]))
            shear_vn = vz[iz] / np.real(np.sqrt(sti["N2mean"]))
            shearn = shear_un + 1j * shear_vn
            ig = ~np.isnan(shearn)
            if np.flatnonzero(ig).size > 10:
                dz = np.mean(np.diff(depth_sh[iz]))
                _, _, Ptot, m0 = helpers.psd(shearn[ig],
                                             dz,
                                             ffttype="t",
                                             detrend=True,
                                             window=window)
                # Compensation for first differencing
                H = np.sinc(m0 * dz / 2 / np.pi)**2
                Ptot = Ptot / H
                Ptot_sh = interp1d(m0, Ptot, bounds_error=False)(m)
                P_shear[iwin, :] = Ptot_sh
            else:
                P_shear[iwin, :] = np.nan
                Ptot_sh = np.zeros_like(m) * np.nan

        # Strain spectra
        # iz = (depth_st >= (zw - delz)) & (depth_st <= (zw + delz))
        segstrain = sti["strain"]
        segstraindep = sti["segz"]
        ig = ~np.isnan(segstrain)
        if np.flatnonzero(ig).size > 10:
            dz = np.mean(np.diff(segstraindep))
            _, _, Ptot, m0 = helpers.psd(segstrain[ig],
                                         dz,
                                         ffttype="t",
                                         detrend=True,
                                         window=window)
            # Compensation for first differencing
            H = np.sinc(m0 * dz / 2 / np.pi)**2
            Ptot = Ptot / H
            Ptot_st = interp1d(m0, Ptot, bounds_error=False)(m)
            P_strain[iwin, :] = Ptot_st
        else:
            P_strain[iwin, :] = np.nan
            Ptot_st = np.zeros_like(m) * np.nan
        # Mean stratification per segment
        Nm = np.sqrt(sti["N2mean"])

        # Shear cutoff wavenumber
        if calcsh:
            iimsh, Mmax_sh[iwin] = find_cutoff_wavenumber(
                Ptot_sh[m_include_sh], m[m_include_sh], sh_integration_limit)

        # Strain cutoff wavenumber
        iimst, Mmax_st[iwin] = find_cutoff_wavenumber(Ptot_st[m_include_st],
                                                      m[m_include_st],
                                                      st_integration_limit)

        if calcsh:
            # Integrate shear spectrum to obtain shear variance
            Ssh = np.trapz(Ptot_sh[iimsh], m[iimsh])
            Int_sh[iwin] = Ssh
            # GM shear variance
            Sshgm, Pshgm = gm_shear_variance(m, iimsh, Nm)

        # Integrate strain spectrum to obtain strain variance
        Sst = np.trapz(Ptot_st[iimst], m[iimst])
        Int_st[iwin] = Sst
        # GM strain variance
        Sstgm, Pstgm = gm_strain_variance(m, iimst, Nm)

        if calcsh:
            # Shear/strain ratio normalized by GM. Factor 3 corrects for the ratio
            # of GM shear to strain = 3 N^2.
            Rw = 3 * (Ssh / Sshgm) / (Sst / Sstgm)
            Rwtot[iwin] = Rw
            # Avoid negative square roots in hRw below
            Rw = 1.01 if Rw < 1.01 else Rw

            # Shear/strain parameterization
            hRw = 3 * (Rw + 1) / (2 * np.sqrt(2) * Rw * np.sqrt(Rw - 1))
            krho_shst[iwin] = (K0 * (Ssh**2 / Sshgm**2) *
                               (hRw * latitude_correction(f, Nm)))
            eps_shst[iwin] = (eps0 * (Nm**2 / N0**2) * (Ssh**2 / Sshgm**2) *
                              (hRw * latitude_correction(f, Nm)))

        # Strain only parameterization
        # Use assumed shear/strain ratio of 3
        Rw = 3
        h2Rw = 1 / 6 / np.sqrt(2) * Rw * (Rw + 1) / np.sqrt(Rw - 1)
        krho_st[iwin] = (K0 * (Sst**2 / Sstgm**2) *
                         (h2Rw * latitude_correction(f, Nm)))
        eps_st[iwin] = (eps0 * (Nm**2 / N0**2) * (Sst**2 / Sstgm**2) *
                        (h2Rw * latitude_correction(f, Nm)))

    if return_diagnostics:
        diag = dict(
            eps_st=eps_st,
            krho_st=krho_st,
            P_shear=P_shear,
            P_strain=P_strain,
            Mmax_sh=Mmax_sh,
            Mmax_st=Mmax_st,
            Rwtot=Rwtot,
            m=m,
            depth_bin=depth_bin,
            strain=straincalc,
            Int_sh=Int_sh,
            Int_st=Int_st,
        )
        return eps_shst, krho_shst, diag
    else:
        return eps_shst, krho_shst
def analyse(z, U, V, dUdz, dVdz, strain, N2_ref, lat, params=default_params):
    """ """

    X = [U, V, dUdz, dVdz, strain, N2_ref]

    if params['plot_profiles']:
        fig, axs = plt.subplots(1, 4, sharey=True)

        axs[0].set_ylabel('$z$ (m)')
        axs[0].plot(np.sqrt(N2_ref), z, 'k-', label='$N_{ref}$')
        axs[0].plot(np.sqrt(strain*N2_ref + N2_ref), z, 'k--', label='$N$')
        axs[0].set_xlabel('$N$ (rad s$^{-1}$)')
        axs[0].legend(loc=0)
        axs[0].set_xticklabels(axs[0].get_xticks(), rotation='vertical')
        axs[1].plot(U, z, 'k-', label='$U$')
        axs[1].plot(V, z, 'r-', label='$V$')
        axs[1].set_xlabel('$U$, $V$ (m s$^{-1}$)')
        axs[1].legend(loc=0)
        axs[1].set_xticklabels(axs[1].get_xticks(), rotation='vertical')
        axs[2].plot(dUdz, z, 'k-', label=r'$\frac{dU}{dz}$')
        axs[2].plot(dVdz, z, 'r-', label=r'$\frac{dV}{dz}$')
        axs[2].set_xlabel(r'$\frac{dU}{dz}$, $\frac{dV}{dz}$ (s$^{-1}$)')
        axs[2].legend(loc=0)
        axs[2].set_xticklabels(axs[2].get_xticks(), rotation='vertical')
        axs[3].plot(strain, z, 'k-')
        axs[3].set_xlabel(r'$\xi_z$ (-)')

    # Split varables into overlapping window segments, bare in mind the last
    # window may not be full.
    width = params['bin_width']
    overlap = params['bin_overlap']
    wdws = [wdw.window(z, x, width=width, overlap=overlap) for x in X]

    n = wdws[0].shape[0]
    z_mean = np.empty(n)
    EK = np.empty(n)
    R_pol = np.empty(n)
    R_om = np.empty(n)
    epsilon = np.empty(n)
    kappa = np.empty(n)

    for i, w in enumerate(zip(*wdws)):

        # This takes the z values from the horizontal velocity.
        wz = w[0][0]
        z_mean[i] = np.mean(wz)
        # This (poor code) removes the z values from windowed variables.
        w = [var[1] for var in w]
        N2_mean = np.mean(w[-1])
        N_mean = np.sqrt(N2_mean)

        # Get the useful power spectra.
        m, PCW, PCCW, Pshear, Pstrain, PEK = \
            window_ps(params['dz'], *w, params=params)

        # Integrate the spectra.
        I = [integrated_ps(m, P, params['m_c'], params['m_0'])
             for P in [Pshear, Pstrain, PCW, PCCW, PEK]]

        Ishear, Istrain, ICW, ICCW, IEK = I

        # Garrett-Munk shear power spectral density normalised.
        # The factor of 2 pi is there to convert to cyclical units.
        GMshear = 2.*np.pi*GM.E_she_z(2*np.pi*m, N_mean)/N_mean

        IGMshear = integrated_ps(m, GMshear, params['m_c'], params['m_0'])

        EK[i] = IEK
        R_pol[i] = ICCW/ICW
        R_om[i] = Ishear/Istrain
        epsilon[i] = GM.epsilon_0*N2_mean/GM.N0**2*Ishear**2/IGMshear**2
        # Apply correcting factors

        epsilon[i] *= L(gsw.f(lat), N_mean)*h_gregg(R_om[i])

        kappa[i] = params['mixing_efficiency']*epsilon[i]/N2_mean

        if params['print_diagnostics']:
            print("Ishear = {}".format(Ishear))
            print("IGMshear = {}".format(IGMshear))
            print("lat = {}. f = {}.".format(lat, gsw.f(lat)))
            print("N_mean = {}".format(N_mean))
            print("R_om = {}".format(R_om[i]))
            print("L = {}".format(L(gsw.f(lat), N_mean)))
            print("h = {}".format(h_gregg(R_om[i])))

        # Plotting here generates a crazy number of plots.
        if params['plot_spectra']:

            # The factor of 2 pi is there to convert to cyclical units.
            GMstrain = 2.*np.pi*GM.E_str_z(2*np.pi*m, N_mean)
            GMvel = 2.*np.pi*GM.E_vel_z(2*np.pi*m, N_mean)

            fig, axs = plt.subplots(4, 1, sharex=True)

            axs[0].loglog(m, PEK, 'k-', label="$E_{KE}$")
            axs[0].loglog(m, GMvel, 'k--', label="GM $E_{KE}$")
            axs[0].set_title("height {:1.0f} m".format(z_mean[i]))
            axs[1].loglog(m, Pshear, 'k-', label="$V_z$")
            axs[1].loglog(m, GMshear, 'k--', label="GM $V_z$")
            axs[2].loglog(m, Pstrain, 'k', label=r"$\xi_z$")
            axs[2].loglog(m, GMstrain, 'k--', label=r"GM $\xi_z$")
            axs[3].loglog(m, PCW, 'r-', label="CW")
            axs[3].loglog(m, PCCW, 'k-', label="CCW")

            axs[-1].set_xlabel('$k_z$ (m$^{-1}$)')

            for ax in axs:
                ax.vlines(params['m_c'], *ax.get_ylim())
                ax.vlines(params['m_0'], *ax.get_ylim())
                ax.grid()
                ax.legend()

    if params['plot_results']:

        fig, axs = plt.subplots(1, 5, sharey=True)

        axs[0].plot(np.log10(EK), z_mean, 'k-o')
        axs[0].set_xlabel('$\log_{10}E_{KE}$ (m$^{2}$ s$^{-2}$)')
        axs[0].set_ylabel('$z$ (m)')
        axs[1].plot(np.log10(R_pol), z_mean, 'k-o')
        axs[1].set_xlabel('$\log_{10}R_{pol}$ (-)')
        axs[1].set_xlim(-1, 1)
        axs[2].plot(np.log10(R_om), z_mean, 'k-o')
        axs[2].set_xlabel('$\log_{10}R_{\omega}$ (-)')
        axs[2].set_xlim(-1, 1)
        axs[3].plot(np.log10(epsilon), z_mean, 'k-o')
        axs[3].set_xlabel('$\log_{10}\epsilon$ (W kg$^{-1}$)')
        axs[4].plot(np.log10(kappa), z_mean, 'k-o')
        axs[4].set_xlabel('$\log_{10}\kappa$ (m$^{2}$ s$^{-1}$)')

        for ax in axs:
            ax.grid()
            ax.set_xticklabels(ax.get_xticks(), rotation='vertical')

    return z_mean, EK, R_pol, R_om, epsilon, kappa
Example #24
0
def lee_wave_tests(kh, omega, N2, ctd, ladcp, dist, depths, error_factor=2, plots=False):
    """
    Testing whether or not the observations can be attributed to lee waves
    """
    S, T, p_ctd, lat, lon = oc.loadCTD(ctd)

#    k, l = horizontal_wave_vector_decomposition(Uspec, Vspec)


    dshift = doppler_shifts(kh, ladcp)

    # Test whether K*U is between N and f
    f = (np.nanmean(gsw.f(lat)))

    dshiftTest = np.full_like(kh, np.nan)
    test_final = np.full_like(kh, np.nan)

    for i, dump in enumerate(kh.T):
        N2mean = np.nanmean(N2[:,i])
        testA = np.abs(dshift[:,i]**2-f**2) <= f**2
        testB = np.abs(dshift[:,i]**2-f**2) <= N2mean
        test_final[:,i] = np.logical_and(testA, testB)
        dshiftTest[:,i] = np.logical_and(dshift[:,i]**2 >= f**2, dshift[:,i]**2<= N2mean)

    dshiftTest2 = dshiftTest == 0
    mask = np.logical_not(test_final)
    kh[mask] = np.nan
    omega[mask] = np.nan
    lambdaH[mask] = np.nan
    k[mask] = np.nan
    l[mask] = np.nan
#    kh[dshiftTest2] = np.nan
#    omega[dshiftTest2] = np.nan
#    lambdaH[dshiftTest2] = np.nan
#    k[dshiftTest2] = np.nan
#    l[dshiftTest2] = np.nan

    file2save = pd.DataFrame(kh)
    file2save.index = np.squeeze(depths)
    file2save.to_excel('Kh_masked.xlsx')
    file2save = pd.DataFrame(omega)
    file2save.index = np.squeeze(depths)
    file2save.to_excel('omega_masked.xlsx')
    file2save = pd.DataFrame(lambdaH)
    file2save.index = np.squeeze(depths)
    file2save.to_excel('lambda_masked.xlsx')
    np.savetxt('kh_masked2.csv', kh)
    np.savetxt('k_masked2.csv', k)
    np.savetxt('l_masked2.csv', l)
    np.savetxt('omega_masked.csv', omega)



    # Test phase of velocity and isopycnal perturbations
    stns = np.arange(1, 1+S.shape[1])
    stns = np.expand_dims(stns, 1)
    stns = np.repeat(stns.T, kh.shape[0], axis=0)

    np.savetxt('dshift_mask.csv',dshiftTest)

    if plots:
        fig = plt.figure()
        plt.contourf(dist, np.squeeze(p_ladcp), U, cmap='seismic')
        plt.colorbar()
        plt.pcolormesh(dist, np.squeeze(depths), dshiftTest, cmap='binary', alpha=.2)
        plt.fill_between(dist, bathy, 4000, color = '#B4B4B4')
        plt.ylim(0, 4000)
        plt.gca().invert_yaxis()
        plt.title("u' with bins with f < Kh*U < N")
        plt.xlabel('Distance Along Transect (km)')
        plt.ylabel('Pressure (dB)')
        for i in range(U.shape[1]):
            plt.annotate(str(i+1), (dist[i], 3600))
import utils


def U_const(z):
    """Constant velocity of 50 cm s-1."""
    return 0.5


def U_shear(z):
    """Default shear of 20 cm s-1 over 1500 m."""
    return 1.3333e-4*z + 5e-1


default_params = {
    'Ufunc': U_const,
    'f': gsw.f(-57.5),
    'N': 1.8e-3,
    'w_0': 0.17,
    'Wf_pvals': np.polyfit([0., 0.06], [0.14, 0.12], 1),
    'dt': 10.,
    't_1': 15000.,
    'x_0': 0.,
    'y_0': 0.,
    'z_0': -1500,
    'print': False
    }


def drdt(r, t, phi_0, Ufunc, Wf_pvals, k, l, m, om, N, f=0., phase_0=0.):
    x = r[0]
    y = r[1]
Example #26
0
# author:   Tiago Bilo

import numpy as np 
import matplotlib.pyplot as plt
from oceans_old.plotting import rstyle
import gsw

plt.rcParams['text.usetex'] = True
plt.rcParams['text.latex.unicode'] = True





## Parameters 
f = gsw.f(45)					# Coriolis parameter (s^-1)
H = 10.*1000					# Height of the domain (m)
u0 = 10. 						# Maximum velocity (m s^-1)
N = 0.01						# Brunt-Vaisala frequency (s^-1)
Rd = N*H/f 						# Rossby deformation radius (m)

## Domain axes (m) 
z = np.linspace(0,H,100)
x = np.linspace(-10/1.0e-6,10/1.0e-6,100)

## Zonal wave numbers (m^-1)
k = np.linspace(0,4.0e-6,100)

## Admensional wavenumber mu
mu = N*H*k/f
Example #27
0
from scipy.interpolate import griddata, interp1d
from netCDF4 import Dataset
import gsw
import glob
import datetime as dt
import xarray as xr
import seawater as sw
import palettable as pal
import matplotlib.gridspec as gridspec

from scipy import signal
import csv

from seabird import cnv

fcor = gsw.f(60)

matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42
matplotlib.rcParams['contour.negative_linestyle'] = 'solid'

rc('xtick', labelsize='Large')
rc('ytick', labelsize='Large')
rc('axes', labelsize='Large')

datadir = '/home/isabela/Documents/projects/OSNAP/data/'
figdir = '/home/isabela/Documents/projects/OSNAP/figures_1418_merged/'

# theta=arctan(vmean[2]/umean[2]) This is how new theta was determined -- just estimated from depth and time averaged flow at this point.
# Copied value here for now so I don't have to load vel necessarily.
theta = 1.164248016423335
Example #28
0
lond, latd = (lon[1:] + lon[:-1]) / 2, (lat[1:] + lat[:-1]) / 2,

#  Plotting
snap = 240
figsize = (12, 6)

fig = plt.figure(figsize=figsize)

ax1 = fig.add_subplot(131, aspect=1)
speed = np.sqrt(surface['u'][snap, 0]**2 + surface['v'][snap, 0]**2)
imspeed = plt.pcolor(lon, lat, speed, vmin=0., vmax=1.5, cmap=cmocean.cm.ice_r)

ax2 = fig.add_subplot(132, aspect=1)
imvort = plt.pcolor(lon,
                    lat,
                    vort['rvort'][snap] / gsw.f(lat),
                    vmin=-5,
                    vmax=5,
                    cmap=cmocean.cm.curl)

ax3 = fig.add_subplot(133, aspect=1)
imdiv = plt.pcolor(lond,
                   latd,
                   div['surface_div'][240] / gsw.f(latd),
                   vmin=-5,
                   vmax=5,
                   cmap=cmocean.cm.balance)

ax1.set_xlabel("Longitude")
ax1.set_ylabel("Latitude")
ax2.set_xlabel("Longitude")
Example #29
0
def analyse(z, U, V, dUdz, dVdz, strain, N2_ref, lat, params=default_params):
    """ """

    X = [U, V, dUdz, dVdz, strain, N2_ref]

    if params['plot_profiles']:
        fig, axs = plt.subplots(1, 4, sharey=True)

        axs[0].set_ylabel('$z$ (m)')
        axs[0].plot(np.sqrt(N2_ref), z, 'k-', label='$N_{ref}$')
        axs[0].plot(np.sqrt(strain * N2_ref + N2_ref), z, 'k--', label='$N$')
        axs[0].set_xlabel('$N$ (rad s$^{-1}$)')
        axs[0].legend(loc=0)
        axs[0].set_xticklabels(axs[0].get_xticks(), rotation='vertical')
        axs[1].plot(U, z, 'k-', label='$U$')
        axs[1].plot(V, z, 'r-', label='$V$')
        axs[1].set_xlabel('$U$, $V$ (m s$^{-1}$)')
        axs[1].legend(loc=0)
        axs[1].set_xticklabels(axs[1].get_xticks(), rotation='vertical')
        axs[2].plot(dUdz, z, 'k-', label=r'$\frac{dU}{dz}$')
        axs[2].plot(dVdz, z, 'r-', label=r'$\frac{dV}{dz}$')
        axs[2].set_xlabel(r'$\frac{dU}{dz}$, $\frac{dV}{dz}$ (s$^{-1}$)')
        axs[2].legend(loc=0)
        axs[2].set_xticklabels(axs[2].get_xticks(), rotation='vertical')
        axs[3].plot(strain, z, 'k-')
        axs[3].set_xlabel(r'$\xi_z$ (-)')

    # Split varables into overlapping window segments, bare in mind the last
    # window may not be full.
    width = params['bin_width']
    overlap = params['bin_overlap']
    wdws = [wdw.window(z, x, width=width, overlap=overlap) for x in X]

    n = wdws[0].shape[0]
    z_mean = np.empty(n)
    EK = np.empty(n)
    R_pol = np.empty(n)
    R_om = np.empty(n)
    epsilon = np.empty(n)
    kappa = np.empty(n)

    for i, w in enumerate(zip(*wdws)):

        # This takes the z values from the horizontal velocity.
        wz = w[0][0]
        z_mean[i] = np.mean(wz)
        # This (poor code) removes the z values from windowed variables.
        w = [var[1] for var in w]
        N2_mean = np.mean(w[-1])
        N_mean = np.sqrt(N2_mean)

        # Get the useful power spectra.
        m, PCW, PCCW, Pshear, Pstrain, PEK = \
            window_ps(params['dz'], *w, params=params)

        # Integrate the spectra.
        I = [
            integrated_ps(m, P, params['m_c'], params['m_0'])
            for P in [Pshear, Pstrain, PCW, PCCW, PEK]
        ]

        Ishear, Istrain, ICW, ICCW, IEK = I

        # Garrett-Munk shear power spectral density normalised.
        # The factor of 2 pi is there to convert to cyclical units.
        GMshear = 2. * np.pi * GM.E_she_z(2 * np.pi * m, N_mean) / N_mean

        IGMshear = integrated_ps(m, GMshear, params['m_c'], params['m_0'])

        EK[i] = IEK
        R_pol[i] = ICCW / ICW
        R_om[i] = Ishear / Istrain
        epsilon[
            i] = GM.epsilon_0 * N2_mean / GM.N0**2 * Ishear**2 / IGMshear**2
        # Apply correcting factors

        epsilon[i] *= L(gsw.f(lat), N_mean) * h_gregg(R_om[i])

        kappa[i] = params['mixing_efficiency'] * epsilon[i] / N2_mean

        if params['print_diagnostics']:
            print("Ishear = {}".format(Ishear))
            print("IGMshear = {}".format(IGMshear))
            print("lat = {}. f = {}.".format(lat, gsw.f(lat)))
            print("N_mean = {}".format(N_mean))
            print("R_om = {}".format(R_om[i]))
            print("L = {}".format(L(gsw.f(lat), N_mean)))
            print("h = {}".format(h_gregg(R_om[i])))

        # Plotting here generates a crazy number of plots.
        if params['plot_spectra']:

            # The factor of 2 pi is there to convert to cyclical units.
            GMstrain = 2. * np.pi * GM.E_str_z(2 * np.pi * m, N_mean)
            GMvel = 2. * np.pi * GM.E_vel_z(2 * np.pi * m, N_mean)

            fig, axs = plt.subplots(4, 1, sharex=True)

            axs[0].loglog(m, PEK, 'k-', label="$E_{KE}$")
            axs[0].loglog(m, GMvel, 'k--', label="GM $E_{KE}$")
            axs[0].set_title("height {:1.0f} m".format(z_mean[i]))
            axs[1].loglog(m, Pshear, 'k-', label="$V_z$")
            axs[1].loglog(m, GMshear, 'k--', label="GM $V_z$")
            axs[2].loglog(m, Pstrain, 'k', label=r"$\xi_z$")
            axs[2].loglog(m, GMstrain, 'k--', label=r"GM $\xi_z$")
            axs[3].loglog(m, PCW, 'r-', label="CW")
            axs[3].loglog(m, PCCW, 'k-', label="CCW")

            axs[-1].set_xlabel('$k_z$ (m$^{-1}$)')

            for ax in axs:
                ax.vlines(params['m_c'], *ax.get_ylim())
                ax.vlines(params['m_0'], *ax.get_ylim())
                ax.grid()
                ax.legend()

    if params['plot_results']:

        fig, axs = plt.subplots(1, 5, sharey=True)

        axs[0].plot(np.log10(EK), z_mean, 'k-o')
        axs[0].set_xlabel('$\log_{10}E_{KE}$ (m$^{2}$ s$^{-2}$)')
        axs[0].set_ylabel('$z$ (m)')
        axs[1].plot(np.log10(R_pol), z_mean, 'k-o')
        axs[1].set_xlabel('$\log_{10}R_{pol}$ (-)')
        axs[1].set_xlim(-1, 1)
        axs[2].plot(np.log10(R_om), z_mean, 'k-o')
        axs[2].set_xlabel('$\log_{10}R_{\omega}$ (-)')
        axs[2].set_xlim(-1, 1)
        axs[3].plot(np.log10(epsilon), z_mean, 'k-o')
        axs[3].set_xlabel('$\log_{10}\epsilon$ (W kg$^{-1}$)')
        axs[4].plot(np.log10(kappa), z_mean, 'k-o')
        axs[4].set_xlabel('$\log_{10}\kappa$ (m$^{2}$ s$^{-1}$)')

        for ax in axs:
            ax.grid()
            ax.set_xticklabels(ax.get_xticks(), rotation='vertical')

    return z_mean, EK, R_pol, R_om, epsilon, kappa
Example #30
0
z = np.linspace(*plt.ylim(), num=10)
xg, zg = np.meshgrid(dist, z)
tg = zg - np.max(topo)
levels = np.arange(-1000, 1, 100)
CS = plt.contour(xg, zg, tg, colors='k', levels=levels)
plt.clabel(CS, inline=1, fontsize=8, fmt='%1.f')

#pf.my_savefig(fig, 'topo', 'section', sdir, fsize='double_col')

# %% Characteristics of the flow
# ---------------------------

# The inertial frequency...
lat_mean = -57.5  # np.mean(lats)
f = np.abs(gsw.f(lat_mean))
print("Mean inertial frequency at {:1.1f} degrees is {:.2E} rad s-1. "
      "The period is {:1.1f} hours.".format(lat_mean, f,
                                            2 * np.pi / (60 * 60 * f)))

# - $N \approx 2.3 \times 10^{-3}$ rad s$^{-1}$. (Near bottom of profiles
# upstream of the ridge.)
# - $U \approx 0.3$ m s$^{-1}$. (Near bottom of profiles upstream of the
# ridge.)
# - $f \approx 1.2 \times 10^{-4}$ rad s$^{-1}$. (57 degrees south.)
# - $h_0 \approx 2 \times 10^3$ m (Ridge height.)
# - $L \approx 2 \times 10^4$ m (Ridge width.)
#
# Periods of motion.
#
# - Buoyancy period, $T_N \approx 50$ mins.
import utils


def U_const(z):
    """Constant velocity of 50 cm s-1."""
    return 0.5


def U_shear(z):
    """Default shear of 20 cm s-1 over 1500 m."""
    return 1.3333e-4 * z + 5e-1


default_params = {
    'Ufunc': U_const,
    'f': gsw.f(-57.5),
    'N': 1.8e-3,
    'w_0': 0.17,
    'Wf_pvals': np.polyfit([0., 0.06], [0.14, 0.12], 1),
    'dt': 10.,
    't_1': 15000.,
    'x_0': 0.,
    'y_0': 0.,
    'z_0': -1500,
    'print': False
}


def drdt(r, t, phi_0, Ufunc, Wf_pvals, k, l, m, om, N, f=0., phase_0=0.):
    x = r[0]
    y = r[1]
Example #32
0
        nans = np.isnan(z) | np.isnan(t) | np.isnan(Ww) | np.isnan(N2_ref) | (z > -50)
        z, t, Ww, N2_ref = z[~nans], t[~nans], Ww[~nans], N2_ref[~nans]

        # Setting up the spectral analysis.
        ts = 60.*t  # Convert to seconds.
        dt = np.round(np.mean(np.diff(ts)))
        fs = 1./dt
        it = np.arange(np.min(ts), np.max(ts), dt)
        iWw = np.interp(it, ts, Ww)
        diWw = sig.detrend(iWw)

        # Get an idea of the buoyancy frequency.
        N_mean = np.mean(np.sqrt(N2_ref[z < -200]))/(2.*np.pi)
        # The inertial frequency.
        fcor = np.abs(gsw.f(-57.5))/(2.*np.pi)

        # Perform the spectral analysis.
        freqs, Pw = sig.welch(iWw, fs=fs, detrend='linear')

        # Fit a curve.
        popt, __ = op.curve_fit(plane_wave, it, diWw,
                                p0=[0.1, 0.002, 0.])
        omfit = popt[1]/(2.*np.pi)
        period = 1/omfit/60.

        plt.figure(figsize=(4,6))

#        plt.subplot(1, 2, 1)
        plt.plot(diWw, it, plane_wave(it, *popt), it)
        plt.xticks(rotation=45)
# hmw4_q2.py
#
# purpose:  Plot the Eady Model solutions from question 2
#
# author:   Tiago Bilo

import numpy as np
import matplotlib.pyplot as plt
from oceans_old.plotting import rstyle
import gsw

plt.rcParams['text.usetex'] = True
plt.rcParams['text.latex.unicode'] = True

## Parameters
f = gsw.f(45)  # Coriolis parameter (s^-1)
H = 10. * 1000  # Height of the domain (m)
u0 = 10.  # Maximum velocity (m s^-1)
N = 0.01  # Brunt-Vaisala frequency (s^-1)
Rd = N * H / f  # Rossby deformation radius (m)

## Domain axes (m)
z = np.linspace(0, H, 100)
x = np.linspace(-10 / 1.0e-6, 10 / 1.0e-6, 100)

## Zonal wave numbers (m^-1)
k = np.linspace(0, 4.0e-6, 100)

## Admensional wavenumber mu
mu = N * H * k / f