def epv_sphere(theta, u, v, levs, lats, lons):
    """
    Computes the Ertel Potential Vorticity (PV) on a latitude/longitude grid.

    :param theta: 3D potential temperature array on isobaric levels
    :param u: 3D u components of the horizontal wind on isobaric levels
    :param v: 3D v components of the horizontal wind on isobaric levels
    :param levs: 1D pressure vectors
    :param lats: 1D latitude vectors
    :param lons: 1D longitude vectors
    :return: Ertel PV in potential vorticity units (PVU)
    """

    iz, iy, ix = theta.shape

    dthdp, dthdy, dthdx = gradient_sphere(theta, levs, lats, lons)
    dudp, dudy, dudx = gradient_sphere(u, levs, lats, lons)
    dvdp, dvdy, dvdx = gradient_sphere(v, levs, lats, lons)

    abvort = np.zeros_like(theta).astype('f')
    for kk in range(0, iz):
        abvort[kk, :, :] = vertical_vorticity_latlon(u[kk, :, :].squeeze(),
                                                     v[kk, :, :].squeeze(),
                                                     lats,
                                                     lons,
                                                     abs_opt=True)

    epv = (-9.81 * (-dvdp * dthdx - dudp * dthdy + abvort * dthdp)) * 1.0e6
    return epv
Example #2
0
def epv_sphere(theta, pres, u, v, lats, lons):
    """
    Computes the Ertel Potential Vorticity (PV) on a latitude/longitude grid
    https://github.com/scavallo/python_scripts/blob/master/utils/weather_modules.py
   
    Input:    
       theta:       3D potential temperature array on isobaric levels
       pres:        3D pressure array
       u,v:         3D u and v components of the horizontal wind on isobaric levels
       lats,lons:   1D latitude and longitude vectors
    
    Output:  
      epv: Ertel PV in potential vorticity units (PVU)
   
    Steven Cavallo
    October 2012
    University of Oklahoma
    """
    iz, iy, ix = theta.shape

    dthdp, dthdy, dthdx = gradient_sphere(theta, pres, lats, lons)
    dudp, dudy, dudx = gradient_sphere(u, pres, lats, lons)
    dvdp, dvdy, dvdx = gradient_sphere(v, pres, lats, lons)

    avort = np.zeros_like(theta).astype('f')
    for kk in range(0, iz):
        avort[kk, :, :] = vertical_vorticity_latlon(u[kk, :, :].squeeze(),
                                                    v[kk, :, :].squeeze(),
                                                    lats, lons, 1)

    epv = (-9.81 * (-dvdp * dthdx - dudp * dthdy + avort * dthdp)) * 10**6

    return epv
def vertical_vorticity_latlon(u, v, lats, lons, abs_opt=False):
    """
    Calculate the vertical vorticity on a latitude/longitude grid.

    :param u: 2 dimensional u wind arrays, dimensioned by (lats,lons).
    :param v: 2 dimensional v wind arrays, dimensioned by (lats,lons).
    :param lats: latitude vector
    :param lons: longitude vector
    :param abs_opt: True to compute absolute vorticity,
                    False for relative vorticity only
    :return: Two dimensional array of vertical vorticity.
    """

    dudy, dudx = gradient_sphere(u, lats, lons)
    dvdy, dvdx = gradient_sphere(v, lats, lons)

    if abs_opt:
        # 2D latitude array
        glats = np.zeros_like(u).astype('f')
        for jj in range(0, len(lats)):
            glats[jj, :] = lats[jj]

        # Coriolis parameter
        f = 2 * 7.292e-05 * np.sin(np.deg2rad(glats))
    else:
        f = 0.

    vert_vort = dvdx - dudy + f

    return vert_vort
