def track_orient(x,y,orient=False):
#    ;Calculate track orientation (on 3 points lagrangian interpolation - see DERIV help page)
    
    getorient=orient
    
    dxy=deriv(x,y)
    
    dx=np.median(deriv(x))
    dy=np.median(deriv(y))

    orient = np.arctan(dxy) if dx > 0 else np.arctan(dxy) + np.pi #Rotate backward (180�)
                                                                  #orientation when track goes
                                                                  #westward
  
    orient = np.remainder(orient,2.0*np.pi)
#    if (medorient < 0) : orient += 2.0*np.pi
#    if (medorient > 2.0*np.pi) THEN orient -= 2D*!dpi
    #Sense is positive for ascending tracks
    sense = True if np.median(orient) < np.pi else False
  
    if getorient : return sense, orient
    else : return sense
示例#2
0
def track_orient(x, y, orient=False):
    #    ;Calculate track orientation (on 3 points lagrangian interpolation - see DERIV help page)

    getorient = orient

    dxy = deriv(x, y)

    dx = np.median(deriv(x))
    dy = np.median(deriv(y))

    orient = np.arctan(
        dxy) if dx > 0 else np.arctan(dxy) + np.pi  #Rotate backward (180�)
    #orientation when track goes
    #westward

    orient = np.remainder(orient, 2.0 * np.pi)
    #    if (medorient < 0) : orient += 2.0*np.pi
    #    if (medorient > 2.0*np.pi) THEN orient -= 2D*!dpi
    #Sense is positive for ascending tracks
    sense = True if np.median(orient) < np.pi else False

    if getorient: return sense, orient
    else: return sense
示例#3
0
 alti_pattern = '/archive/MSA/rdussurget/sauvegarde_13032013/VMShared/data/alti/regional/mfstep-dt/j2_cf/dt_upd_med_j2_sla_vxxc_*.nc'
 alti=alti_data(alti_pattern,limit=limit,verbose=verbose,time_range=trange.tolist(),track=t)
 alti.update_with_slice(alti.slice('track', t))
 alti.reorder()  
 
 cycle_list=alti.cycle_list()
 tracks=alti.track_list()
 trange_str = alti.time_range()[0]
 
 nt=len(cycle_list)
 
 sla=alti.sla*100.0
 lon=alti.lon
 lat=alti.lat
 dst=AT.calcul_distance(lat,lon)
 dx=np.median(AT.deriv(dst))
 N=len(lon)
 
 slaft=np.ma.empty(sla.shape)
 ugpl=slaft.copy()
 ugpllo=slaft.copy()
 ugfd=slaft.copy()
 ugfds=slaft.copy()
 
 #Filter small scales
 for i in np.arange(nt):
     slaft[i,:]=AT.loess(sla[i,:], dst, 40.)
     ugpl[i,:] = geost_1d(lon,lat,sla[i,:]/100.,pl04=True,p=20.,q=20.)
     ugpllo[i,:] = geost_1d(lon,lat,slaft[i,:]/100.,pl04=True,p=20.,q=20.)
     ugfd[i,:] = geost_1d(lon,lat,slaft[i,:]/100.,pl04=False)
     dumlon,dumlat,ugfds[i,:-1] = geost_1d(lon,lat,slaft[i,:]/100.,pl04=False,strict=True)
