def regrid_sphere(nlat,nlon,Nens,X): """ Truncate lat,lon grid to another resolution in spherical harmonic space. Triangular truncation Inputs: nlat : number of latitudes nlon : number of longitudes Nens : number of ensemble members X : data array of shape (nlat*nlon,Nens) ntrunc : triangular truncation (e.g., use 42 for T42) Outputs : lat_new : 2D latitude array on the new grid (nlat_new,nlon_new) lon_new : 2D longitude array on the new grid (nlat_new,nlon_new) X_new : truncated data array of shape (nlat_new*nlon_new, Nens) """ # Originator: Greg Hakim # University of Washington # May 2015 # create the spectral object on the original grid specob_lmr = Spharmt(nlon,nlat,gridtype='regular',legfunc='computed') # truncate to a lower resolution grid (triangular truncation) # ifix = np.remainder(ntrunc,2.0).astype(int) # nlat_new = ntrunc + ifix # nlon_new = int(nlat_new*1.5) ntrunc = 42 nlat_new = 64 nlon_new = 128 # create the spectral object on the new grid specob_new = Spharmt(nlon_new,nlat_new,gridtype='regular',legfunc='computed') # create new lat,lon grid arrays dlat = 90./((nlat_new-1)/2.) dlon = 360./nlon_new veclat = np.arange(-90.,90.+dlat,dlat) veclon = np.arange(0.,360.,dlon) blank = np.zeros([nlat_new,nlon_new]) lat_new = (veclat + blank.T).T lon_new = (veclon + blank) # transform each ensemble member, one at a time X_new = np.zeros([nlat_new*nlon_new,Nens]) for k in range(Nens): X_lalo = np.reshape(X[:,k],(nlat,nlon)) Xbtrunc = regrid(specob_lmr, specob_new, X_lalo, ntrunc=nlat_new-1, smooth=None) vectmp = Xbtrunc.flatten() X_new[:,k] = vectmp return X_new,lat_new,lon_new
def regrid_field(field, lat, lon, lat_new, lon_new): nlat_old, nlon_old = np.size(lat), np.size(lon) nlat_new, nlon_new = np.size(lat_new), np.size(lon_new) spec_old = Spharmt(nlon_old, nlat_old, gridtype='regular', legfunc='computed') spec_new = Spharmt(nlon_new, nlat_new, gridtype='regular', legfunc='computed') #remove nans field[np.isnan(field)] = 0 field_new = [] for field_old in field: regridded_field = regrid(spec_old, spec_new, field_old, ntrunc=None, smooth=None) field_new.append(regridded_field) field_new = np.array(field_new) return field_new
def regrid(self, ntrunc, inplace=False): old_spec = Spharmt(self.nlon, self.nlat, gridtype='regular', legfunc='computed') ifix = ntrunc % 2 new_nlat = ntrunc + ifix new_nlon = int(new_nlat * 1.5) new_spec = Spharmt(new_nlon, new_nlat, gridtype='regular', legfunc='computed') include_poles = False if new_nlat % 2 == 0 else True new_lat_2d, new_lon_2d, _, _ = generate_latlon( new_nlat, new_nlon, include_endpts=include_poles) new_lat = new_lat_2d[:, 0] new_lon = new_lon_2d[0, :] # new_value = [] # for old_value in self.value: old_value = np.moveaxis(self.value, 0, -1) regridded_value = regrid(old_spec, new_spec, old_value, ntrunc=new_nlat - 1, smooth=None) new_value = np.moveaxis(regridded_value, -1, 0) # new_value.append(regridded_value) new_value = np.array(new_value) if inplace: self.value = new_value self.lat = new_lat self.lon = new_lon self.nlat = np.size(new_lat) self.nlon = np.size(new_lon) self.ntrunc = ntrunc else: new_field = self.copy() new_field.value = new_value new_field.lat = new_lat new_field.lon = new_lon new_field.nlat = np.size(new_lat) new_field.nlon = np.size(new_lon) new_field.ntrunc = ntrunc return new_field
def __init__(self, lat, lon, rsphere=6.3712e6, legfunc='stored', trunc=None): # Length of lat/lon arrays self.nlat = len(lat) self.nlon = len(lon) if self.nlat % 2: gridtype = 'gaussian' else: gridtype = 'regular' self.s = Spharmt(self.nlon, self.nlat, gridtype=gridtype, rsphere=rsphere, legfunc=legfunc) # Reverse latitude array if necessary # self.ReverseLat = False # if lat[0] < lat[-1]: # lat = self._reverse_lat(lat) # self.ReverseLat = True # lat/lon in degrees self.glat = lat self.glon = lon # lat/lon in radians self.rlat = np.deg2rad(lat) self.rlon = np.deg2rad(lon) self.rlons, self.rlats = np.meshgrid(self.rlon, self.rlat) # Constants # Earth's angular velocity self.omega = 7.292e-05 # unit: s-1 # Gravitational acceleration self.g = 9.8 # unit: m2/s # Misc self.dtype = np.float32
def __init__(self, nlon, nlat, truncation, radius=6371200.): """ Initialize the spectral transforms engine. Arguments: * nlon: int Number of longitudes in the transform grid. * nlat: int Number of latitudes in the transform grid. * truncation: int The spectral truncation (triangular). This is the maximum number of spherical harmonic modes retained in the discrete truncation. More modes means higher resolution. """ self.sh = Spharmt(nlon, nlat, gridtype='regular', rsphere=radius) self.radius = radius self.nlon = nlon self.nlat = nlat self.truncation = truncation
date, date) nc = Dataset(fcstfile) if ntime is None: times = nc['time'][:].tolist() levels = nc['plev'][:].tolist() ntime = times.index(fhour) nlev = levels.index(level) lons = nc['longitude'][:] lats = nc['latitude'][:] nlons = len(lons) nlats = len(lats) re = 6.3712e6 ntrunc = nlats - 1 spec = Spharmt(nlons, nlats, rsphere=re, gridtype='regular', legfunc='computed') indxm, indxn = getspecindx(ntrunc) degree = indxn.astype(np.float) if int(nc['time'][ntime]) != fhour: raise ValueError('incorrect forecast time') fcst_data1 = nc[varnc][ntime, nlev, ...] nc.close() if fhour > 9: fcstfile = '%s/%s/fv3longcontrol2_historyp_%s_latlon.nc' % (datapath2, date, date) else: fcstfile = '%s/%s/fv3control2_historyp_%s_latlon.nc' % (datapath2, date, date) nc = Dataset(fcstfile)
def __init__(self, u, v, gridtype='regular', rsphere=6.3712e6): """Initialize a VectorWind instance. **Arguments:** *u*, *v* Zonal and meridional wind components respectively. Their types should be either `numpy.ndarray` or `numpy.ma.MaskedArray`. *u* and *v* must have matching shapes and contain no missing values. *u* and *v* may be 2 or 3-dimensional with shape (nlat, nlon) or (nlat, nlon, nt), where nlat and nlon are the number of latitudes and longitudes respectively and nt is the number of fields. The latitude dimension must be oriented north-to-south. The longitude dimension should be oriented west-to-east. **Optional arguments:** *gridtype* Type of the input grid, either 'regular' for evenly-spaced grids, or 'gaussian' for Gaussian grids. Defaults to 'regular'. *rsphere* The radius in metres of the sphere used in the spherical harmonic computations. Default is 6371200 m, the approximate mean spherical Earth radius. **See also:** `~windspharm.tools.prep_data`, `~windspharm.tools.recover_data`, `~windspharm.tools.get_recovery`, `~windspharm.tools.reverse_latdim`, `~windspharm.tools.order_latdim`. **Examples:** Initialize a `VectorWind` instance with zonal and meridional components of the vector wind on the default regular (evenly-spaced) grid: from windspharm.standard import VectorWind w = VectorWind(u, v) Initialize a `VectorWind` instance with zonal and meridional components of the vector wind specified on a Gaussian grid: from windspharm.standard import VectorWind w = VectorWind(u, v, gridtype='gaussian') """ # For both the input components check if there are missing values by # attempting to fill missing values with NaN and detect them. If the # inputs are not masked arrays then take copies and check for NaN. try: self.u = u.filled(fill_value=np.nan) except AttributeError: self.u = u.copy() try: self.v = v.filled(fill_value=np.nan) except AttributeError: self.v = v.copy() if np.isnan(self.u).any() or np.isnan(self.v).any(): raise ValueError('u and v cannot contain missing values') # Make sure the shapes of the two components match. if u.shape != v.shape: raise ValueError('u and v must be the same shape') if len(u.shape) not in (2, 3): raise ValueError('u and v must be rank 2 or 3 arrays') nlat = u.shape[0] nlon = u.shape[1] try: # Create a Spharmt object to do the computations. self.gridtype = gridtype.lower() self.s = Spharmt(nlon, nlat, gridtype=self.gridtype, rsphere=rsphere) except ValueError: if self.gridtype not in ('regular', 'gaussian'): err = 'invalid grid type: {0:s}'.format(repr(gridtype)) else: err = 'invalid input dimensions' raise ValueError(err) # Method aliases. self.rotationalcomponent = self.nondivergentcomponent self.divergentcomponent = self.irrotationalcomponent
# set model parameters. nlons = 128 # number of longitudes ntrunc = 42 # spectral truncation (for alias-free computations) nlats = (nlons / 2) + 1 # for regular grid. gridtype = 'regular' dt = 900 # time step in seconds tdiab = 12. * 86400 # thermal relaxation time scale tdrag = 4. * 86400. # lower layer drag efold = 4 * dt # hyperdiffusion time scale rsphere = 6.37122e6 # earth radius jetexp = 2 umax = 40 moistfact = 0.1 # create spherical harmonic instance. sp = Spharmt(nlons, nlats, rsphere=rsphere, gridtype=gridtype) # create model instance. model =\ TwoLevel(sp,dt,ntrunc,efold=efold,tdiab=tdiab,tdrag=tdrag,jetexp=jetexp,umax=umax,moistfact=moistfact) # initial state is equilbrium jet + random noise. vg = np.zeros((sp.nlat, sp.nlon, 2), np.float32) ug = model.uref vrtspec, divspec = sp.getvrtdivspec(ug, vg, model.ntrunc) psispec = np.zeros(vrtspec.shape, vrtspec.dtype) psispec.real += npran.normal(scale=1.e4, size=(psispec.shape)) psispec.imag += npran.normal(scale=1.e4, size=(psispec.shape)) vrtspec = vrtspec + model.lap[:, np.newaxis] * psispec thetaspec = model.nlbalance(vrtspec) divspec = np.zeros(thetaspec.shape, thetaspec.dtype)
def __init__(self, H, W): super(PowerSpectrum, self).__init__() self.spharm = Spharmt(W, H, legfunc='stored') self.spectrums = [] self.needs_sh = True
def main(): # non-linear barotropically unstable shallow water test case # of Galewsky et al (2004, Tellus, 56A, 429-440). # "An initial-value problem for testing numerical models of the global # shallow-water equations" DOI: 10.1111/j.1600-0870.2004.00071.x # http://www-vortex.mcs.st-and.ac.uk/~rks/reprints/galewsky_etal_tellus_2004.pdf # requires matplotlib for plotting. # grid, time step info nlons = 256 # number of longitudes ntrunc = int(nlons/3) # spectral truncation (for alias-free computations) nlats = int(nlons/2) # for gaussian grid. dt = 150 # time step in seconds itmax = 6*int(86400/dt) # integration length in days # parameters for test rsphere = 6.37122e6 # earth radius omega = 7.292e-5 # rotation rate grav = 9.80616 # gravity hbar = 10.e3 # resting depth umax = 80. # jet speed phi0 = np.pi/7.; phi1 = 0.5*np.pi - phi0; phi2 = 0.25*np.pi en = np.exp(-4.0/(phi1-phi0)**2) alpha = 1./3.; beta = 1./15. hamp = 120. # amplitude of height perturbation to zonal jet efold = 3.*3600. # efolding timescale at ntrunc for hyperdiffusion ndiss = 8 # order for hyperdiffusion # setup up spherical harmonic instance, set lats/lons of grid x = Spharmt(nlons,nlats,ntrunc,rsphere,gridtype='gaussian') lons,lats = np.meshgrid(x.lons,x.lats) f = 2.*omega*np.sin(lats) # coriolis # zonal jet. vg = np.zeros((nlats,nlons),np.float) u1 = (umax/en)*np.exp(1./((x.lats-phi0)*(x.lats-phi1))) ug = np.zeros((nlats),np.float) ug = np.where(np.logical_and(x.lats < phi1, x.lats > phi0), u1, ug) ug.shape = (nlats,1) ug = ug*np.ones((nlats,nlons),dtype=np.float) # broadcast to shape (nlats,nlonss) # height perturbation. hbump = hamp*np.cos(lats)*np.exp(-((lons-np.pi)/alpha)**2)*np.exp(-(phi2-lats)**2/beta) # initial vorticity, divergence in spectral space vrtspec, divspec = x.getvrtdivspec(ug,vg) vrtg = x.spectogrd(vrtspec) divg = x.spectogrd(divspec) # create hyperdiffusion factor hyperdiff_fact = np.exp((-dt/efold)*(x.lap/x.lap[-1])**(ndiss/2)) # solve nonlinear balance eqn to get initial zonal geopotential, # add localized bump (not balanced). vrtg = x.spectogrd(vrtspec) tmpg1 = ug*(vrtg+f); tmpg2 = vg*(vrtg+f) tmpspec1, tmpspec2 = x.getvrtdivspec(tmpg1,tmpg2) tmpspec2 = x.grdtospec(0.5*(ug**2+vg**2)) phispec = x.invlap*tmpspec1 - tmpspec2 phig = grav*(hbar + hbump) + x.spectogrd(phispec) phispec = x.grdtospec(phig) # initialize spectral tendency arrays ddivdtspec = np.zeros(vrtspec.shape+(3,), np.complex) dvrtdtspec = np.zeros(vrtspec.shape+(3,), np.complex) dphidtspec = np.zeros(vrtspec.shape+(3,), np.complex) nnew = 0; nnow = 1; nold = 2 # time loop. time1 = time.time() for ncycle in range(itmax+1): t = ncycle*dt # get vort,u,v,phi on grid vrtg = x.spectogrd(vrtspec) ug,vg = x.getuv(vrtspec,divspec) phig = x.spectogrd(phispec) print('t=%6.2f hours: min/max %6.2f, %6.2f' % (t/3600.,vg.min(), vg.max())) # compute tendencies. tmpg1 = ug*(vrtg+f); tmpg2 = vg*(vrtg+f) ddivdtspec[:,nnew], dvrtdtspec[:,nnew] = x.getvrtdivspec(tmpg1,tmpg2) dvrtdtspec[:,nnew] *= -1 tmpg = x.spectogrd(ddivdtspec[:,nnew]) tmpg1 = ug*phig; tmpg2 = vg*phig tmpspec, dphidtspec[:,nnew] = x.getvrtdivspec(tmpg1,tmpg2) dphidtspec[:,nnew] *= -1 tmpspec = x.grdtospec(phig+0.5*(ug**2+vg**2)) ddivdtspec[:,nnew] += -x.lap*tmpspec # update vort,div,phiv with third-order adams-bashforth. # forward euler, then 2nd-order adams-bashforth time steps to start. if ncycle == 0: dvrtdtspec[:,nnow] = dvrtdtspec[:,nnew] dvrtdtspec[:,nold] = dvrtdtspec[:,nnew] ddivdtspec[:,nnow] = ddivdtspec[:,nnew] ddivdtspec[:,nold] = ddivdtspec[:,nnew] dphidtspec[:,nnow] = dphidtspec[:,nnew] dphidtspec[:,nold] = dphidtspec[:,nnew] elif ncycle == 1: dvrtdtspec[:,nold] = dvrtdtspec[:,nnew] ddivdtspec[:,nold] = ddivdtspec[:,nnew] dphidtspec[:,nold] = dphidtspec[:,nnew] vrtspec += dt*( \ (23./12.)*dvrtdtspec[:,nnew] - (16./12.)*dvrtdtspec[:,nnow]+ \ (5./12.)*dvrtdtspec[:,nold] ) divspec += dt*( \ (23./12.)*ddivdtspec[:,nnew] - (16./12.)*ddivdtspec[:,nnow]+ \ (5./12.)*ddivdtspec[:,nold] ) phispec += dt*( \ (23./12.)*dphidtspec[:,nnew] - (16./12.)*dphidtspec[:,nnow]+ \ (5./12.)*dphidtspec[:,nold] ) # implicit hyperdiffusion for vort and div. vrtspec *= hyperdiff_fact divspec *= hyperdiff_fact # switch indices, do next time step. nsav1 = nnew; nsav2 = nnow nnew = nold; nnow = nsav1; nold = nsav2 time2 = time.time() print('CPU time = ',time2-time1) # make a contour plot of potential vorticity in the Northern Hem. fig = plt.figure(figsize=(12,4)) # dimensionless PV pvg = (0.5*hbar*grav/omega)*(vrtg+f)/phig print('max/min PV',pvg.min(), pvg.max()) lons1d = (180./np.pi)*x.lons-180.; lats1d = (180./np.pi)*x.lats levs = np.arange(-0.2,1.801,0.1) cs=plt.contourf(lons1d,lats1d,pvg,levs,extend='both') cb=plt.colorbar(cs,orientation='horizontal') # add colorbar cb.set_label('potential vorticity') plt.grid() plt.xlabel('degrees longitude') plt.ylabel('degrees latitude') plt.xticks(np.arange(-180,181,60)) plt.yticks(np.arange(-5,81,20)) plt.axis('equal') plt.axis('tight') plt.ylim(0,lats1d[0]) plt.title('PV (T%s with hyperdiffusion, hour %6.2f)' % (ntrunc,t/3600.)) plt.savefig("output_swe.pdf") plt.show()
f = f - f.mean(axis=0) a = a - a.mean(axis=0) covfa = (f*a).mean(axis=0) varf = (f**2).mean(axis=0) vara = (a**2).mean(axis=0) return covfa/(np.sqrt(varf)*np.sqrt(vara)) def getmse(f,a): return ((f-a)**2).mean(axis=0) nlonsin = 800; nlatsin = 400 nlons = 360; nlats = 181 ntrunc = 20 latbound = 20. sin = Spharmt(nlonsin,nlatsin) sout = Spharmt(nlons,nlats) delta = 360./nlons lats = 90.-delta*np.arange(nlats) coslats = np.cos((np.pi/180.)*lats) coslats = coslats[:,np.newaxis]*np.ones((nlats,nlons)) latnh = lats.tolist().index(latbound) latsh = lats.tolist().index(-latbound) coslatsnh = coslats[0:latnh+1,:] coslatssh = coslats[latsh:,:] coslatstr = coslats[latnh:latsh+1,:] lons = delta*np.arange(nlons) lons, lats = np.meshgrid(lons,lats[::-1]) filename = varshort
import matplotlib.pyplot as plt import numpy as np # set up orthographic map projection. map = Basemap(projection='ortho', lat_0=30, lon_0=-60, resolution='l') # draw coastlines, country boundaries, fill continents. map.drawcoastlines() # draw the edge of the map projection region (the projection limb) map.drawmapboundary() # draw lat/lon grid lines every 30 degrees. map.drawmeridians(np.arange(0, 360, 30)) map.drawparallels(np.arange(-90, 90, 30)) min = int(raw_input('input degree (m) of legendre function to plot:')) nin = int(raw_input('input order (n) of legendre function to plot:')) nlons = 720 nlats = 361 x = Spharmt(nlons, nlats, legfunc='computed') ntrunc = nlats - 1 indxm, indxn = getspecindx(ntrunc) nm = -1 i = 0 for m, n in zip(indxm, indxn): if m == min and n == nin: nm = i exit else: i = i + 1 if nm < 0: raise ValueError( 'invalid m,n - must fit within triangular truncation at wavenumber ' + repr(ntrunc)) coeffs = np.zeros((ntrunc + 1) * (ntrunc + 2) / 2, np.complex)
# ERA smatch, ematch = find_date_indices(ERA20C_time,stime,etime) ERA20C = ERA20C - np.mean(ERA20C[smatch:ematch,:,:],axis=0) # ----------------------------------- # Regridding the data for comparisons # ----------------------------------- print('\n regridding data to a common T42 grid...\n') iplot_loc= False #iplot_loc= True # create instance of the spherical harmonics object for each grid specob_lmr = Spharmt(nlon,nlat,gridtype='regular',legfunc='computed') specob_tcr = Spharmt(nlon_TCR,nlat_TCR,gridtype='regular',legfunc='computed') specob_era20c = Spharmt(nlon_ERA20C,nlat_ERA20C,gridtype='regular',legfunc='computed') # truncate to a lower resolution grid (common:21, 42, 62, 63, 85, 106, 255, 382, 799) ntrunc_new = 42 # T42 ifix = np.remainder(ntrunc_new,2.0).astype(int) nlat_new = ntrunc_new + ifix nlon_new = int(nlat_new*1.5) # lat, lon grid in the truncated space dlat = 90./((nlat_new-1)/2.) dlon = 360./nlon_new veclat = np.arange(-90.,90.+dlat,dlat) veclon = np.arange(0.,360.,dlon) blank = np.zeros([nlat_new,nlon_new]) lat2_new = (veclat + blank.T).T