def test_order_latdim_null(self): # order_latdim should not reverse a north-south latitude dimension u = np.random.rand(12, 17, 73, 144) v = np.random.rand(12, 17, 73, 144) lat = np.arange(90, -92.5, -2.5) latr, ur, vr = order_latdim(lat, u, v, axis=2) assert_array_equal(lat, latr) assert_array_equal(u, ur) assert_array_equal(v, vr)
def test_order_latdim(self): # order_latdim should reverse a south-north latitude dimension u = np.random.rand(12, 17, 73, 144) v = np.random.rand(12, 17, 73, 144) lat = np.arange(-90, 92.5, 2.5) latr, ur, vr = order_latdim(lat, u, v, axis=2) assert_array_equal(lat[::-1], latr) assert_array_equal(u[:, :, ::-1], ur) assert_array_equal(v[:, :, ::-1], vr)
def test_order_latdim(self): """order_latdim() reverses south-to-north latitude dimension?""" u = np.random.rand(12, 17, 73, 144) v = np.random.rand(12, 17, 73, 144) lat = np.arange(-90, 92.5, 2.5) latr, ur, vr = order_latdim(lat, u, v, axis=2) errl = error(lat[::-1], latr) erru = error(u[:,:,::-1], ur) errv = error(v[:,:,::-1], vr) assert_almost_equal(errl, 0., places=7) assert_almost_equal(erru, 0., places=7) assert_almost_equal(errv, 0., places=7)
def readin(): ncu = (NetCDFFile('/home/scottyiu/Desktop/work/data/model/50yrs/seasonal/3D/uwind/uwind_sea_' + myjob + '_yseasmean.nc')) uwnd = ncu.variables['u'][:,myheight,:,:] #7 for model, 14 for era: 200hPa lons = ncu.variables['longitude'][:] lats = ncu.variables['latitude'][:] ncu.close() ncv = (NetCDFFile('/home/scottyiu/Desktop/work/data/model/50yrs/seasonal/3D/vwind/vwind_sea_' + myjob + '_yseasmean.nc')) vwnd = ncv.variables['v'][:,myheight,:,:] #7 for model, 14 for era: 200hPa ncv.close() uwnd, uwnd_info = prep_data(uwnd, 'tyx') vwnd, vwnd_info = prep_data(vwnd, 'tyx') lats, uwnd, vwnd = order_latdim(lats, uwnd, vwnd) return (ncu,uwnd,lons,lats,ncv,vwnd,uwnd_info,vwnd_info)
def test_order_latdim_null(self): """ order_latdim() does not modify north-to-south latitude dimension? """ u = np.random.rand(12, 17, 73, 144) v = np.random.rand(12, 17, 73, 144) lat = np.arange(90, -92.5, -2.5) latr, ur, vr = order_latdim(lat, u, v, axis=2) errl = error(lat, latr) erru = error(u, ur) errv = error(v, vr) assert_almost_equal(errl, 0., places=7) assert_almost_equal(erru, 0., places=7) assert_almost_equal(errv, 0., places=7)
def mass_stream_func(uu, vv, lat, lvl, Global=True): ''' Name: MASS_STREAM_FUNC Purpose: An IDL procedure to compute the zonal-mean meridional stream function Inputs: uu : 3-D array of zonal winds [nlvl, nlat, nlon] vv : 3-D array of meridional winds [nlvl, nlat, nlon] lat : A 1- or 2-D array of latitude values (degrees) [nlat] lvl : A 1- or 2-D array of pressure levels (Pa) [nlvl] Outputs: psi : The meridional mass stream function (kg s**-1) p : Pressures for the stream function (Pa) Keywords: Global : Sets if computing for global or for a zonal subset using method of Zhang and Wang (2013) Author and history: Kyle R. Wodzicki ''' if (not Global) and (not VectorWind): raise Exception('Failed to import windspharm.standard.VectorWind!!!') elif (not Global): uu, uu_info = prep_data(uu, 'pyx') # Prepare data for VectorWind class vv, vv_info = prep_data(vv, 'pyx') # Prepare data for VectorWind class lat, uu, vv = order_latdim(lat, uu, vv) # Fix latitude order VW = VectorWind(uu, vv) # Initialize vector wind class uchi, vchi = VW.irrotationalcomponent() # Get irrotational components vv = recover_data( vchi, vv_info) # Convert v-irrot component back to input order vv = np.nanmean(vv, axis=2) # Average over longitude (last dimension) dims = vv.shape # Get dimensions of VV if (lat.ndim == 1): # If the latitude is only 1-D if (dims[0] == lat.size): vv = vv.transpose() dims = vv.shape lat = np.repeat(lat.reshape(1, dims[1]), dims[0], axis=0) # Reshape to match vv array lat = lat[:-1, :] if (lvl.ndim == 1): # If the level is only 1-D lvl = np.repeat(lvl.reshape(dims[0], 1), dims[1], axis=1) # Reshape to match vv array revFlat = False if (lvl[0, 0] > lvl[-1, 0]): # If pressure levels are decending revFlat = True lvl = lvl[::-1, :] # Reverse to ascending vv = vv[::-1, :] # Reverse vv too dp = lvl[1:, :] - lvl[:-1, :] # Compute change in pressure between levels dv = (vv[1:, :] + vv[:-1, :]) / 2.0 # Compute mean wind for level p = ((lvl[1:, 0] + lvl[:-1, 0]) / 2.0).flatten() # Reform mean pressure for level for output psi = 2.0 * np.pi * R_e * np.cos( np.radians(lat)) / g # Compute scalar for psi equation psi *= np.cumsum(dv * dp, axis=0) # Multiply scalar by the integeral of vv * dp return psi, p # Return stream function and pressure
ANALYSES """"""""""""""""""""""""""""""""""""""""""""""""""" #--------------- Calcul du potentiel de vitesses et de son gradient ----------------------- #--------- = partie divergente du champ = partie par laquelle se fait l export --------------- #--------------- MOYENNE ----------------------- #--- The standard interface requires that latitude and longitude be the leading ---- #--- dimensions of the input wind components, and that wind components must be ---- #--- either 2D or 3D arrays. The data read in is 3D and has latitude and ---- #--- longitude as the last dimensions. ---- #--- It is also required that the latitude dimension is north-to-south. Again the ---- #--- bundled tools make this easy. ---- lats_r, uwnd, vwnd = order_latdim(lats,UE_mean_pin,VE_mean_pin) #- Create a VectorWind instance to handle the computation of streamfunction and velocity potential- w = VectorWind(uwnd, vwnd) #--- fonction de courant (sf ; streamfunction) ---- #--- potentiel de vitesse (vp ; velocity potential) ---- sf, vp = w.sfvp() #--- partie divergente du champ = gradient du potentiel de vitesses ---- grad_vp = w.irrotationalcomponent() #--- on masque les continents parce que les valeurs sur les continents sont trop fortes ----
#--------------- Calcul du potentiel de vitesses et de son gradient ----------------------- #--------- = partie divergente du champ = partie par laquelle se fait l export --------------- #--------------- MOYENNE ----------------------- #--- The standard interface requires that latitude and longitude be the leading ---- #--- dimensions of the input wind components, and that wind components must be ---- #--- either 2D or 3D arrays. The data read in is 3D and has latitude and ---- #--- longitude as the last dimensions. ---- #--- It is also required that the latitude dimension is north-to-south. Again the ---- #--- bundled tools make this easy. ---- UE_mean_pin_o = np.mean(UE_mean_pin, axis=0) VE_mean_pin_o = np.mean(VE_mean_pin, axis=0) lats_r, uwnd, vwnd = order_latdim(lats, UE_mean_pin_o, VE_mean_pin_o) #- Create a VectorWind instance to handle the computation of streamfunction and velocity potential- w = VectorWind(uwnd, vwnd) #--- fonction de courant (sf ; streamfunction) ---- #--- potentiel de vitesse (vp ; velocity potential) ---- sf, vp = w.sfvp() #--- partie divergente du champ = gradient du potentiel de vitesses ---- grad_vp = w.irrotationalcomponent() #--- on masque les continents parce que les valeurs sur les continents sont trop fortes ----
print("Data uploaded for %d"%iyr) #print uwnd.shape #print uwnd[1,1,1] # The standard interface requires that latitude and longitude be the leading # dimensions of the input wind components, and that wind components must be # either 2D or 3D arrays. The data read in is 3D and has latitude and # longitude as the last dimensions. The bundled tools can make the process of # re-shaping the data a lot easier to manage. uwnd1, uwnd_info = prep_data(np.squeeze(uwnd[:,ilev,:,:]), 'tyx') vwnd1, vwnd_info = prep_data(np.squeeze(vwnd[:,ilev,:,:]), 'tyx') # It is also required that the latitude dimension is north-to-south. Again the # bundled tools make this easy. lats, uwnd1, vwnd1 = order_latdim(lats, uwnd1, vwnd1) # Create a VectorWind instance to handle the computation of streamfunction and # velocity potential. w = VectorWind(uwnd1, vwnd1) # Compute the streamfunction and velocity potential. Also use the bundled # tools to re-shape the outputs to the 4D shape of the wind components as they # were read off files. sf, vp = w.sfvp() sf = recover_data(sf, uwnd_info) vp = recover_data(vp, uwnd_info) #print sf.shape #print sf[1,1,1] print("Streamfunction done")
F0 = F[i, :] U0 = scipy.sparse.linalg.spsolve(A, F0) U[i, :] = U0 test = np.fft.ifft(U) from windspharm.standard import VectorWind from windspharm.tools import prep_data, recover_data, order_latdim uwnd, uwnd_info = prep_data(u_n[4:-4, 4:-4], 'xyp') vwnd, vwnd_info = prep_data(v_n[4:-4, 4:-4], 'xyp') lats, uwnd, vwnd = order_latdim(phi, uwnd, vwnd) w = VectorWind(uwnd, vwnd) sf, vp = w.sfvp() sf = recover_data(sf, uwnd_info) vp = recover_data(vp, vwnd_info) uchi, vchi, upsi, vpsi = w.helmholtz() uchi = recover_data(uchi, uwnd_info) vchi = recover_data(vchi, uwnd_info) upsi = recover_data(upsi, uwnd_info) vpsi = recover_data(vpsi, uwnd_info) s = w.s #convert vort + div from A-grid model to u,v using Spharm vrt, vrt_info = prep_data(vort_n[4:-4, 4:-4], 'xyp') div, div_info = prep_data(div_n[4:-4, 4:-4], 'xyp')
varvm_neg = np.nanmean(varv_neg, axis=0) hitum_pos = np.nanmean(hitu_pos, axis=0) hitum_neg = np.nanmean(hitu_neg, axis=0) hitvm_pos = np.nanmean(hitv_pos, axis=0) hitvm_neg = np.nanmean(hitv_neg, axis=0) ### Prepare data for calculating uwnd_pos, uwndinfo_pos = prep_data(varum_pos, 'tyx') vwnd_pos, vwndinfo_pos = prep_data(varvm_pos, 'tyx') uwnd_neg, uwndinfo_neg = prep_data(varum_neg, 'tyx') vwnd_neg, vwndinfo_neg = prep_data(varvm_neg, 'tyx') latn, uwnd_pos, vwnd_pos = order_latdim(lat, uwnd_pos, vwnd_pos) latn, uwnd_neg, vwnd_neg = order_latdim(lat, uwnd_neg, vwnd_neg) hituwnd_pos, hituwndinfo_pos = prep_data(hitum_pos, 'tyx') hitvwnd_pos, hitvwndinfo_pos = prep_data(hitvm_pos, 'tyx') hituwnd_neg, hituwndinfo_neg = prep_data(hitum_neg, 'tyx') hitvwnd_neg, hitvwndinfo_neg = prep_data(hitvm_neg, 'tyx') latn, hituwnd_pos, hitvwnd_pos = order_latdim(lat, hituwnd_pos, hitvwnd_pos) latn, hituwnd_neg, hitvwnd_neg = order_latdim(lat, hituwnd_neg, hitvwnd_neg) ### Change lat/lon to mesh lon2n, lat2n = np.meshgrid(lon, latn) ### Calculate VelocityWind object
def calc_quantity(uwnd, vwnd, quantity, lat_axis, lon_axis, axis_order): """Calculate a single wind quantity. Args: uwnd (numpy.ndarray): Zonal wind vwnd (numpy.ndarray): Meridional wind quantity (str): Quantity to be calculated lat_axis (list): Latitude axis values lon_axis (list): Longitude axis values axis_order (str): e.g. tyx Design: windsparm requires the input data to be on a global grid (due to the spherical harmonic representation used), latitude and longitude to be the leading axes and the latitude axis must go from 90 to -90. The cdms2 interface is supposed to adjust for these things but I've found that things come back upsidedown if the lat axis isn't right, so I've just used the standard interface here instead. Reference: ajdawson.github.io/windspharm """ check_global(lat_axis, lon_axis) # Make latitude and longitude the leading coordinates uwnd, uwnd_info = prep_data(numpy.array(uwnd), axis_order) vwnd, vwnd_info = prep_data(numpy.array(vwnd), axis_order) # Make sure latitude dimension is north-to-south lats, uwnd, vwnd = order_latdim(lat_axis, uwnd, vwnd) flip_lat = False if lats[0] == lat_axis[0] else True w = VectorWind(uwnd, vwnd) data_out = {} if quantity == 'rossbywavesource': eta = w.absolutevorticity() div = w.divergence() uchi, vchi = w.irrotationalcomponent() etax, etay = w.gradient(eta) data_out['rws1'] = (-eta * div) / (1.e-11) data_out['rws2'] = (-(uchi * etax + vchi * etay)) / (1.e-11) data_out['rws'] = data_out['rws1'] + data_out['rws2'] elif quantity == 'magnitude': data_out['spd'] = w.magnitude() elif quantity == 'vorticity': data_out['vrt'] = w.vorticity() elif quantity == 'divergence': div = w.divergence() data_out['div'] = div / (1.e-6) elif quantity == 'absolutevorticity': avrt = w.absolutevorticity() data_out['avrt'] = avrt / (1.e-5) elif quantity == 'absolutevorticitygradient': avrt = w.absolutevorticity() ugrad, vgrad = w.gradient(avrt) avrtgrad = numpy.sqrt(numpy.square(ugrad) + numpy.square(vgrad)) data_out['avrtgrad'] = avrtgrad / (1.e-5) elif quantity == 'planetaryvorticity': data_out['pvrt'] = w.planetaryvorticity() elif quantity == 'irrotationalcomponent': data_out['uchi'], data_out['vchi'] = w.irrotationalcomponent() elif quantity == 'nondivergentcomponent': data_out['upsi'], data_out['vpsi'] = w.nondivergentcomponent() elif quantity == 'streamfunction': sf = w.streamfunction() data_out['sf'] = sf / (1.e+6) elif quantity == 'velocitypotential': vp = w.velocitypotential() data_out['vp'] = vp / (1.e+6) else: sys.exit('Wind quantity not recognised') # Return data to its original shape for key in data_out.keys(): data_out[key] = recover_structure(data_out[key], flip_lat, uwnd_info) return data_out
ncu.close() ncv = Dataset(example_data_path("vwnd_mean.nc"), "r") vwnd = ncv.variables["vwnd"][:] ncv.close() # The standard interface requires that latitude and longitude be the leading # dimensions of the input wind components, and that wind components must be # either 2D or 3D arrays. The data read in is 3D and has latitude and # longitude as the last dimensions. The bundled tools can make the process of # re-shaping the data a lot easier to manage. uwnd, uwnd_info = prep_data(uwnd, "tyx") vwnd, vwnd_info = prep_data(vwnd, "tyx") # It is also required that the latitude dimension is north-to-south. Again the # bundled tools make this easy. lats, uwnd, vwnd = order_latdim(lats, uwnd, vwnd) # Create a VectorWind instance to handle the computations. w = VectorWind(uwnd, vwnd) # Compute components of rossby wave source: absolute vorticity, divergence, # irrotational (divergent) wind components, gradients of absolute vorticity. eta = w.absolutevorticity() div = w.divergence() uchi, vchi = w.irrotationalcomponent() etax, etay = w.gradient(eta) # Combine the components to form the Rossby wave source term. Re-shape the # Rossby wave source array to the 4D shape of the wind components as they were # read off files. S = -eta * div - (uchi * etax + vchi * etay)
ncu.close() ncv = Dataset(example_data_path('vwnd_mean.nc'), 'r') vwnd = ncv.variables['vwnd'][:] ncv.close() # The standard interface requires that latitude and longitude be the leading # dimensions of the input wind components, and that wind components must be # either 2D or 3D arrays. The data read in is 3D and has latitude and # longitude as the last dimensions. The bundled tools can make the process of # re-shaping the data a lot easier to manage. uwnd, uwnd_info = prep_data(uwnd, 'tyx') vwnd, vwnd_info = prep_data(vwnd, 'tyx') # It is also required that the latitude dimension is north-to-south. Again the # bundled tools make this easy. lats, uwnd, vwnd = order_latdim(lats, uwnd, vwnd) # Create a VectorWind instance to handle the computation of streamfunction and # velocity potential. w = VectorWind(uwnd, vwnd) # Compute the streamfunction and velocity potential. Also use the bundled # tools to re-shape the outputs to the 4D shape of the wind components as they # were read off files. sf, vp = w.sfvp() sf = recover_data(sf, uwnd_info) vp = recover_data(vp, uwnd_info) # Pick out the field for December and add a cyclic point (the cyclic point is # for plotting purposes). sf_dec, lons_c = add_cyclic_point(sf[11], lons)
def compute_rws(ds_u, ds_v, lat_coord='lat', lon_coord='lon', time_coord='time'): """ Computation of absolute vorticity, divergence, and Rossby wave source. Outputs xarray datasets of each. Args: ds_u (xarray data array): Zonal (u) wind (m/s). ds_v (xarray data array): Meridional (v) wind (m/s). lat_coord (str): Latitude coordinate. Defaults to ``lat``. lon_coord (str): Longitude coordinate. Defaults to ``lon``. time_coord (str): Time coordinate. Defaults to ``time``. Returns: Xarray datasets for absolute vorticity, divergence, and Rossby wave source. """ from windspharm.standard import VectorWind from windspharm.tools import prep_data, recover_data, order_latdim # grab lat and lon coords lats = ds_u.coords[lat_coord].values lons = ds_u.coords[lon_coord].values time = ds_u.coords[time_coord].values _, wnd_info = prep_data(ds_u.values, 'tyx') # reorder dims into lat, lon, time uwnd = ds_u.transpose(lat_coord, lon_coord, time_coord).values vwnd = ds_v.transpose(lat_coord, lon_coord, time_coord).values # reorder lats to north-south direction lats, uwnd, vwnd = order_latdim(lats, uwnd, vwnd) # initialize wind vector instance w = VectorWind(uwnd, vwnd) # Absolute vorticity (sum of relative and planetary vorticity). eta = w.absolutevorticity() # Horizontal divergence. div = w.divergence() # Irrotational (divergent) component of the vector wind. uchi, vchi = w.irrotationalcomponent() # Computes the vector gradient of a scalar field on the sphere. etax, etay = w.gradient(eta) # Compute rossby wave source S = -eta * div - (uchi * etax + vchi * etay) # recover data shape S = recover_data(S, wnd_info) div = recover_data(div, wnd_info) eta = recover_data(eta, wnd_info) # assemble xarray datasets data_rws = xr.Dataset({ 'rws': (['time', 'lat', 'lon'], S), }, coords={ 'time': (['time'], time), 'lat': (['lat'], lats), 'lon': (['lon'], lons) }, attrs={'long_name': 'Rossby wave source'}) data_div = xr.Dataset( { 'div': (['time', 'lat', 'lon'], div), }, coords={ 'time': (['time'], time), 'lat': (['lat'], lats), 'lon': (['lon'], lons) }, attrs={'long_name': 'Horizontal divergence (300-mb)'}) data_eta = xr.Dataset( { 'eta': (['time', 'lat', 'lon'], eta), }, coords={ 'time': (['time'], time), 'lat': (['lat'], lats), 'lon': (['lon'], lons) }, attrs={ 'long_name': 'Absolute vorticity (sum of relative and planetary vorticity)' }) return data_eta, data_div, data_rws