示例#4
0
                     time_range=trange.tolist(),
                     track=t)
    alti.update_with_slice(alti.slice('track', t))
    alti.reorder()

    cycle_list = alti.cycle_list()
    tracks = alti.track_list()
    trange_str = alti.time_range()[0]

    nt = len(cycle_list)

    sla = alti.sla * 100.0
    lon = alti.lon
    lat = alti.lat
    dst = AT.calcul_distance(lat, lon)
    dx = np.median(AT.deriv(dst))
    N = len(lon)

    slaft = np.ma.empty(sla.shape)
    ugpl = slaft.copy()
    ugpllo = slaft.copy()
    ugfd = slaft.copy()
    ugfds = slaft.copy()

    #Filter small scales
    for i in np.arange(nt):
        slaft[i, :] = AT.loess(sla[i, :], dst, 40.)
        ugpl[i, :] = geost_1d(lon,
                              lat,
                              sla[i, :] / 100.,
                              pl04=True,
示例#5
0
def geost_1d(*args, **kwargs):  #(lon,lat,nu): OR (dst,nu)
    """
    ;+
    ;
    ;   GEOST_1D : Compute geostrophic speeds from a sea level dataset <br />
    ;
    ;   Reference : Powell, B. S., et R. R. Leben (2004), An Optimal Filter for <br />
    ;   Geostrophic Mesoscale Currents from Along-Track Satellite Altimetry, <br />
    ;   Journal of Atmospheric and Oceanic Technology, 21(10), 1633-1642.
    ;
    ; @param lon {in}{optional}{type:NUMERIC} longitude in degrees
    ; @param lat {in}{optional}{type:NUMERIC} latitude in degrees
    ; @param dst {in}{optional}{type:NUMERIC} along-track distance.
    ; @param z {in}{required}{type:NUMERIC} sea level surface. Can either be absolute<br />
    ;          values (SSH) or relative values (SLA). This MUST be given in METERS.
    ; @keyword strict {in}{optional}{type:BOOLEAN} If True, compute gradient at mid-distance.
    ; @keyword pl04 {in}{optional}{type:BOOLEAN} If True, use the Powell & Leben 2004 method.
    ;          
    ; @returns Geostrophic velocity component, positive eastward
    ;
    ;
    ;
    ; @author Renaud DUSSURGET, LEGOS/CTOH
    ; @history Created Sep. 2009 from genweights.m (Brian Powell (c) 2004, <br />
    ;   University of Colorado, Boulder)<br />
    ;   Modified May 2010 to be compliant with 20Hz datasets (p & n can vary).<br />
    ;     Warining may also be issued for data with holes within the width of the<br />
    ;     window.<br />
    ;   Modified June 2010 to include filtering window width in KM instead of nb. of<br />
    ;     points (Equivalent btw. 1Hz and 20Hz data).<br />
    ;
    ; @uses CALCUL_DISTANCE, EXIST, GENWEIGTHS, SETINTERSECTION, SETUNION, <br />
    ;   OPTIMAL_SLOPE, GRAVITY, CORIOLIS, TRACK_ORIENT
    ;
    ; @example dummy1=geost_1D(lon,lat,sla,pl04=True,p=11,q=11) :<br />
    ;   Return along-track velocity anomalies using a 11km by 11km Powell & Leben 2004 filter window <br />
    ;          dummy2=geost_1D(dst,sla,strict=True) :<br />
    ;   Return along-track velocity anomalies computed at mid-distance <br />
    ;
    ;-
    """

    lon = args[0]
    lat = args[1]

    dst = args[2] if len(args) == 4 else calcul_distance(
        lat, lon) * 1e3  #distance in meters
    nu = args[3] if len(args) == 4 else args[2]

    isVector = len(np.shape(nu)) == 1

    #Reshape nu if vector
    if isVector: nu = np.reshape(nu, (len(nu), 1))

    nt = np.shape(nu)[1] if not isVector else 1
    sh = nu.shape
    nufilt = np.ma.array(np.empty(sh), mask=True, dtype=nu.dtype)

    pl04 = kwargs.pop('pl04', False)
    filter = kwargs.pop('filter', None)
    strict = kwargs.pop('strict', False)
    verbose = kwargs.pop('verbose', False)

    if filter is not None:
        for t in np.arange(nt):
            nufilt[:, t] = loess(nu[:, t], dst, filter * 1e3)
        nu = nufilt

    if pl04:
        ug = np.ma.array(np.empty(sh), mask=True, dtype=nu.dtype)
        for t in np.arange(nt):
            ug[:, t] = powell_leben_filter_km(lon,
                                              lat,
                                              nu[:, t],
                                              verbose=verbose,
                                              **kwargs)
        if isVector: ug = ug.flatten()
        return ug

    #If strict option is set to True, compute gradients at mid-distance between points
    if strict:
        lon = (lon[1:] - lon[:-1]) / 2. + lon[0:-1]
        lat = (lat[1:] - lat[:-1]) / 2. + lat[0:-1]

    #Compute gravitational & coriolis forces
    if strict: sh = (sh[0] - 1, sh[1])
    g = np.repeat(gravity(lat), nt).reshape(sh)
    f = np.repeat(coriolis(lat), nt).reshape(sh)

    #Compute SSH 1st derivative
    #    dh = deriv(dst,nu) #(deriv is very bad...)

    dh = np.ma.array(np.empty(sh), mask=True, dtype=nu.dtype)
    for t in np.arange(nt):
        dh[:, t] = (nu[1:, t] - nu[:-1, t]) / (dst[1:] -
                                               dst[:-1]) if strict else deriv(
                                                   dst, nu[:, t])

    #Compute geostrophy


#    print f
#    print g
#    print dh
    ug = -(g * dh) / (f)

    #Inverse sign of ug for descending tracks as Coriolis is oriented to the right
    #northward
    if (not track_orient(lon, lat)):  #descending tracks
        ug *= -1

    if isVector: ug = ug.flatten()

    return (lon, lat, ug) if strict else ug
示例#6
0
def decorrelation_scale(var, lat, lon, ind, verbose=1):
    '''
    solid_body_scale
    @summary: Compute the decorrelation length-scale of detected eddies.
    @note: This is the original technique applied in :
           Dussurget, R, F Birol, R.A. Morrow, et P. De Mey. 2011. « Fine Resolution<br />
           Altimetry Data for a Regional Application in the Bay of Biscay ». Marine<br />
           Geodesy 2 (34): 1‑30. doi:10.1080/01490419.2011.584835.
    @note: A linear regression is applied between the two points around the decorrelation<br />
           scale to better detect its position.
    @note: If no sufficient data is found on one of both sides, eddy is considered as<br />
           symmetric and scales are thus only computed from one side.
    @param var: variable on which to apply the analysis : SLA, wavelet-filtered SLA,<br />
                daughter wavelets, etc...
    @param lon, lat: Longitude/latitude arrays.
    @ind: Indices of detected eddies.
    @return diameter, symmetric : Diameter (km) of detected eddies, and symmetric flag to<br />
            check whether symmetry assumption was used or not.
    @author: Renaud DUSSURGET, LER/PAC IFREMER.
    @since : November 2012.
    @change: Create in November 2012 by RD.

    '''
    xid = ind[1]
    yid = ind[0]
    ne = np.size(xid)
    diameter = np.zeros(ne, dtype=np.float64)
    symmetric = np.zeros(ne, dtype=bool)

    if verbose >= 1: print '\tdecorrelation_scale() running'

    for j in np.arange(ne):
        #        print j
        #Extract current SLA profile
        cursla = var[xid[j], :]
        fg = ~cursla.mask
        dumy = np.where(np.arange(len(cursla))[fg] == yid[j])[0][
            0]  #update yid with compressed SLA array
        cursla = cursla[fg]
        cursla -= np.median(cursla)

        #Fill gaps
        dst, dumlon, dumlat, dumsla, gaplen, ngaps, gapedges, interpolated = grid_track(
            lat[fg], lon[fg], cursla)

        #Update yid with resampled SLA array
        dumy = np.arange(len(dst))[~interpolated][dumy]

        #Shrink data if there are any gaps greater than 3 points (ie. no valid interpolation)
        #        if (gaplen > 3).any() :
        #            gapedges=gapedges[:,gaplen > 3] #Remove gaps smaller than 3 points
        #            left=gapedges[1,np.where(gapedges[1,:] >= dumy)[0][0]] if (gapedges[1,:] < dumy).any() else 0
        #            right=gapedges[0,np.where(gapedges[0,:] >= dumy)[0][0]] if (gapedges[0,:] >= dumy).any() else len(dumsla)-1
        #            dumsla=dumsla[left:right+1]

        #Get sla profile on both sides of the eddy
        dumsla_r = dumsla[dumy:]  #np.roll(cursla,-dumy)
        dumsla_l = dumsla[dumy:0:-1]  #np.roll(cursla[::-1],dumy+1)

        #Compute the auto-correlation on each sides.
        nr = len(dumsla_r)
        nl = len(dumsla_l)
        acorr_l = np.zeros(nl)
        acorr_r = np.zeros(nr)
        lag_r = np.arange(nr)
        lag_l = np.arange(nl)
        for i, l in enumerate(lag_l):
            acorr_l[i] = np.corrcoef(dumsla_l, np.roll(dumsla_l, l))[0][1]
        for i, l in enumerate(lag_r):
            acorr_r[i] = np.corrcoef(dumsla_r, np.roll(dumsla_r, l))[0][1]

        #detect first zero crossing of auto-corr function with the derivative of its absolute
        zc_l = (np.where(
            deriv(np.abs(acorr_l)) > acorr_l))[0] if nl >= 3 else []
        zc_r = (np.where(
            deriv(np.abs(acorr_r)) > acorr_r))[0] if nr >= 3 else []
        zer_cross = []
        if len(zc_l) != 0: zer_cross = np.append(zer_cross, zc_l[0])
        if len(zc_r) != 0: zer_cross = np.append(zer_cross, zc_r[0])

        #Linearly interpolate the auto-correlation function to get the zero-crossing distance
        fit = np.ma.array(np.zeros((2, 2)), mask=np.ones((2, 2), dtype=bool))
        if len(zc_l) != 0:
            fit[0, :] = np.ma.array(np.polyfit(
                dst[zc_l[0] - 1:zc_l[0] + 1], acorr_l[zc_l[0] - 1:zc_l[0] + 1],
                1),
                                    mask=np.zeros((2), dtype=bool))
        if len(zc_r) != 0:
            fit[1, :] = np.ma.array(np.polyfit(
                dst[zc_r[0] - 1:zc_r[0] + 1], acorr_r[zc_r[0] - 1:zc_r[0] + 1],
                1),
                                    mask=np.zeros((2), dtype=bool))

        #If no decorrelation is found on one side, use twice the decorrelation on valid side
        if fit.mask.sum() == 2:
            fit[fit.mask] = fit[~fit.mask]
            symmetric[j] = True

        #Get diameter
        diameter[j] = -((fit[0][1] / fit[0][0]) + (fit[1][1] / fit[1][0]))

    return diameter, symmetric
示例#7
0
def solid_body_scale(var, lat, lon, ind, verbose=1, **kwargs):
    '''
    solid_body_scale
    @summary: Compute the diameter of eddy core using maxima of geostrophic velocities<br />
              computed on both sides of the eddy, and computes the equivalent Relative<br />
              Vorticity for a solid body rotating eddy.
    @note: This technique was first applied in Le Hénaff et al., 2012. Cyclonic<br />
           activity in the eastern Gulf of Mexico: characterization. Submitted to <br />
           Progress in Oceanography.
    @note: A 2nd order polynomial over 3-4 points around the velocity maximum is<br />
           computed to better detect its position.
    @note: Geostrophic velocities are computed using the Powell and Leben (2004)<br />
           methodology - powell_leben_filter_km() function. Filtering parameters are<br/>
           p=q=12km on each sides of the point.
           Powell, B.S., et R.R. Leben. 2004. « An Optimal Filter for Geostrophic Mesoscale<br/>
           Currents from Along-Track Satellite Altimetry ». Journal of Atmospheric and<br/>
           Oceanic Technology 21 (10) (octobre 1): 1633‑1642.
    @param var: variable on which to apply the analysis : SLA, wavelet-filtered SLA,<br />
                daughter wavelets, etc...
    @param lon, lat: Longitude/latitude arrays.
    @ind: Indices of detected eddies.
    @return diameter, relvort : Diameter (km) and Relative Vorticity (s-1) of detected eddies.
    @author: Renaud DUSSURGET, LER/PAC IFREMER.
    @since : November 2012.
    @change: Created in November 2012 by RD.
    '''

    #Set defaults values for geostrophic velocities
    p = kwargs.pop('p', 20.)
    q = kwargs.pop('q', p)
    filter = kwargs.pop('filter', 40.)

    if verbose >= 1:
        print '\tsolid_body_scale() running: SLA filtering prior computation of velocities:{0} km, Velocity filtering:{1} km'.format(
            np.int(filter) if filter is not None else 'None', np.int(p + q))

    xid = ind[1]
    yid = ind[0]
    ne = np.size(xid)
    diameter = np.zeros(ne, dtype=np.float32)  #Peak-to-peak diameter
    amplitude = np.zeros(
        ne, dtype=np.float32)  #Amplitude over peak-to-peak baseline
    north = np.zeros(ne, dtype=np.float32)  #Position of northern edge
    south = np.zeros(ne, dtype=np.float32)  #Position of southern edge
    relvort = np.zeros(
        ne, dtype=np.float32
    )  #Estimated relative vorticity (linear fitted of speed vs radius - chose another model)
    rk_diameter = np.zeros(
        ne, dtype=np.float32)  #Peak-to-peak diameter of the Rankine vortex
    rk_relvort = np.zeros(
        ne, dtype=np.float32
    )  #Estimated relative vorticity (for a fitted rankine vortex model)
    rk_center = np.zeros(
        ne, dtype=int)  #Center of unbiased rankine vortex (cf. self advection)
    self_advect = np.zeros(
        ne, dtype=np.float32)  #Self advection (velocity anomaly)

    for j in np.arange(ne):
        #        print j
        #Extract current SLA profile
        cursla = var[xid[j], :]
        fg = ~cursla.mask
        dumy = np.where(np.arange(len(cursla))[fg] == yid[j])[0][
            0]  #update yid with compressed SLA array
        cursla = cursla[fg]
        cursla -= np.median(cursla)

        #Fill gaps
        dst, dumlon, dumlat, dumsla, gaplen, ngaps, gapedges, interpolated = grid_track(
            lat[fg], lon[fg], cursla)
        ugeo = geost_1d(dumlon,
                        dumlat,
                        dumsla,
                        pl04=True,
                        filter=filter,
                        p=p,
                        q=q)
        ncur = len(dst)

        northward = dumlat[-1] > dumlat[0]

        #Update yid with resampled SLA array
        dumy = np.arange(len(dst))[~interpolated][dumy]

        #        #Shrink data if there are any gaps greater than 3 points (ie. no valid interpolation)
        #        if (gaplen > 3).any() :
        #            gapedges=gapedges[:,gaplen > 3] #Remove gaps smaller than 3 points
        #            left=gapedges[1,np.where(gapedges[1,:] >= dumy)[0][0]] if (gapedges[1,:] < dumy).any() else 0
        #            right=gapedges[0,np.where(gapedges[0,:] >= dumy)[0][0]] if (gapedges[0,:] >= dumy).any() else len(dumsla)-1
        #            dumsla=dumsla[left:right+1]

        #Get sla profile on both sides of the eddy
        dumsla_n = dumsla[dumy:] if northward else dumsla[dumy:0:-1]
        dumsla_s = dumsla[dumy:0:-1] if northward else dumsla[dumy:]
        ugeo_n = ugeo[dumy:] if northward else ugeo[dumy:0:-1]
        ugeo_s = ugeo[dumy:0:-1] if northward else ugeo[dumy:]
        #        dumsla_s = dumsla[dumy:0:-1]  #np.roll(cursla[::-1],dumy+1)
        nn = len(dumsla_n)
        ns = len(dumsla_s)

        iscyclone = dumsla[dumy] < 0

        #        #If not enough data on one side, take the opposite #
        #        if nn < 3 :
        #            dumsla_n = dumsla_s
        #            ugeo_n = ugeo_s
        #            nn=ns
        #        if ns < 3 :
        #            dumsla_s = dumsla_n
        #            ugeo_s = ugeo_n
        #            ns=nn

        #Detect local velocity maxima on both sides of eddy (we keep only the four first peaks)
        if (iscyclone
            ):  #cyclone : negative speeds to the north, positive to the south
            mx_s = np.where(maximum_filter1d(ugeo_s, 3) == ugeo_s)[0]
            mx_n = np.where(maximum_filter1d(-ugeo_n, 3) == -ugeo_n)[0]
        elif (
                not iscyclone
        ):  #anticyclone : positive speeds to the north, negative to the south
            mx_s = np.where(maximum_filter1d(-ugeo_s, 3) == -ugeo_s)[0]
            mx_n = np.where(maximum_filter1d(ugeo_n, 3) == ugeo_n)[0]
        else:
            raise Exception('This case is not possible')

        #We only retain peaks with a SLA difference over than 1 cm from SLA peak to avoid points near peak
        #Rq: This happens when peak is found at eddy center... This could possibly avoided?
        mx_s = mx_s[(mx_s != 0)
                    & (np.abs(dumsla_s[mx_s] - dumsla[dumy]) > 0.01)]
        mx_n = mx_n[(mx_n != 0)
                    & (np.abs(dumsla_n[mx_n] - dumsla[dumy]) > 0.01)]

        #Replace with data from the opposite side if no maxima are found
        if len(mx_n) == 0:
            dumsla_n = dumsla_s.copy()
            ugeo_n = ugeo_s.copy()
            nn = ns
            mx_n = mx_s

        if len(mx_s) == 0:
            dumsla_s = dumsla_n.copy()
            ugeo_s = ugeo_n.copy()
            ns = nn
            mx_s = mx_n

        mx_s = mx_s[0]  #Retain first peak only
        mx_n = mx_n[0]  #Retain first peak only

        #        north[j] = dumy - mx_n
        #        south[j] = mx_s

        amplitude[j] = np.abs(dumsla[dumy] -
                              np.mean([dumsla_n[mx_n], dumsla_s[mx_s]]))

        #Show detection
        #        plt.plot(dst,dumsla);plt.plot(dst[dumy],dumsla[dumy],'or');plt.plot(dst[dumy+mx_n],dumsla[dumy+mx_n],'og');plt.plot(dst[dumy-mx_s],dumsla[dumy-mx_s],'og');plt.show()

        #Fit a 2nd order polynomial on the 4 points surrounding the extrema
        if mx_s != ns - 1:  #if the peak is not the furthest point
            if np.abs(ugeo_s[mx_s - 1]) > np.abs(ugeo_s[mx_s + 1]):
                fit = np.polyfit(
                    dst[mx_s - 1:mx_s + 3 if mx_s + 3 <= ns else ns],
                    ugeo_s[mx_s - 1:mx_s + 3 if mx_s + 3 <= ns else ns], 2)
            else:
                fit = np.polyfit(dst[mx_s - 2 if mx_s >= 2 else 0:mx_s + 2],
                                 ugeo_s[mx_s - 2 if mx_s >= 2 else 0:mx_s + 2],
                                 2)
        else:
            fit = np.polyfit(dst[mx_s - 2 if mx_s >= 2 else 0:mx_s + 1],
                             ugeo_s[mx_s - 2 if mx_s >= 2 else 0:mx_s + 1], 2)
        radius_s = (-fit[1]) / (
            2 * fit[0])  #This is the minimum value of the 2nd order polynomial
        if (mx_s > 1) and (mx_s < ns - 1) and (mx_n > 1) and (mx_n < ns - 1):
            if (radius_s > dst[mx_s - 1]) & (radius_s < dst[mx_s + 1]):
                diameter[j] += radius_s
            else:
                diameter[j] += dst[mx_s]
        else:
            diameter[j] += dst[mx_s]

#        dtoto=np.arange(dst[mx_s-1],dst[mx_s+3 if mx_s+3 <= ns else ns])
#        toto=fit[2]+dtoto*fit[1]+(dtoto**2)*fit[0]
#        plt.plot(dst[mx_s-1:mx_s+3 if mx_s+3 <= ns else ns],ugeo_s[mx_s-1:mx_s+3 if mx_s+3 <= ns else ns]);plt.plot(dtoto,toto)

        if mx_n != nn - 1:
            if np.abs(ugeo_n[mx_n - 1]) > np.abs(ugeo_n[mx_n + 1]):
                fit = np.polyfit(
                    dst[mx_n - 1:mx_n + 3 if mx_n + 3 <= nn else nn],
                    ugeo_n[mx_n - 1:mx_n + 3 if mx_n + 3 <= nn else nn], 2)
            else:
                fit = np.polyfit(dst[mx_n - 2 if mx_n >= 2 else 0:mx_n + 2],
                                 ugeo_n[mx_n - 2 if mx_n >= 2 else 0:mx_n + 2],
                                 2)
        else:
            fit = np.polyfit(dst[mx_n - 2 if mx_n >= 2 else 0:mx_n + 1],
                             ugeo_n[mx_n - 2 if mx_n >= 2 else 0:mx_n + 1], 2)
        radius_n = (-fit[1]) / (
            2 * fit[0])  #This is the minimum value of the 2nd order polynomial

        if (mx_s > 1) and (mx_s < ns - 1) and (mx_n > 1) and (mx_n < ns - 1):
            if (radius_n > dst[mx_n - 1]) & (radius_n < dst[mx_n + 1]):
                diameter[j] += radius_n
            else:
                diameter[j] += dst[mx_n]
        else:
            diameter[j] += dst[mx_n]

#        diameter[j] += np.abs((-fit[1]) / (2 * fit[0]))

#        print diameter[j], \
#            calcul_distance(dumlat[dumy-mx_s],dumlon[dumy-mx_s],dumlat[dumy+mx_n],dumlon[dumy+mx_n]), \
#            np.abs(dst[dumy] - dst[dumy+mx_n]) + np.abs(dst[dumy] - dst[dumy-mx_s]) , \
#            np.abs(dst[mx_n]) + np.abs(dst[mx_s])
#         dumdiam=np.append(dumdiam,np.abs(dst[mx_n]) + np.abs(dst[mx_s])) if j > 0 else [np.abs(dst[mx_n]) + np.abs(dst[mx_s])]
#        dtoto=np.arange(dst[mx_n-1],dst[mx_n+3 if mx_n+3 <= nn else nn])
#        toto=fit[2]+dtoto*fit[1]+(dtoto**2)*fit[0]
#        plt.plot(dst[mx_n-1:mx_n+3 if mx_n+3 <= nn else nn],ugeo_n[mx_n-1:mx_n+3 if mx_n+3 <= nn else nn]);plt.plot(dtoto,toto);plt.show()

#Compute relative vorticity
#--> Linear fitting of speed against distance
#        print j
        curdst = np.append(-dst[mx_s:0:-1] * 1e3, dst[1:mx_n + 1] * 1e3)
        curugeo = np.append(ugeo_s[mx_s:0:-1], ugeo_n[1:mx_n + 1])
        relvort[j] = -np.polyfit(curdst, curugeo, 1)[0]
        #        if northward : relvort[j]*=-1.
        #        print relvort[j]
        #Fit a Rankine vortex profile

        #First center eddy on zero (remove self-advection)
        Vanom = np.mean([ugeo_s[mx_s], ugeo_n[mx_n]])
        #        V=np.max(np.abs([ugeo_s[mx_s],ugeo_n[mx_n]]-Vanom)) #estimated circulation
        V = ugeo_n[
            mx_n] - Vanom  #estimated  circulation (negative northward for cyclones, positive for anticyclones)
        R = (diameter[j] /
             2.0) if northward else -(diameter[j] / 2.0)  #estimated radius
        dx = np.median(deriv(dst))  #sampling

        #         print j, len(np.abs(ugeo-Vanom)[np.abs(dst - dst[dumy]) < np.abs(R)])
        rid = np.arange(ncur)[np.abs(dst - dst[dumy]) < np.abs(R)][np.argmin(
            np.abs(ugeo - Vanom)[np.abs(dst - dst[dumy]) < np.abs(R)])]
        r = (dst - dst[dumy])[rid]  #distance offset to debiased eddy

        pn = np.ceil(R / dx)  #Number of points to theorical peaks
        u1 = ugeo_s[:pn * 4][::-1]
        u2 = ugeo_n[1:pn * 4]
        d1 = dst[0:len(u1)]
        d2 = dst[1:len(u2) + 1]
        #        curdst2=np.append(-d1[::-1],d2)
        #        curugeo2=np.append(u1,u2)
        #        [Rout, Vout], flag  = optimize.leastsq(resid, [R,V], args=(dst-dst[dumy]-r,ugeo-Vanom)
        [Rout,
         Vout], flag = leastsq_bounds(resid, [R, V],
                                      [[0, 1.5 * R], [0, 2 * V]],
                                      args=(dst - dst[dumy] - r, ugeo - Vanom))
        #        if (iscyclone and northward) or (not iscyclone and not northward):
        #            [Rout, Vout], flag = leastsq_bounds( resid, [R,V], [[0,R],[2*V,0]], args=(dst-dst[dumy]-r,ugeo-Vanom)) #constrained lsq fit
        #        else :
        #            [Rout, Vout], flag = leastsq_bounds( resid, [R,V], [[0,R],[0,2*V]], args=(dst-dst[dumy]-r,ugeo-Vanom))

        rk_diameter[j] = Rout * 2.0
        rk_relvort[j] = Vout / (
            Rout * 1e3
        )  #if ( (Rout/R) < 1.5) else relvort[j] #This is now constrained whithin LS fitting
        if (northward): rk_relvort[j] *= -1.
        #        print rk_relvort[j], relvort[j]
        self_advect[j] = Vanom
        rid_input = nearest(lon, dumlon[np.arange(ncur)[rid]])
        if calcul_distance(lat[rid_input], lon[rid_input], dumlat[rid],
                           dumlon[rid]) < dx:
            rk_center[j] = rid_input
        else:
            rk_center[j] = rid
            print '[kernel.getScales()]WARNING:center has not been offsetted due to its distance to original location'


#         dumsla_n[mx_n]

#        try :
#             plt.subplot(2,1,1);plt.title('Eddy #{0} (x:{1} , t:{2})\nRV: rk={3}, lin={4}'.format(j,xid[j],yid[j],rk_relvort[j],relvort[j]))
#             plt.plot(dst-dst[dumy]-r,dumsla,'-ok',markersize=2);plt.plot(0,dumsla[np.where((dst-dst[dumy]-r) == 0)[0]],'ob');plt.plot(-r,dumsla[dumy],'or');plt.plot((dst-dst[dumy]-r)[dumy+mx_n],dumsla[dumy+mx_n],'og');plt.plot((dst-dst[dumy]-r)[dumy-mx_s],dumsla[dumy-mx_s],'og');plt.ylabel('SLA (m)')
#             dum=rankine_model(dst-dst[dumy]-r, Rout, Vout)
#             plt.subplot(2,1,2);plt.plot(dst-dst[dumy]-r,ugeo-Vanom,'-k');plt.plot(0,(ugeo-Vanom)[np.where((dst-dst[dumy]-r) == 0)[0]],'ob');plt.plot(-r,(ugeo-Vanom)[dumy],'or');plt.plot((dst-dst[dumy]-r)[dumy+mx_n],(ugeo-Vanom)[dumy+mx_n],'og');plt.plot((dst-dst[dumy]-r)[dumy-mx_s],(ugeo-Vanom)[dumy-mx_s],'og');plt.plot(dst-dst[dumy]-r,dum,'-b');plt.ylabel('Velocity anomaly(m.s-1)');plt.xlabel('Distance to offseted center (km)')
#             plt.show()
#        except :
#            pass

#        relvort[j] = np.median(np.append(np.abs(ugeo_n[1:mx_n+1])/(dst[1:mx_n+1]*1e3),np.abs(ugeo_s[1:mx_s+1])/(dst[1:mx_s+1]*1e3)))
#        if (dumsla[dumy] > dumsla[dumy-1]) | (dumsla[dumy] > dumsla[dumy+1]) : relvort[j] *= -1 #Inver sign if anticyclonic

    return diameter, relvort, amplitude, rk_relvort, rk_center, rk_diameter, self_advect
示例#8
0
    alti.reorder()  #2D reordering of the data

    track_list = [9]
    #    track_list = alti.track_list()

    #Loop over tracks
    #################
    for t in track_list:

        #Load variables and split by track number
        fg = alti.slice('track', t)
        lon = alti.lon[fg]
        lat = alti.lat[fg]
        dst = AT.calcul_distance(lat, lon)
        N = len(lon)
        dx = np.median(AT.deriv(dst))
        time = AT.grid_time(alti.date[:, fg])
        sla = alti.sla[:, fg]
        #        time = np.mean(time,axis=1)
        nt = len(time)
        dt = np.median(AT.deriv(time))

        #Loess filtering of SLA
        #        for i in np.arange(nt):
        #            sla[i,:]=AT.loess(sla[i,:], dst, 40.)

        #Run wavelet analysis
        #####################

        #WV analysis
        sa_spectrum, sa_lscales, wvsla, daughter = ke.runAnalysis(
示例#9
0
def get_spec(dx,Vin,verbose=False,m=6,gain=1.0,res_factor=10.,integration=False,periodogram=False,mother='morlet'):
    
    
    #Setup Wavelet Transform parameters
    ###################################
    
    if mother == 'morlet':
        scale2len = (4*np.pi) / (m + np.sqrt(2+m*m)) #"fourrier factor" (for Morlet)
        len2scale = 1/scale2len
    elif mother=='dog':
        len2scale = np.sqrt(m+0.5) / (2*np.pi)
        scale2len = (2*np.pi) / np.sqrt(m+0.5) #"fourrier factor"
    else :
        raise Exception('Wavelet function "{0}" is not defined - choose between "morlet" & "dog"')
    
    N=len(Vin)
    
    T = dx*N
    s0 = 2.0 * dx if mother == 'morlet' else (2*dx) * len2scale #smallest wavescale (devided by fourier wavelength)
    dj = res_factor * (dx/T) * len2scale #set scale interval (remember this is scaled by s0^(-1/2) ; no units!
    dj0 =  (dx/T) * len2scale
    J = np.fix((np.log((T*len2scale)/s0) / np.log(2.)) / dj).astype(int) #number of scales from s0 to T
    
    #Setup wavelet object
    exec('mother_obj=kernel.wavelet.{0}({1})'.format(mother,m))
        
    #Run transform
    wave, s, k, coi, daughter, fft, fftfreqs = kernel.wavelet.cwt(Vin, dx, dj, s0, J,mother_obj)
    
    Cd = mother_obj.cdelta
    p = 1. / k
    
    #Mask data
    ##########
    # 1) Out of confidence interval
    mask = np.repeat(coi,J+1).reshape((N,J+1)).transpose() <= np.repeat(p,N).reshape((J+1,N))
#    mask = np.ones(N,J+1)
    
    a = np.ma.array(np.real(wave),mask=mask)             #Real part of the transform
    b = np.ma.array(np.imag(wave),mask=mask)
    csquared = a**2.0 + b**2.0
    
    c = np.sqrt(csquared)
    
    if not periodogram : csquared = csquared.sum(axis=1) / (~mask).sum(axis=1)
    
    # integration of the spectrum
    # shift to have values centered on the intervals
    dk = deriv(k)
    k_ = interp1d(np.arange(J+1),k,np.arange(J)+0.5)  #Shift wavelengths by half the unit
    
    #Spectral integration
    if integration and not periodogram:
        esd = k_*0.0
        psd = k_*0.0
        dk = deriv(k)
        for i in np.arange(len(k_)):
            esd[i] = np.sum((csquared * (N/2.0))[(k > (k_[i]-dk[i])) & (k < (k_[i]+dk[i]))]) / 2.0
            psd[i] = np.sum(csquared[(k > (k_[i]-dk[i])) & (k < (k_[i]+dk[i]))]) / (2.0**2) #This is variance units integration
        fq=k_
    else :
        esd = csquared
        psd = esd.copy()  /2.
        fq=k.copy()
        
    psd = (psd / (dj*res_factor))
    
    #Get frequencies and period  
    p=1/fq
    
    return {'psd':psd,'esd':esd,'fq':fq,'p':p,'gain':gain}
示例#10
0
def geost_1d(*args,**kwargs) : #(lon,lat,nu): OR (dst,nu)
    """
    ;+
    ;
    ;   GEOST_1D : Compute geostrophic speeds from a sea level dataset <br />
    ;
    ;   Reference : Powell, B. S., et R. R. Leben (2004), An Optimal Filter for <br />
    ;   Geostrophic Mesoscale Currents from Along-Track Satellite Altimetry, <br />
    ;   Journal of Atmospheric and Oceanic Technology, 21(10), 1633-1642.
    ;
    ; @param lon {in}{optional}{type:NUMERIC} longitude in degrees
    ; @param lat {in}{optional}{type:NUMERIC} latitude in degrees
    ; @param dst {in}{optional}{type:NUMERIC} along-track distance.
    ; @param z {in}{required}{type:NUMERIC} sea level surface. Can either be absolute<br />
    ;          values (SSH) or relative values (SLA). This MUST be given in METERS.
    ; @keyword strict {in}{optional}{type:BOOLEAN} If True, compute gradient at mid-distance.
    ; @keyword pl04 {in}{optional}{type:BOOLEAN} If True, use the Powell & Leben 2004 method.
    ;          
    ; @returns Geostrophic velocity component, positive eastward
    ;
    ;
    ;
    ; @author Renaud DUSSURGET, LEGOS/CTOH
    ; @history Created Sep. 2009 from genweights.m (Brian Powell (c) 2004, <br />
    ;   University of Colorado, Boulder)<br />
    ;   Modified May 2010 to be compliant with 20Hz datasets (p & n can vary).<br />
    ;     Warining may also be issued for data with holes within the width of the<br />
    ;     window.<br />
    ;   Modified June 2010 to include filtering window width in KM instead of nb. of<br />
    ;     points (Equivalent btw. 1Hz and 20Hz data).<br />
    ;
    ; @uses CALCUL_DISTANCE, EXIST, GENWEIGTHS, SETINTERSECTION, SETUNION, <br />
    ;   OPTIMAL_SLOPE, GRAVITY, CORIOLIS, TRACK_ORIENT
    ;
    ; @example dummy1=geost_1D(lon,lat,sla,pl04=True,p=11,q=11) :<br />
    ;   Return along-track velocity anomalies using a 11km by 11km Powell & Leben 2004 filter window <br />
    ;          dummy2=geost_1D(dst,sla,strict=True) :<br />
    ;   Return along-track velocity anomalies computed at mid-distance <br />
    ;
    ;-
    """
    
    lon = args[0]
    lat = args[1]
    
    dst = args[2] if len(args) == 4 else calcul_distance(lat,lon) * 1e3 #distance in meters
    nu = args [3] if len(args) == 4 else args[2]
    
    isVector = len(np.shape(nu)) == 1 
    
    #Reshape nu if vector
    if isVector : nu=np.reshape(nu,(len(nu),1))
    
    nt = np.shape(nu)[1] if not isVector else 1
    sh = nu.shape
    nufilt=np.ma.array(np.empty(sh),mask=True,dtype=nu.dtype)
    
    pl04 = kwargs.pop('pl04',False)
    filter = kwargs.pop('filter', None)
    strict = kwargs.pop('strict',False)
    verbose = kwargs.pop('verbose',False)
    
    if filter is not None :
        for t in np.arange(nt) : 
            nufilt[:,t] =loess(nu[:,t],dst,filter*1e3)
        nu=nufilt
    
    if pl04 :
        ug = np.ma.array(np.empty(sh),mask=True,dtype=nu.dtype)
        for t in np.arange(nt) :
            ug[:,t] = powell_leben_filter_km(lon,lat,nu[:,t],verbose=verbose,**kwargs)
        if isVector : ug=ug.flatten()
        return ug
    
    #If strict option is set to True, compute gradients at mid-distance between points
    if strict :
        lon = (lon[1:] - lon[:-1])/2. + lon[0:-1]
        lat = (lat[1:] - lat[:-1])/2. + lat[0:-1]
    
    
    #Compute gravitational & coriolis forces
    if strict : sh = (sh[0]-1,sh[1])
    g = np.repeat(gravity(lat),nt).reshape(sh)
    f = np.repeat(coriolis(lat),nt).reshape(sh)
    
    #Compute SSH 1st derivative
#    dh = deriv(dst,nu) #(deriv is very bad...)
    
    
    dh = np.ma.array(np.empty(sh),mask=True,dtype=nu.dtype)
    for t in np.arange(nt) :
        dh[:,t] = (nu[1:,t] - nu[:-1,t])/(dst[1:] - dst[:-1]) if strict else deriv(dst,nu[:,t])
      
    #Compute geostrophy
#    print f
#    print g
#    print dh
    ug = - (g*dh) / (f)
  
    #Inverse sign of ug for descending tracks as Coriolis is oriented to the right
    #northward
    if (not track_orient(lon,lat)) : #descending tracks
        ug *=-1
    
    if isVector : ug=ug.flatten()
    
    return (lon,lat,ug) if strict else ug
示例#11
0
def uvgrid(*args, **kwargs):  #;lon, lat, time, sla, STRICT=True):

    lon = args[0]
    lat = args[1]

    if len(args) == 3:
        sla = args[2]
        time = np.arange(1)
    else:
        time = args[2]
        sla = args[3]

    strict = kwargs.get('strict', False)

    nx = len(lon)
    ny = len(lat)
    nt = len(time)

    sla = sla.reshape((nt, ny, nx))

    nxout = nx - 1 if strict else nx
    nyout = ny - 1 if strict else ny

    dx = np.median(deriv(lon))
    dy = np.median(deriv(lat))

    #Compute spatial distance gradients (convert to meters)
    xgrad = np.repeat(
        [calcul_distance(l, 0.0, l, dx) * 1e3 for l in np.float64(lat)],
        nx).reshape((ny, nx))
    ygrad = np.repeat(calcul_distance(0, 0, dy, 0) * 1e3, nx * ny).reshape(
        (ny, nx))  #meridional distance gradient is constant everywhere

    lonout = interp1d(np.arange(nx), lon,
                      np.arange(nxout) + 0.5) if strict else lon
    latout = interp1d(np.arange(ny), lat,
                      np.arange(nyout) + 0.5) if strict else lat

    glon, glat = np.meshgrid(lonout, latout)

    g = gravity(glat)
    f = coriolis(glat)

    #Init gradients
    dhx = np.ma.array(np.zeros((nt, nyout, nxout)), mask=True)
    dhx.data[:] = dhx.fill_value
    dhy = dhx.copy()
    dhdx = dhx.copy()
    dhdy = dhx.copy()
    u = dhx.copy()
    v = dhx.copy()

    #Loop over time
    for i in np.arange(nt):

        #2 points differenciation
        if strict:
            dhx[i, :, :] = np.diff(sla[i, :, :], axis=1)
            dhy[i, :, :] = np.diff(sla[i, :, :], axis=0)
        else:
            #3 points differenciation
            dhy[i, :, :], dhx[i, :, :] = np.gradient(sla[i, :, :])

        dhdx[i, :, :] = dhx[i, :, :] / xgrad
        dhdy[i, :, :] = dhy[i, :, :] / ygrad

        u[i, :, :] = -(g * dhdy[i, :, :]) / (f)  #m.s-1
        v[i, :, :] = (g * dhdx[i, :, :]) / (f)  #m.s-1

    u = np.squeeze(u)
    v = np.squeeze(v)

    return u, v