Example #4
0
def eliassen_palm_flux_sphere(geop, theta, lats, lons, levs, normalize_option):
    """
    Computes the 3-D Eliassen-Palm flux vectors and divergence on a 
    latitude/longitude grid with any vertical coordinate 
   
    Computation is Equation 5.7 from:
    R. A. Plumb, On the Three-dimensional Propagation of Stationary Waves, J. Atmos. Sci., No. 3, 42 (1985).
  
    Input:    
        geop:      3D geopotential (m^2 s-2)
        theta:     3D potential temperature (K)
        lats,lons: 1D latitude and longitude vectors
        levs:      1D pressure vector (Pa)
        normalize_option: 0 = no normalizing, 1 = normalize by maximum value at each vertical level, 2 = standardize 
   
    Output:      
       Fx, Fy, Fz: Eliassen-Palm flux x, y, z vector components
       divF: Eliassen-Palm flux divergence
   
    Steven Cavallo
    March 2014
    University of Oklahoma
    """

    iz, iy, ix = geop.shape

    # First need to filter out numeric nans
    geop = arr.filter_numeric_nans(geop, 0, 0, 'low')
    theta = arr.filter_numeric_nans(theta, 200, 0, 'low')
    theta = arr.filter_numeric_nans(theta, 10000, 0, 'high')

    theta_anom, theta_anom_std = calculate.spatial_anomaly(theta, 1)
    geop_anom, geop_anom_std = calculate.spatial_anomaly(geop, 1)

    latarr = np.zeros_like(geop).astype('f')
    farr = np.zeros_like(geop).astype('f')
    for kk in range(0, iz):
        for jj in range(0, iy):
            latarr[kk, jj, :] = lats[jj]
            farr[kk, jj, :] = 2.0 * constants.omega * np.sin(lats[jj] *
                                                             (np.pi / 180.0))

    psi = geop / farr
    psi_anom, psi_anom_std = calculate.spatial_anomaly(psi, 1)

    pres = np.zeros_like(theta_anom).astype('f')
    for kk in range(0, iz):
        pres[kk, :, :] = levs[kk]

    coef = pres * np.cos(latarr * (np.pi / 180.0))
    arg1 = coef / (2.0 * np.pi * (constants.Re**2) *
                   np.cos(latarr * (np.pi / 180.0)) * np.cos(latarr *
                                                             (np.pi / 180.0)))
    arg2 = coef / (2.0 * np.pi * (constants.Re**2) * np.cos(latarr *
                                                            (np.pi / 180.0)))
    arg3 = coef * (2.0 * (constants.omega**2) *
                   np.sin(latarr * (np.pi / 180.0)) * np.sin(latarr *
                                                             (np.pi / 180.0)))

    dthdz, yy, xx = gradient_sphere(theta, geop / g, lats, lons)
    xx, dthdy, dthdx = gradient_sphere(theta_anom, geop / g, lats, lons)
    dpsidz, dpsidy, dpsidx = gradient_sphere(psi_anom, geop / g, lats, lons)
    d2psidxdz, d2psidxdy, d2psidx2 = gradient_sphere(dpsidx, geop / g, lats,
                                                     lons)
    aaa, d2psidxdz, ccc = gradient_sphere(dpsidz, geop / g, lats, lons)

    N2 = (g / theta) * (dthdz)
    arg4 = arg3 / (N2 * constants.Re * np.cos(latarr * (np.pi / 180.0)))

    Fx = arg1 * (dpsidx**2.0 - (psi_anom * d2psidx2))
    Fy = arg2 * ((dpsidy * dpsidx) - (psi_anom * d2psidxdy))
    Fz = arg4 * ((dpsidx * dpsidz) - (psi_anom * d2psidxdz))

    Fx_z, Fx_y, Fx_x = gradient_sphere(Fx, geop / g, lats, lons)
    Fy_z, Fy_y, Fy_x = gradient_sphere(Fy, geop / g, lats, lons)
    Fz_z, Fz_y, Fz_x = gradient_sphere(Fz, geop / g, lats, lons)

    divF = Fx_x + Fy_y + Fz_z

    if normalize_option == 1:
        for kk in range(0, iz):
            Fx[kk, :, :] = Fx[kk, :, :] / np.nanmax(np.abs(Fx[kk, :, :]))
            Fy[kk, :, :] = Fy[kk, :, :] / np.nanmax(np.abs(Fy[kk, :, :]))
            Fz[kk, :, :] = Fz[kk, :, :] / np.nanmax(np.abs(Fz[kk, :, :]))
    if normalize_option == 2:
        for kk in range(0, iz):
            Fx[kk, :, :] = Fx[kk, :, :] / np.nanstd(Fx[kk, :, :])
            Fy[kk, :, :] = Fy[kk, :, :] / np.nanstd(Fy[kk, :, :])
            Fz[kk, :, :] = Fz[kk, :, :] / np.nanstd(Fz[kk, :, :])

    return Fx, Fy, Fz, divF