def __init__(self, var, maxvalue=0., fillvalue=0., shoreline=None): if var.getLongitude() is None: var.getAxis(1).designateLongitude() if var.getLatitude() is None: var.getAxis(1).designateLatitude() if var.getGrid() is None: var.setGrid(create_grid(var.getLongitude(), var.getLatitude())) self._bathy = var self._xres, self._yres = resol(self.get_grid()) _GriddedBathyMasked_.__init__(self, shoreline=shoreline, fillvalue=fillvalue, maxvalue=maxvalue) self._lon2d, self._lat2d = meshgrid(self.get_lon(), self.get_lat()) # self._lon2dp,self._lat2dp = meshbounds(self.get_lon(), self.get_lat()) self._xxs = self._yys = None
import pylab as P # Création de bathymétries fictives à partir de Smith and Sandwell import cdms2 from vacumm.config import data_sample cdms2.axis.longitude_aliases.append('x') cdms2.axis.latitude_aliases.append('y') f = cdms2.open(data_sample('ETOPO2v2g_flt.grd')) # - large var_large = f('z', lon=(-7, -1), lat=(46, 49)) # - petite var_small = f('z', lon=(-4.5, -.5), lat=(44.5, 46.5)) f.close() # - regrillage de la large vers une grille moins fine from vacumm.misc.grid import regridding, resol, create_grid xr, yr = resol(var_large.getGrid()) grid_large = create_grid((-7., -1, xr * 4.5), (46., 49, yr * 4.5)) var_large = regridding.regrid2d(var_large, grid_large) # On ajoute un traît de côte pour le masquage from vacumm.bathy.bathy import GriddedBathy, GriddedBathyMerger bathy_large = GriddedBathy(var_large, shoreline='i') bathy_small = var_small # Création de la grille finale de résolution intermédiaire final_grid = create_grid((-6., .5, xr * 2.5), (45, 47., yr * 2.5)) # On crée maintenant le merger merger = GriddedBathyMerger(final_grid) # - ajout de la bathy basse resolution en premier (en dessous) merger += bathy_large
def get_spec(var1, var2=None, dx=None, dy=None, verbose=False, fft=False, **kwargs): """Get the spectrum of a 2D variable :Return: specvar,nbwave,dk """ # Get the resolution in meters kwresol = kwfilter(kwargs, 'resol_') if None in [dx, dy]: if not cdms2.isVariable(var1): raise TypeError('var1 must be a MV2 array to compute dx and dy') kwresol.setdefault('proj', True) ldx, ldy = resol(var1, **kwresol) dx = dx or ldx dy = dy or ldy if N.ma.isMA(var1): var1= var1.filled(0.) if N.ma.isMA(var2): var2 = var2.filled(0.) # Part 1 - estimate of the wavenumbers [kx,ky,kkx,kky,kk,Lx,Ly] = get_kxky(var1, dx, dy, verbose=verbose) if verbose: print "dx = %s, fy = %s " %(dx,dy) print "kx = ",kx[0:3] print "ky = ",ky[0:3] print "kkx[0:3,2] = ",kkx[0:3,2] print "kky[0:3,1] = ",kky[0:3,1] print "kk[0:3,3] = ",kk[0:3,3] print "shape",kx.shape,ky.shape,kkx.shape,kky.shape,kk.shape # Part 2 - estimate of the spectrum # - fast fourier transform if fft: hat_phi1=N.fft.fft2(var1) hat_phi1=hat_phi1*hat_phi1.conj() hat_phi1=hat_phi1.real.copy() # useless else: hat_phi1 = var1 if var2 is not None: if fft: hat_phi2=N.fft.fft2(var2) hat_phi2=hat_phi2*hat_phi2.conj() hat_phi2=hat_phi2.real.copy() # useless else: hat_phi2 = var2 hat_spec = hat_phi1 + hat_phi2 else: hat_spec = hat_phi1 # - integration of the spectrum # shift to have values centered on the intervals dk = kx[1] - kx[0] dk_half = dk/2 # half of the interval k_= kx[0:min(var1.shape[1],var1.shape[0])/2] + dk specvar = k_*0 for i in range(len(k_)): # get indexes that satisfy two conditions # integration over a spectral width specvar[i] = ( hat_spec[ (kk<=k_[i]+dk_half) & (kk>k_[i]-dk_half) ] ).sum() # Normalisation (Danioux 2011) specvar /= (var1.shape[1]*var1.shape[0])**2 * dk # Dimensionalization to be able to compare with the litterature nbwave = k_*1000.0/2.0/N.pi # from rad/m to km/m dk *= 1000.0/2.0/N.pi specvar *= 2.0*N.pi/1000.0 if verbose: if var2 is not None: print "\n Normalized co-spectrum : \n",specvar else: print "\n Normalized spectrum : \n",specvar return specvar,nbwave,dk
def energy_spectrum(var, dx=None, dy=None, ctime=None, dispfig=False, latmean=None, verbose=False): """Compute the energy spectrum of a 2D variable""" # Guess dx and/or dy if None in [dx, dy]: if not cdms2.isVariable(var): raise TypeError('var must be a MV2 array to compute dx and dy') kwresol.setdefault('proj', True) ldx, ldy = resol(var, **kwresol) dx = dx or ldx dy = dy or ldy if latmean is None: if not cdms2.isVariable(var): raise Exception('You must provide explicitly latmean') latmean = var.getLatitude().getValue().mean() # Numpy arrays sshbox = var.filled(0.) if N.ma.isMA(var) else var ##################################################### # estimate of the spatial resolution and the latitude ##################################################### grav = 9.81 #latmean = int(float(latmean)) #dx = int(grid[0])*np.cos(np.pi*latmean/180.) f0 = 2*N.pi/(24.*3600.)*2.0*N.sin(N.pi*latmean/180.) gof0 = grav/f0 if verbose: print "the spatial resolution of the grid is constant \n dx = %s m, dy = %s m" %(dx,dy) print "the averaged latitude is %s degrees\n" %(latmean) ############################################### # 1ST PART ANALYZE FROM THE SEA SURFACE HEIGHT # -------------------------------------------- ############################################### # zonal average and its removing from ssh # mean on i (we erase 1 dimension) # and duplication along i (depends on sshbox.mean(1).shape) # then we need to transpose to have constant value along i and variations along j #revoir sshbox = sshbox - N.tile( sshbox.mean(1),(sshbox.shape[1],1) ).T # plot of ssh (box domain) #if options.dispfig: plot.contour_xy(sshbox,sshbox.shape[0],sshbox.shape[1],'ssh_box_minus_iaverage') # estimate of the rms to further check sshbox_rms = N.sqrt( (sshbox**2).mean() ) if verbose: print "rms of the ssh over the region of interest (from physical field) : %s \n" %sshbox_rms ################################ # create a double periodic field ################################ ssh2per = N.tile( sshbox, (2,2) ) ssh2per[ssh2per.shape[0]/2:ssh2per.shape[0],0:ssh2per.shape[1]/2] = sshbox[::-1,::] ssh2per[::,ssh2per.shape[1]/2:] = N.fliplr(ssh2per[::,0:ssh2per.shape[1]/2]) #if options.dispfig: plot.contour_xy(ssh2per,ssh2per.shape[0],ssh2per.shape[1],'ssh_double_periodic') del sshbox # estimate of the rms to further check ssh2per_rms = N.sqrt( (ssh2per**2).mean() ) if verbose: print "rms of the double periodic ssh over the region of interest (from physical field) : %s \n" %ssh2per_rms ################################ # wavenumber spectrum of the ssh (double periodic field) ################################ # estimate of the spectrum ssh2per_spec, ssh2per_k, dk = get_spec(ssh2per, dx=dx, dy=dy, fft='x2k', verbose=verbose) # sshbox in physical space # make sure the FFT is correct : we must have the same rms either from physics or from wavenumbers ssh2per_rmsk = N.sqrt( (ssh2per_spec*dk).sum() ) if verbose: print "rms of the ssh over the region of interest (from wave number fields) : %s \n" %ssh2per_rmsk # figure if dispfig: plot_loglog_kspec(ssh2per_spec, ssh2per_k, savefig='ssh2per_spec', title='SPECTRUM OF SSH (double periodic)', subtitle=str(ctime), xlabel='Wavenumber (cycles/km)', ylabel='SSH [m^2/(cycle/km)]', slope=-5) ########################################### # the ssh pectrum after doubling the domain # is much better than the previous one ########################################### #################################################### # 2ND PART ANALYZIS FROM THE GEOSTROPHIC VELOCITIES # ------------------------------------------------- #################################################### ########################################### # estimate of the geostrophic velocities (from the spectrum of the periodic field of ssh) ########################################### # estimate of the wavenumbers kx,ky,kkx,kky,kk,Lx,Ly = get_kxky(ssh2per, dx, dy, verbose=verbose) # estimate of the velocities from the spectrum of the ssh ussh = -gof0*N.fft.ifft2( (kky*N.fft.fft2(ssh2per))*N.complex(0,1) ).real vssh = gof0*N.fft.ifft2( (kkx*N.fft.fft2(ssh2per))*N.complex(0,1) ).real #if options.dispfig: plot.contour_xy(ussh,ussh.shape[0],ussh.shape[1],'ussh (from double periodic field spectral method) ') #if options.dispfig: plot.contour_xy(vssh,vssh.shape[0],vssh.shape[1],'vssh (from double periodic field and spectral method) ') ssh2per_shape = ssh2per.shape del ssh2per ####################################################### # wavenumber co-spectrum of the geostrophic velocities (eke) ####################################################### # estimate of the co-spectrum uv2per_cospec,eke_k,dk = get_cospec(ussh, vssh, dx=dx, dy=dy, verbose=verbose, fft=True) # estimate of the eke to further check uv2per_rmsk = N.sqrt( ((uv2per_cospec*dk)/2.).sum() ) if verbose: print "eke over the region of interest (from physical field) : %s \n" %uv2per_rmsk # make sure the FFT is correct : we must have the same rms either from physics or from wavenumbers #ssh2per_rmsk = N.sqrt( (ssh2per_spec*dk).mean() ) #if verbose: print "eke over the region of interest (from physical field) : %s \n" %sshbox_rms #if verbose: print "rms of the ssh over the region of interest (from wave number fields) : %s \n" %ssh2per_rmsk #if verbose: print "rms difference (wavenumber - physics) : %s \n" %(ssh2per_rmsk-ssh2per_rms) # figure if dispfig: plot_loglog_kspec(uv2per_cospec, eke_k, savefig='eke2per_spec', title='SPECTRUM OF EKE', subtitle=str(ctime), xlabel='Wavenumber (cycles/km)', ylabel='EKE [(m/s)^2/(cycle/km)]') #################################################### # 3RD PART ESTIMATE OF THE FLUXES OF ENERGY # ------------------------------------------------- #################################################### ########################################### # estimate of the production of eke ########################################### # geostrophic velocities in the spectral space are non zero in the bottom-left corner ug = ussh.copy() ; del ussh ug[ssh2per_shape[0]/2:ssh2per_shape[0],::] = 0. ug[::,ssh2per_shape[1]/2:] = 0. vg = vssh.copy() ; del vssh vg[ssh2per_shape[0]/2:ssh2per_shape[0],::] = 0. vg[::,ssh2per_shape[1]/2:] = 0. #if options.dispfig: plot.contour_xy(ug,ug.shape[0],ug.shape[1],'ug (from the spectrum of the periodic ssh)') #if options.dispfig: plot.contour_xy(vg,vg.shape[0],vg.shape[1],'vg (from the spectrum of the periodic ssh)') u = N.fft.fft2(ug) v = N.fft.fft2(vg) ugx = N.fft.ifft2( (u*kkx)*N.complex(0,1) ).real ugy = N.fft.ifft2( (u*kky)*1j ).real vgx = N.fft.ifft2( (v*kkx)*1j ).real vgy = N.fft.ifft2( (v*kky)*1j ).real term_u = N.fft.fft2(ug*ugx + vg*ugy) term_v = N.fft.fft2(ug*vgx + vg*vgy) eke_prod = - ( u.conj()*term_u + v.conj()*term_v ).real eke_prod_phys1=N.fft.ifft2(eke_prod).real #if options.dispfig: plot.contour_xy(eke_prod_phys1,eke_prod_phys1.shape[0],eke_prod_phys1.shape[1],'eke_prod_phys1') term_u = 1j*kkx*N.fft.fft2(ug*ug) + 1j*kky*N.fft.fft2(vg*ug) term_v = 1j*kkx*N.fft.fft2(ug*vg) + 1j*kky*N.fft.fft2(vg*vg) eke_prod = - ( u.conj()*term_u + v.conj()*term_v ).real eke_prod_phys2=N.fft.ifft2(eke_prod).real #if options.dispfig: plot.contour_xy(eke_prod_phys2,eke_prod_phys2.shape[0],eke_prod_phys2.shape[1],'eke_prod_phys2') #if options.dispfig: plot.contour_xy(eke_prod_phys1-eke_prod_phys2,eke_prod_phys2.shape[0],eke_prod_phys2.shape[1],'diff_eke_prod') phi = eke_prod_phys1-eke_prod_phys2 # estimate of the total energy flux of the momentum equation gg_spec, gg_k, dk = get_spec(eke_prod, dx=dx, dy=dy, verbose=verbose, fft=False) # phi in Fourier space # choose kmax1 such that it corresponds to gg_k(kmax1) < 1/(3*dx)*1000 [km/m] (2dx Shanon + take into account diffusion) kmax1 = min( N.where(gg_k>= 1/(3.0*dx)*1000.)[0][0] - 1 ,gg_spec.shape[0]) if verbose: print "Shanon criterium kmax1 = %s, gg_k(kmax1) = %s, gg_k(kmax1+1) = %s, 1/(3.0*dx)*1000. = %s" %(kmax1,gg_k[kmax1],gg_k[kmax1+1],1/(3.0*dx)*1000.) # integration from large scales to small ones (shift one large scales) tpi = N.array( [sum(gg_spec[ i:kmax1 ]) for i in range(kmax1)] ) tpi[0]=0. # figure if dispfig: plot_semilogx_kspec(tpi, gg_k[:kmax1], savefig='ssh_spec', title='TOTAL ENERGY FLUX', subtitle=str(ctime), xlabel='Wavenumber (cycles/km)', ylabel='Sum of EKE from small scales to k [(m/s)^2/(cycle/km)]') if verbose: print "The end !" del grav,f0,gof0,sshbox_rms,ssh2per_rms,dk,kx,ky,kkx,kky,kk,Lx,Ly,uv2per_rmsk,ug,vg,u,v,term_u,term_v,ugx,ugy,vgx,vgy,eke_prod,eke_prod_phys1,eke_prod_phys2,phi,gg_spec gc.collect() return ssh2per_spec, ssh2per_k, uv2per_cospec, eke_k, tpi, gg_k[:kmax1]
y = xyz.y z = xyz.z # %% Extensions # - en tenant compte des zones de selection et exclusion print 'Limites:', xyz.xmin, xyz.xmax, xyz.ymin, xyz.ymax # - donnees brutes print 'X min brut:', xyz.get_xmin(mask=False), xyz.get_x(mask=False).min() # %% Mean resolution print 'Resolution in degrees:', xyz.resol(deg=True) print 'Resolution in meters:', xyz.resol() # %% Automatic grid grid_auto = xyz.grid print 'Resolution of auto grid:', resol(grid_auto) # %% Interpolation on auto grid print 'Interpolation:' gridded_auto = xyz.togrid() # equivalent a : # >>> gridded_auto = xyz.togrid(xyz.grid) # %% Interpolation on manual grid print 'Interpolation and masking, then extraction' # - defintion grid_manual = create_grid((-5.3, -4.91, .01), (48.1, 48.41, .01)) # - interpolation gridded_manual = xyz.togrid(grid_manual, mask='h') # - extraction with margin xyz_up = xyz.clip(zone=(None, None, None, 48.3), margin=2)
y = xyz.y z = xyz.z # Extensions # - en tenant compte des zones de selection et exclusion print 'Limites :', xyz.xmin, xyz.xmax, xyz.ymin, xyz.ymax # - donnees brutes print 'X min brut :', xyz.get_xmin(mask=False), xyz.get_x(mask=False).min() # Resolution moyenne print 'Resolution geographique :', xyz.resol(deg=True) print 'Resolution metrique :', xyz.resol() # Definition auto d'une grille reguliere grid_auto = xyz.grid print 'Resolution grille auto :', resol(grid_auto) # Interpolation sur grille auto print 'Interpolation auto' gridded_auto = xyz.togrid() # equivalent a : # >>> gridded_auto = xyz.togrid(xyz.grid) # Interpolation sur grille manuelle print 'Interpolation et masquage manuels puis extraction' # - defintion de la grille grid_manual = create_grid((-5.3, -4.91, .01), (48.1, 48.41, .01)) # - interpolation gridded_manual = xyz.togrid(grid_manual, mask='h') # Extraction d'une sous-zone (xmin,ymin...) avec marge xyz_up = xyz.clip(zone=(None, None, None, 48.3), margin=2)
lonn, latn = get_xy(gg, num=True) grid = create_grid(*gg) print 'Dimensions : nx=%i ny=%i' % grid.shape[::-1] print 'Axes : lon="%s" lat="%s" (%iD)' % (lon.id, lat.id, lonn.ndim) # Extension print 'Zonal extent : %s -> %s [%s -> %s]' % ( lonn.min(), lonn.max(), lonlab( lonn.min(), decimal=False), lonlab(lonn.max(), decimal=False)) print 'Meridional extent : %s -> %s [%s -> %s]' % ( latn.min(), latn.max(), latlab( latn.min(), decimal=False), latlab(latn.max(), decimal=False)) # Resolution lonres, latres = resol(gg, proj=False) xres, yres = resol(gg, proj=True) xres /= 1000. yres /= 1000. print 'Zonal resolution : %g° / %gkm' % (lonres, xres) print 'Meridional resolution: %g° / %gkm' % (latres, yres) # Plot if options.plot or options.out: xmin, ymin, xmax, ymax = scalebox(grid, 1 / options.zoom) for att in 'xmin', 'xmax', 'ymin', 'ymax': if getattr(options, att) is not None: exec att + " = %s" % getattr(options, att) if options.figsize is not None: try:
if grid is None: sys.exit('Variable "%s" has no grid'%options.vname) else: # loop on all variables for vname in f.listvariables(): grid = f[vname].getGrid() if grid is not None: break else: sys.exit('No variable with a grid found') grid = (grid.getLongitude().clone(), grid.getLatitude().clone()) # VACUMM path here = os.path.dirname(__file__) for rpath in [os.path.join(here, '../lib/python')]: path = os.path.abspath(rpath) sys.path.append(path) # Resolution try: from vacumm.misc.grid import resol except: sys.exit('Error when loading vacumm') xres, yres = resol(grid, proj=options.meters) if options.meters: units = 'km' xres /= 1000. yres /= 1000. else: units = '°' print 'dx=%(xres)g%(units)s, dy=%(yres)g%(units)s'%locals() f.close()
# Dimension gg = (lon, lat) lonn, latn = get_xy(gg, num=True) grid = create_grid(*gg) print 'Dimensions : nx=%i ny=%i'%grid.shape[::-1] print 'Axes : lon="%s" lat="%s" (%iD)'%(lon.id, lat.id, lonn.ndim) # Extension print 'Zonal extent : %s -> %s [%s -> %s]'%( lonn.min(), lonn.max(), lonlab(lonn.min(), decimal=False), lonlab(lonn.max(), decimal=False)) print 'Meridional extent : %s -> %s [%s -> %s]'%( latn.min(), latn.max(), latlab(latn.min(), decimal=False), latlab(latn.max(), decimal=False)) # Resolution lonres, latres = resol(gg, proj=False) xres, yres = resol(gg, proj=True) xres /= 1000. yres /= 1000. print 'Zonal resolution : %g° / %gkm'%(lonres, xres) print 'Meridional resolution: %g° / %gkm'%(latres, yres) # Plot if options.plot or options.out: xmin, ymin, xmax, ymax = scalebox(grid, 1/options.zoom) for att in 'xmin', 'xmax', 'ymin', 'ymax': if getattr(options, att) is not None: exec att+" = %s"%getattr(options, att) if options.figsize is not None: try: options.figsize = eval(options.figsize)
# -*- coding: utf8 -*- # Création de bathymétries fictives à partir de Smith and Sandwell import cdms2 from vacumm.config import data_sample cdms2.axis.longitude_aliases.append('x') cdms2.axis.latitude_aliases.append('y') f = cdms2.open(data_sample('ETOPO2v2g_flt.grd')) # - large var_large = f('z', lon=(-7, -1), lat=(46, 49)) # - petite var_small = f('z', lon=(-4.5, -.5), lat=(44.5, 46.5)) f.close() # - regrillage de la large vers une grille moins fine from vacumm.misc.grid import regridding, resol, create_grid xr, yr = resol(var_large.getGrid()) grid_large = create_grid((-7., -1, xr*4.5), (46., 49, yr*4.5)) var_large = regridding.regrid2d(var_large, grid_large) # On ajoute un traît de côte pour le masquage from vacumm.bathy.bathy import GriddedBathy, GriddedBathyMerger bathy_large = GriddedBathy(var_large, shoreline='i') bathy_small = var_small # Création de la grille finale de résolution intermédiaire final_grid = create_grid((-6., .5, xr*2.5), (45, 47., yr*2.5)) # On crée maintenant le merger merger = GriddedBathyMerger(final_grid) # - ajout de la bathy basse resolution en premier (en dessous) merger += bathy_large # - puis ajout de celle haute résolution
def barotropic_geostrophic_velocity(ssh, dxy=None, gravity=default_gravity, cyclic=False, format_axes=True, getu=True, getv=True, filter=None): """Get barotropic geostropic velocity from SSH on a C-grid .. note:: ssh is supposed to be at T points, ubt is computed at V points, and vbt is computed at U points. .. todo:: Rewrite it using :mod:`vacumm.data.misc.arakawa` and defining a limited number of algorithms for different staggering configurations. :Params: - **ssh**: Sea surface height. - **dxy**, optional: Horizontal resolutions (m). Resolution along X and Y are respectively at U and V points. Possible forms: - ``res``: A scalar meaning a constant resolution along X and Y. - ``(dx,dy)``: A tuple of resolutions along X and Y. - ``None``: Resolution is estimated using :func:`~vacumm.misc.grid.misc.resol`. :Return: ``(ubt,vbt)`` """ if not getu and not getv: return # Init masked if getu: ugbt = format_var(ssh * MV2.masked, 'ugbt', format_axes=False) if getv: vgbt = format_var(ssh * MV2.masked, 'vgbt', format_axes=False) # Grid tgrid = ssh.getGrid() if getu: ugrid = shiftgrid(tgrid, ishift=0.5) if getv: vgrid = shiftgrid(tgrid, jshift=0.5) if format_axes: if getv: format_grid(ugrid, 'u') if getu: format_grid(vgrid, 'v') if getu: set_grid(ugbt, vgrid) if getv: set_grid(vgbt, ugrid) # Resolutions if dxy is None: dxt, dyt = resol(ssh, proj=True, mode='local') dxu = 0.5 * (dxt[:, 1:] + dxt[:, :-1]) del dxt dyv = 0.5 * (dyt[1:, :] + dyt[:-1, :]) del dyt elif not isinstance(dxy, (list, tuple)): dxu = dyv = dxy else: dxu, dyv = dxy if getv and isinstance(dxu, N.ndarray): if cdms2.isVariable(dxu): dxu = dxu.asma() if dxu.ndim == 1: dxu.shape = 1, -1 if dxu.shape[1] == ssh.shape[-1]: dxu = dxu[:, :-1] if getu and isinstance(dyv, N.ndarray): if cdms2.isVariable(dyv): dyv = dyv.asma() if dyv.ndim == 1: dyv.shape = -1, 1 if dyv.shape[0] == ssh.shape[-2]: dyv = dyv[:-1] # Get geostrophic factor f0 = coriolis_parameter(ssh, gravity=gravity, fromvar=True).asma() bad = f0 == 0. f0[bad] = 1. f0[bad] = N.ma.masked del bad gf = gravity / f0 del f0 # Computes sshm = ssh.asma() sshm = sshm * gf del gf if getu: ugbt[..., :-1, :] = -N.ma.diff(sshm, axis=-2) / dyv del dyv if getv: vgbt[..., :-1] = N.ma.diff(sshm, axis=-1) / dxu del dxu del sshm if getu and cyclic: ugbt[..., -1] = ugbt[..., 0] if not getu: return vgbt elif not getv: return ugbt return ugbt, vgbt
def barotropic_geostrophic_velocity(ssh, dxy=None, gravity=default_gravity, cyclic=False, format_axes=True, getu=True, getv=True, filter=None): """Get barotropic geostropic velocity from SSH on a C-grid .. note:: ssh is supposed to be at T points, ubt is computed at V points, and vbt is computed at U points. .. todo:: Rewrite it using :mod:`vacumm.data.misc.arakawa` and defining a limited number of algorithms for different staggering configurations. :Params: - **ssh**: Sea surface height. - **dxy**, optional: Horizontal resolutions (m). Resolution along X and Y are respectively at U and V points. Possible forms: - ``res``: A scalar meaning a constant resolution along X and Y. - ``(dx,dy)``: A tuple of resolutions along X and Y. - ``None``: Resolution is estimated using :func:`~vacumm.misc.grid.misc.resol`. :Return: ``(ubt,vbt)`` """ if not getu and not getv: return # Init masked if getu: ugbt = format_var(ssh*MV2.masked, 'ugbt', format_axes=False) if getv: vgbt = format_var(ssh*MV2.masked, 'vgbt', format_axes=False) # Grid tgrid = ssh.getGrid() if getu: ugrid = shiftgrid(tgrid, ishift=0.5) if getv: vgrid = shiftgrid(tgrid, jshift=0.5) if format_axes: if getv: format_grid(ugrid, 'u') if getu: format_grid(vgrid, 'v') if getu: set_grid(ugbt, vgrid) if getv: set_grid(vgbt, ugrid) # Resolutions if dxy is None: dxt, dyt = resol(ssh, proj=True, mode='local') dxu = 0.5*(dxt[:, 1:]+dxt[:, :-1]) ; del dxt dyv = 0.5*(dyt[1:, :]+dyt[:-1, :]) ; del dyt elif not isinstance(dxy, (list, tuple)): dxu = dyv = dxy else: dxu, dyv = dxy if getv and isinstance(dxu, N.ndarray): if cdms2.isVariable(dxu): dxu = dxu.asma() if dxu.ndim==1: dxu.shape = 1, -1 if dxu.shape[1]==ssh.shape[-1]: dxu = dxu[:, :-1] if getu and isinstance(dyv, N.ndarray): if cdms2.isVariable(dyv): dyv = dyv.asma() if dyv.ndim==1: dyv.shape = -1, 1 if dyv.shape[0]==ssh.shape[-2]: dyv = dyv[:-1] # Get geostrophic factor f0 = coriolis_parameter(ssh, gravity=gravity, fromvar=True).asma() bad = f0==0. f0[bad] = 1. f0[bad] = N.ma.masked ; del bad gf = gravity/f0 ; del f0 # Computes sshm = ssh.asma() sshm = sshm*gf ; del gf if getu: ugbt[..., :-1, :] = -N.ma.diff(sshm, axis=-2)/dyv ; del dyv if getv: vgbt[..., :-1] = N.ma.diff(sshm, axis=-1)/dxu ; del dxu del sshm if getu and cyclic: ugbt[..., -1] = ugbt[..., 0] if not getu: return vgbt elif not getv: return ugbt return ugbt, vgbt