def test_coriolis_force(): """Test basic coriolis force calculation.""" lat = np.array([-90., -30., 0., 30., 90.]) * units.degrees cor = coriolis_parameter(lat) values = np.array([-1.4584232E-4, -.72921159E-4, 0, .72921159E-4, 1.4584232E-4]) * units('s^-1') assert_almost_equal(cor, values, 7)
def calcgw_gfs(v, lat, lon): height, lats, lons = v.data(lat1=lat - gw_gfs_margin_deg, lat2=lat + gw_gfs_margin_deg, lon1=lon - gw_gfs_margin_deg, lon2=lon + gw_gfs_margin_deg) i = np.searchsorted(lats[:, 0], lat) if abs(lats[i + 1, 0] - lat) < abs(lats[i, 0] - lat): i = i + 1 j = np.searchsorted(lons[0, :], lon) if abs(lons[0, i + 1] - lon) < abs(lons[0, i] - lon): j = j + 1 #print('level', v.level, 'height', height[i,j], lats[i,j], lons[i,j]) # Set up some constants based on our projection, including the Coriolis parameter and # grid spacing, converting lon/lat spacing to Cartesian f = mpcalc.coriolis_parameter(np.deg2rad(lats)).to('1/s') dx, dy = mpcalc.lat_lon_grid_deltas(lons, lats) res_km = (dx[i, j] + dy[i, j]).magnitude / 2000. # Smooth height data. Sigma=1.5 for gfs 0.5deg height = ndimage.gaussian_filter(height, sigma=1.5 * 50 / res_km, order=0) # In MetPy 0.5, geostrophic_wind() assumes the order of the dimensions is (X, Y), # so we need to transpose from the input data, which are ordered lat (y), lon (x). # Once we get the components,transpose again so they match our original data. geo_wind_u, geo_wind_v = mpcalc.geostrophic_wind(height * units.m, f, dx, dy) return height[i, j], geo_wind_u[i, j], geo_wind_v[i, j]
def calcgw_wrf(f, lat, lon, levels, tidx=0): # MFDataset removes the time dimension from XLAT, XLONG xlat = f.variables['XLAT'] xlslice = (0, ) * (len(xlat.shape) - 2) + (slice(None), slice(None)) xlat = xlat[xlslice] xlong = f.variables['XLONG'][xlslice] (iy, ix), area, (iby, ibx) = get_wrf_dims(f, lat, lon, xlat, xlong) areat = (tidx, ) + area areatz = (tidx, slice(None)) + area #print('wrf coords', lat, lon, xlat[iy,ix], xlong[iy,ix]) #print(xlat[area][iby,ibx], xlong[area][iby,ibx], areat) # load area hgt = (f.variables['PH'][areatz] + f.variables['PHB'][areatz]) / 9.81 hgtu = (hgt[:-1] + hgt[1:]) * .5 pres = f.variables['P'][areatz] + f.variables['PB'][areatz] terrain = f.variables['HGT'][areat] # find suitable pressure levels yminpres, xminpres = np.unravel_index(pres[0].argmin(), pres[0].shape) pres1 = pres[0, yminpres, xminpres] - 1. aglpt = hgtu[:, iby, ibx] - terrain[iby, ibx] pres0 = pres[np.searchsorted(aglpt, levels[-1]), iby, ibx] # plevels = np.arange(pres1, min(pres0, pres1)-1, -1000.) plevels = np.arange(pres1, min(pres0, pres1) - 1000, -1000.) # !!!! # interpolate wrf into pressure levels phgt = log_interpolate_1d(plevels, pres, hgtu, axis=0) # Set up some constants based on our projection, including the Coriolis parameter and # grid spacing, converting lon/lat spacing to Cartesian coriol = mpcalc.coriolis_parameter(np.deg2rad(xlat[area])).to('1/s') # lat_lon_grid_deltas doesn't work under py2, but for WRF grid it is still # not very accurate, better use direct values. #dx, dy = mpcalc.lat_lon_grid_deltas(xlong[area], xlat[area]) dx = f.DX * units.m dy = f.DY * units.m # Smooth height data. Sigma=1.5 for gfs 0.5deg res_km = f.DX / 1000. ug = np.zeros(plevels.shape, 'f8') vg = np.zeros(plevels.shape, 'f8') for i in range(len(plevels)): sh = ndimage.gaussian_filter(phgt[i, :, :], sigma=1.5 * 50 / res_km, order=0) # ugl, vgl = mpcalc.geostrophic_wind(sh * units.m, coriol, dx, dy) # bug1 ugl, vgl = mpcalc.geostrophic_wind(sh * units.m, dx, dy, np.deg2rad(xlat[area])) ug[i] = ugl[iby, ibx].magnitude vg[i] = vgl[iby, ibx].magnitude return phgt[:, iby, ibx], ug, vg
def test_coriolis_force(array_type): """Test basic coriolis force calculation.""" mask = [False, True, False, True, False] lat = array_type([-90., -30., 0., 30., 90.], 'degrees', mask=mask) cor = coriolis_parameter(lat) values = array_type( [-1.4584232E-4, -.72921159E-4, 0, .72921159E-4, 1.4584232E-4], 's^-1', mask=mask) assert_array_almost_equal(cor, values, 7)
def getParameters(self): self.lambda_z = (self.alt[-1] - self.alt[0]) * 2 self.m = 2 * np.pi / self.lambda_z #phi = eps[4] #orientation of ellipse print("PHIIII", self.phi) rot = np.array([[np.cos(self.phi), -np.sin(self.phi)], [np.sin(self.phi), np.cos(self.phi)]]) #print("ROTATION:", rot) #print("SIZE OF ROT:", rot.shape) uv = np.array([self.u, self.v]) uvrot = np.matmul(rot, uv) urot = uvrot[0, :] dT = np.diff(self.temp) #print("Diferential Temperature:", dT) dz = np.diff(self.alt) wf = (2 * self.a) / (2 * self.b) #long axis / short axis print("WFFFFFFFFFFFF", wf) bvMean = np.mean(self.bv2) coriolisFreq = mpcalc.coriolis_parameter(latitudeOfAnalysis) #print("Coriolis Parameter:", coriolisFreq) intrinsicFreq = coriolisFreq.magnitude * wf #need to assign units to output from ellipse fitting to ensure dimensional accuracy k_h = np.sqrt((coriolisFreq.magnitude**2 * self.m**2) / abs(bvMean) * (wf**2 - 1)) #horizontal wavenumber print("KHHHHHHHHHHHHHHHHHHHHHHHHH", k_h) intrinsicHorizPhaseSpeed = intrinsicFreq / k_h k_h_2 = np.sqrt((intrinsicFreq**2 - coriolisFreq.magnitude**2) * (self.m**2 / abs(bvMean))) int2 = intrinsicFreq / k_h_2 dTdz = dT / dz eta = np.mean(dTdz / urot[0:-1]) if eta < 0: self.phi -= np.pi self.altOfDetection = np.mean(self.alt) #print("m: {}, lz: {}, h: {}, bv{}".format(self.m, self.lambda_z, intrinsicHorizPhaseSpeed, bvMean)) #return altitude of detection, latitude, longitude, vertical wavelength,horizontal wavenumber, intrinsic horizontal phase speed, axial ratio l/s return [ self.altOfDetection, self.lat[0], self.long[0], self.lambda_z, k_h, intrinsicHorizPhaseSpeed, wf ]
def 500hPa_GFS_vorticity(lon_west, lon_east, lat_south, lat_north): LATEST_DATA.variables('Geopotential_height_isobaric', 'u-component_of_wind_isobaric', 'v-component_of_wind_isobaric').add_lonlat() LATEST_DATA.lonlat_box(lon_west, lon_east, lat_south, lat_north) LATEST_DATA.vertical_level(50000) DATA = NCSS_DATA.get_data(LATEST_DATA) DTIME = DATA.variables['Geopotential_height_isobaric'].dimensions[0] DLAT = DATA.variables['Geopotential_height_isobaric'].dimensions[2] DLON = DATA.variables['Geopotential_height_isobaric'].dimensions[3] LAT = DATA.variables[DLAT][:] LON = DATA.variables[DLON][:] TIMES = DATA.variables[DTIME] VTIMES = num2date(TIMES[:], TIMES.units) H500 = DATA.variables['Geopotential_height_isobaric'][0, 0, :, :] U500 = DATA.variables['u-component_of_wind_isobaric'][0, 0, :, :]*units('m/s') V500 = DATA.variables['v-component_of_wind_isobaric'][0, 0, :, :]*units('m/s') DTIME = DATA.variables['Geopotential_height_isobaric'].dimensions[:] f = mpcalc.coriolis_parameter(np.deg2rad(LAT)).to(units('1/sec')) DX, DY = mpcalc.lat_lon_grid_spacing(LON, LAT) VORT500 = mpcalc.vorticity(U500, V500, DX, DY, dim_order='YX') VORT500 = (VORT500*(units('1/s')))
def geostr_met(array_2d_geoheight, array_1d_lat, array_1d_lon) : ''' Calculate Geostrophic wind map (2d) from 2d array area. https://unidata.github.io/python-gallery/examples/Ageostrophic_Wind_Example.html Parameters ---------- array_2d_geoheight : read numpy array [m] array_1d_lat : read numpy array [deg] array_1d_lon : read numpy array [deg] Returns ------- array_2d : return interplated and extrapolated 2d array ''' import numpy as np import metpy.calc as mpcalc from metpy.units import units # Combine 1D latitude and longitudes into a 2D grid of locations lon_2d, lat_2d = np.meshgrid(array_1d_lon, array_1d_lat) # Set up some constants based on our projection, including the Coriolis parameter and # grid spacing, converting lon/lat spacing to Cartesian f = mpcalc.coriolis_parameter(np.deg2rad(lat_2d)).to('1/s') dx, dy = mpcalc.lat_lon_grid_deltas(lon_2d + 360, lat_2d) dx, dy = np.array(dx), np.array(dy) dy *= -1 # In MetPy 0.5, geostrophic_wind() assumes the order of the dimensions is (X, Y), # so we need to transpose from the input data, which are ordered lat (y), lon (x). # Once we get the components,transpose again so they match our original data. geo_wind_u, geo_wind_v = mpcalc.geostrophic_wind(array_2d_geoheight.data * units.m, f, dx, dy) return(geo_wind_u, geo_wind_v)
def test_coriolis_warning(): """Test that warning is raise when latitude larger than pi radians.""" with pytest.warns(UserWarning): coriolis_parameter(50) with pytest.warns(UserWarning): coriolis_parameter(-50)
# # Nearly all of the calculations in `metpy.calc` will accept DataArrays by converting them # into their corresponding unit arrays. While this may often work without any issues, we must # keep in mind that because the calculations are working with unit arrays and not DataArrays: # # - The calculations will return unit arrays rather than DataArrays # - Broadcasting must be taken care of outside of the calculation, as it would only recognize # dimensions by order, not name # # Also, some of the units used in CF conventions (such as 'degrees_north') are not recognized # by pint, so we must implement a workaround. # # As an example, we calculate geostropic wind at 500 hPa below: lat, lon = xr.broadcast(y, x) f = mpcalc.coriolis_parameter(lat.values * units.degrees) dx, dy = mpcalc.lat_lon_grid_deltas(lon.values, lat.values) heights = data['height'].loc[time[0]].loc[{vertical.name: 500.}] u_geo, v_geo = mpcalc.geostrophic_wind(heights, f, dx, dy, dim_order='yx') print(u_geo) print(v_geo) ######################################################################### # Plotting # -------- # # Like most meteorological data, we want to be able to plot these data. DataArrays can be used # like normal numpy arrays in plotting code, or we can use some of xarray's plotting # functionality. # # (More detail beyond the following can be found at `xarray's plotting reference
# T = lifting_300hPa_trough(parameter='temp') # Digging Trough # Z = digging_300hPa_trough(parameter='hght') # T = digging_300hPa_trough(parameter='temp') ###################################################################### # Set geographic parameters for analytic grid to then # lats = np.linspace(35, 50, 101) lons = np.linspace(260, 290, 101) lon, lat = np.meshgrid(lons, lats) # Calculate Geostrophic Wind from Analytic Heights f = mpcalc.coriolis_parameter(lat * units('degrees')) dx, dy = mpcalc.lat_lon_grid_deltas(lons, lats) ugeo, vgeo = mpcalc.geostrophic_wind(Z * units.meter, f, dx, dy, dim_order='yx') # Get the wind direction for each point wdir = mpcalc.wind_direction(ugeo, vgeo) # Compute the Gradient Wind via an approximation dydx = mpcalc.first_derivative(Z, delta=dx, axis=1) d2ydx2 = mpcalc.first_derivative(dydx, delta=dx, axis=1) R = ((1 + dydx.m**2)**(3. / 2.)) / d2ydx2.m
ureg = UnitRegistry() lats_p = lats * ureg.deg lons_p = lons * ureg.deg #lats_p.dims = units.deg #lons_p.dims = units.deg phi, theta = np.meshgrid(lons, lats) * ureg.deg #f = 2.*7.2921e-5*np.sin(theta*np.pi/180.)/ureg.second #dy = dy*units.meters #dx = dx*units.meters #print(dx.dim, dy) f = mpcalc.coriolis_parameter(theta) #f, lons = cartopy.util.add_cyclic_point(f, coord=lon, axis=1) dx, dy = mpcalc.lat_lon_grid_deltas(phi, theta) print(f.shape) #f = np.repeat(f, 129, axis=1 ) print(dx.shape) #lat, lon = xr.broadcast(lats_p, lons_p) heights = geopot * ureg.hPa heights = xr.DataArray(geopot[0, :, :] * units['hPa'], dims=("lat", "lon"), coords={ "lon": lons_p, "lat": lats_p
hght_500 = ds.variables['Geopotential_height_isobaric'][0, lev_500, :, :] hght_500 = ndimage.gaussian_filter(hght_500, sigma=3, order=0) * units.meter uwnd_500 = units('m/s') * ds.variables['u-component_of_wind_isobaric'][ 0, lev_500, :, :] vwnd_500 = units('m/s') * ds.variables['v-component_of_wind_isobaric'][ 0, lev_500, :, :] ####################################### # Begin Data Calculations # ----------------------- dx, dy = mpcalc.lat_lon_grid_deltas(lon, lat) f = mpcalc.coriolis_parameter(np.deg2rad(lat)).to(units('1/sec')) avor = mpcalc.vorticity(uwnd_500, vwnd_500, dx, dy, dim_order='yx') + f avor = ndimage.gaussian_filter(avor, sigma=3, order=0) * units('1/s') vort_adv = mpcalc.advection(avor, [uwnd_500, vwnd_500], (dx, dy), dim_order='yx') * 1e9 ####################################### # Map Creation # ------------ # Set up Coordinate System for Plot and Transforms dproj = ds.variables['LambertConformal_Projection'] globe = ccrs.Globe(ellipse='sphere',
height = height_var[0, 0, :, :].squeeze() u_wind = u_wind_var[0, 0, :, :].squeeze() * units('m/s') v_wind = v_wind_var[0, 0, :, :].squeeze() * units('m/s') # Convert number of hours since the reference time into an actual date time = num2date(time_var[:].squeeze(), time_var.units) # Combine 1D latitude and longitudes into a 2D grid of locations lon_2d, lat_2d = np.meshgrid(lon, lat) # Smooth height data height = ndimage.gaussian_filter(height, sigma=1.5, order=0) # Set up some constants based on our projection, including the Coriolis parameter and # grid spacing, converting lon/lat spacing to Cartesian f = mpcalc.coriolis_parameter(np.deg2rad(lat_2d)).to('1/s') dx, dy = mpcalc.lat_lon_grid_spacing(lon_2d, lat_2d) dy *= -1 # In MetPy 0.5, geostrophic_wind() assumes the order of the dimensions is (X, Y), # so we need to transpose from the input data, which are ordered lat (y), lon (x). # Once we get the components,transpose again so they match our original data. geo_wind_u, geo_wind_v = mpcalc.geostrophic_wind(height * units.m, f, dx, dy) geo_wind_u = geo_wind_u geo_wind_v = geo_wind_v # Calculate ageostrophic wind components ageo_wind_u = u_wind - geo_wind_u ageo_wind_v = v_wind - geo_wind_v # Create new figure
######################################################################### # Calculations # ------------ # # Most of the calculations in `metpy.calc` will accept DataArrays by converting them # into their corresponding unit arrays. While this may often work without any issues, we must # keep in mind that because the calculations are working with unit arrays and not DataArrays: # # - The calculations will return unit arrays rather than DataArrays # - Broadcasting must be taken care of outside of the calculation, as it would only recognize # dimensions by order, not name # # As an example, we calculate geostropic wind at 500 hPa below: lat, lon = xr.broadcast(y, x) f = mpcalc.coriolis_parameter(lat) dx, dy = mpcalc.lat_lon_grid_deltas(lon, lat, initstring=data_crs.proj4_init) heights = data['height'].loc[time[0]].loc[{vertical.name: 500.}] u_geo, v_geo = mpcalc.geostrophic_wind(heights, f, dx, dy) print(u_geo) print(v_geo) ######################################################################### # Also, a limited number of calculations directly support xarray DataArrays or Datasets (they # can accept *and* return xarray objects). Right now, this includes # # - Derivative functions # - ``first_derivative`` # - ``second_derivative`` # - ``gradient`` # - ``laplacian``
def test_coriolis_units(): """Test that coriolis returns units of 1/second.""" f = coriolis_parameter(50 * units.degrees) assert f.units == units('1/second')
""" ##################################### import cartopy.crs as ccrs import cartopy.feature as cfeature from cartopy.util import add_cyclic_point import matplotlib import matplotlib.pyplot as plt import metpy.calc as mpcalc from metpy.units import units import numpy as np ##################################### lats = np.arange(-90, 91) * units.degrees coriolis = mpcalc.coriolis_parameter(lats) ##################################### fig = plt.figure(figsize=(8, 5)) ax = plt.subplot(1, 1, 1) ax.plot(lats, coriolis) ax.set_xlabel('Latitude', fontsize=14) ax.set_ylabel('Coriolis Parameter', fontsize=14) ##################################### lons = np.arange(0, 360) coriolis = np.ones((181, 360)) * coriolis[:, np.newaxis]