def test_speed_dir_roundtrip(): """Test round-tripping between speed/direction and components.""" # Test each quadrant of the whole circle wspd = np.array([15., 5., 2., 10.]) * units.meters / units.seconds wdir = np.array([160., 30., 225., 350.]) * units.degrees u, v = get_wind_components(wspd, wdir) wdir_out = get_wind_dir(u, v) wspd_out = get_wind_speed(u, v) assert_array_almost_equal(wspd, wspd_out, 4) assert_array_almost_equal(wdir, wdir_out, 4)
def test_speed(): """Test calculating wind speed.""" u = np.array([4., 2., 0., 0.]) * units('m/s') v = np.array([0., 2., 4., 0.]) * units('m/s') speed = get_wind_speed(u, v) s2 = np.sqrt(2.) true_speed = np.array([4., 2 * s2, 4., 0.]) * units('m/s') assert_array_almost_equal(true_speed, speed, 4)
def test_get_wind_speed(): """Test that get_wind_speed wrapper works (deprecated in 0.9).""" with pytest.warns(MetpyDeprecationWarning): s = get_wind_speed(-3. * units('m/s'), -4. * units('m/s')) assert_almost_equal(s, 5. * units('m/s'), 3)
def test_scalar_speed(): """Test wind speed with scalars.""" s = get_wind_speed(-3. * units('m/s'), -4. * units('m/s')) assert_almost_equal(s, 5. * units('m/s'), 3)
def test_get_wind_speed(): """Test that get_wind_speed wrapper works (deprecated in 0.9).""" s = get_wind_speed(-3. * units('m/s'), -4. * units('m/s')) assert_almost_equal(s, 5. * units('m/s'), 3)
# Determine the level of 500 hPa levs = data.variables[dlev][:] lev_500 = np.where(levs == 500)[0][0] # Create more useable times for output times = data.variables[dtime] vtimes = num2date(times[:], times.units) # Pull out the 500 hPa Heights hght = data.variables['Geopotential_height'][:].squeeze() * units.meter uwnd = data.variables['u_wind'][:].squeeze() * units('m/s') vwnd = data.variables['v_wind'][:].squeeze() * units('m/s') # Calculate the magnitude of the wind speed in kts sped = get_wind_speed(uwnd, vwnd).to('knots') ################################## # Set up the projection for LCC plotcrs = ccrs.LambertConformal(central_longitude=-100.0, central_latitude=45.0) datacrs = ccrs.PlateCarree(central_longitude=0.) states_provinces = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lakes', scale='50m', facecolor='none') ################################## # Subset and smooth
dlon = data.variables['Geopotential_height_isobaric'].dimensions[3] lat = data.variables[dlat][:] lon = data.variables[dlon][:] # Converting times using the num2date function available through netCDF4 times = data.variables[dtime] vtimes = num2date(times[:], times.units) # Smooth the 250-hPa heights using a gaussian filter from scipy.ndimage hgt_250, lon = cutil.add_cyclic_point(data.variables['Geopotential_height_isobaric'][:], coord=lon) Z_250 = ndimage.gaussian_filter(hgt_250[0, 0, :, :], sigma=3, order=0) u250 = cutil.add_cyclic_point(data.variables['u-component_of_wind_isobaric'][0, 0, :, :]) v250 = cutil.add_cyclic_point(data.variables['v-component_of_wind_isobaric'][0, 0, :, :]) wspd250 = mpcalc.get_wind_speed(u250, v250) * 1.94384 ################################################# # The next cell sets up the geographic details for the plot that we are going to do later. # This is done using the Cartopy package. We will also bring in some geographic data to # geo-reference the image for us. datacrs = ccrs.PlateCarree() plotcrs = ccrs.NorthPolarStereo(central_longitude=-100.0) states_provinces = cfeature.NaturalEarthFeature(category='cultural', name='admin_1_states_provinces_lakes', scale='50m', facecolor='none') # Make a grid of lat/lon values to use for plotting with Basemap. lons, lats = np.meshgrid(lon, lat)
def plot_background(ax): ax.set_extent([WLON, ELON, SLAT, NLAT]) ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidth=0.5) ax.add_feature(cfeature.LAKES.with_scale('50m'), linewidth=0.5) ax.add_feature(cfeature.STATES, linewidth=0.5) ax.add_feature(cfeature.BORDERS, linewidth=0.5) return ax # ============================================================================= # FIG #1: 250: JET STREAM, GEOPOTENTIAL HEIGHT, DIVERGENCE # ============================================================================= H250 = HGT_DATA.variables['hgt'][TIME_INDEX, 8, :, :] U250 = UWND_DATA.variables['uwnd'][TIME_INDEX, 8, :, :] * units('m/s') V250 = VWND_DATA.variables['vwnd'][TIME_INDEX, 8, :, :] * units('m/s') SPEED250 = mpcalc.get_wind_speed(U250, V250) DIV250 = mpcalc.divergence(U250, V250, DX, DY, dim_order='YX') DIV250 = (DIV250 * (units('1/s'))) # ============================================================================= # FIG #2: 500: VORTICITY, GEOPOTENTIAL HEIGHT, VORTICITY ADVECTION # ============================================================================= H500 = HGT_DATA.variables['hgt'][TIME_INDEX, 5, :, :] U500 = UWND_DATA.variables['uwnd'][TIME_INDEX, 5, :, :] * units('m/s') V500 = VWND_DATA.variables['vwnd'][TIME_INDEX, 5, :, :] * units('m/s') DX, DY = mpcalc.lat_lon_grid_spacing(LON, LAT) VORT500 = mpcalc.vorticity(U500, V500, DX, DY, dim_order='YX') VORT500 = (VORT500 * (units('1/s'))) VORT_ADV500 = mpcalc.advection(VORT500, [U500, V500], (DX, DY), dim_order='yx') # ============================================================================= # FIG #3: 700: Q-VECTORS+CONVERGENCE, GEOPOTENTIAL HEIGHT # =============================================================================
def Map_Jets(i, im_save_path): from siphon.catalog import TDSCatalog top_cat = TDSCatalog('http://thredds.ucar.edu/thredds/catalog.xml') ref = top_cat.catalog_refs['Forecast Model Data'] new_cat = ref.follow() model = new_cat.catalog_refs[4] gfs_cat = model.follow() ds = gfs_cat.datasets[1] subset = ds.subset() query_data = subset.query() query_data.lonlat_box(west=-130, east=-50, south=10, north=60) # Allow for NetCDF files query_data.accept('netcdf4') query_data.time(i) data = query_data.variables('Geopotential_height_isobaric', 'Pressure_reduced_to_MSL_msl', 'u-component_of_wind_isobaric', 'v-component_of_wind_isobaric') # Finally attempt to access the data data = subset.get_data(query_data) lat = data.variables['lat'][:].squeeze() lon = data.variables['lon'][:].squeeze() lev_250 = np.where(data.variables['isobaric4'][:] == 25000)[0][0] hght_250 = data.variables['Geopotential_height_isobaric'][0, lev_250, :, :] u_250 = data.variables['u-component_of_wind_isobaric'][0, lev_250, :, :] v_250 = data.variables['v-component_of_wind_isobaric'][0, lev_250, :, :] # Create a figure object, title it, and do the plots. fig = plt.figure(figsize=(17., 11.)) add_metpy_logo(fig, 30, 940, size='small') # Add the map and set the extent ax6 = plt.subplot(1, 1, 1, projection=plotcrs) # Add state boundaries to plot ax6.add_feature(states_provinces, edgecolor='b', linewidth=1) # Add country borders to plot ax6.add_feature(country_borders, edgecolor='k', linewidth=1) # Convert number of hours since the reference time into an actual date time_var = data.variables[find_time_var( data.variables['v-component_of_wind_isobaric'])] time_final = num2date(time_var[:].squeeze(), time_var.units) print( str(time_final)[:4] + "_" + str(time_final)[5:7] + "_" + str(time_final)[8:10] + "_" + str(time_final)[11:13] + "Z") file_time = str(time_final)[:4] + "_" + str(time_final)[5:7] + "_" + str( time_final)[8:10] + "_" + str(time_final)[11:13] + "Z" # Plot Title plt.title('GFS: 250mb Heights and Jet Streaks (m/s)', loc='left', fontsize=16) plt.title(' {0:%d %B %Y %H:%MZ}'.format(time_final), loc='right', fontsize=16) # Heights #--------------------------------------------------------------------------------------------------- MIN = hght_250.min() MAX = hght_250.max() #print hght_250.min(),hght_250.max() hght_250 = ndimage.gaussian_filter(hght_250, sigma=3, order=0) * units.meter clev250 = np.arange(MIN, MAX, 80) cs = ax6.contour(lon, lat, hght_250.m, clev250, colors='black', linewidths=2.0, linestyles='solid', transform=ccrs.PlateCarree()) #plt.clabel(cs, fontsize=10, inline=1, inline_spacing=10, fmt='%i', # rightside_up=True, use_clabeltext=True) # Winds #--------------------------------------------------------------------------------------------------- #lon_slice = slice(None, None, 7) #lat_slice = slice(None, None, 7) #ax4.barbs(lon[lon_slice], lat[lat_slice], # u_250[lon_slice, lat_slice].magnitude, # v_250[lon_slice, lat_slice].magnitude, # transform=ccrs.PlateCarree(), zorder=2) wspd250 = mpcalc.get_wind_speed(u_250, v_250) clevsped250 = np.arange(50, 100, 1) cf = ax6.contourf(lon, lat, wspd250, clevsped250, cmap="gist_ncar", transform=ccrs.PlateCarree()) #cbar = plt.colorbar(cf, cax=cax, orientation='horizontal', extend='max', extendrect=True,pad=0.2) cbaxes = fig.add_axes(colorbar_axis) cbar = plt.colorbar(cf, orientation='horizontal', cax=cbaxes) ax6.set_extent(extent, datacrs) plt.close(fig) #--------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------- GFS_Jet = im_save_path + "GFS/Jets/" if not os.path.isdir(GFS_Jet): os.makedirs(GFS_Jet) fig.savefig(GFS_Jet + "250mb_Heights_Winds_" + file_time + ".png", bbox_inches='tight', dpi=120) print('done.')
def Map_PVJet(i, im_save_path): from siphon.catalog import TDSCatalog top_cat = TDSCatalog('http://thredds.ucar.edu/thredds/catalog.xml') ref = top_cat.catalog_refs['Forecast Model Data'] new_cat = ref.follow() model = new_cat.catalog_refs[4] gfs_cat = model.follow() ds = gfs_cat.datasets[1] gfs_cat.datasets[1] subset = ds.subset() query_data = subset.query() query_data.lonlat_box(west=-130, east=-50, south=10, north=60) # Allow for NetCDF files query_data.accept('netcdf4') query_data.time(i) query_data.variables('Geopotential_height_potential_vorticity_surface', 'Geopotential_height_isobaric', 'u-component_of_wind_isobaric', 'v-component_of_wind_isobaric', 'Relative_humidity_isobaric', "Pressure_reduced_to_MSL_msl") #230., 295., 15., 45. #query.lonlat_box(west=230., east=295., south=15., north=45.) query_data.lonlat_box(west=-130, east=-50, south=10, north=60) query_data.accept('netcdf4') data = subset.get_data(query_data) PV_Heights = data.variables[ 'Geopotential_height_potential_vorticity_surface'][:].squeeze() PV_1 = np.where(data.variables['potential_vorticity_surface'][:] == 1.9999999949504854E-6)[0][0] PV_1st = PV_Heights[PV_1] lev_250 = np.where(data.variables['isobaric4'][:] == 25000)[0][0] hght_250 = data.variables['Geopotential_height_isobaric'][0, lev_250, :, :] u_250 = data.variables['u-component_of_wind_isobaric'][0, lev_250, :, :] v_250 = data.variables['v-component_of_wind_isobaric'][0, lev_250, :, :] lat = data.variables['lat'][:] lon = data.variables['lon'][:] mslp = data.variables['Pressure_reduced_to_MSL_msl'][:].squeeze() # Create a figure object, title it, and do the plots. fig = plt.figure(figsize=(17., 11.)) add_metpy_logo(fig, 30, 940, size='small') # Add the map and set the extent ax = plt.subplot(1, 1, 1, projection=plotcrs) # Add state boundaries to plot ax.add_feature(states_provinces, edgecolor='b', linewidth=1) # Add country borders to plot ax.add_feature(country_borders, edgecolor='k', linewidth=1) # Convert number of hours since the reference time into an actual date time_var = data.variables[find_time_var( data.variables['v-component_of_wind_isobaric'])] time_final = num2date(time_var[:].squeeze(), time_var.units) print( str(time_final)[:4] + "_" + str(time_final)[5:7] + "_" + str(time_final)[8:10] + "_" + str(time_final)[11:13] + "Z") file_time = str(time_final)[:4] + "_" + str(time_final)[5:7] + "_" + str( time_final)[8:10] + "_" + str(time_final)[11:13] + "Z" # Plot Title plt.title('GFS: PV and Jet Streaks (m/s)', loc='left', fontsize=16) plt.title(' {0:%d %B %Y %H:%MZ}'.format(time_final), loc='right', fontsize=16) # Heights #--------------------------------------------------------------------------------------------------- MIN = hght_250.min() MAX = hght_250.max() #print hght_250.min(),hght_250.max() hght_250_smooth = ndimage.gaussian_filter(hght_250, sigma=3, order=0) * units.meter clev250 = np.arange(MIN, MAX, 80) #cs = ax.contour(lon_2d, lat_2d, hght_250_smooth, clev250, colors='black', linewidths=2.0, # linestyles='solid', transform=datacrs) #plt.clabel(cs, fontsize=10, inline=1, inline_spacing=10, fmt='%i', # rightside_up=True, use_clabeltext=True) # Winds #--------------------------------------------------------------------------------------------------- #lon_slice = slice(None, None, 7) #lat_slice = slice(None, None, 7) #ax4.barbs(lon[lon_slice], lat[lat_slice], # u_250[lon_slice, lat_slice].magnitude, # v_250[lon_slice, lat_slice].magnitude, # transform=ccrs.PlateCarree(), zorder=2) #clev_mslp = np.arange(0, 1200, 3) #cs = ax.contour(lon, lat, mslp/100, clev_mslp, colors='k',alpha=0.5, #linestyles='solid', transform=datacrs,zorder=5) # cmap='rainbow, linewidths=3 #plt.clabel(cs, fontsize=10, inline=1, inline_spacing=10, fmt='%i', # rightside_up=True, use_clabeltext=True,colors='k') wspd250 = mpcalc.get_wind_speed(u_250, v_250) #print wspd250.min() clevsped250 = np.arange(50, 100, 5) cf = ax.contour(lon, lat, wspd250, clevsped250, colors='r', transform=datacrs) plt.clabel(cf, fontsize=10, inline=1, inline_spacing=10, fmt='%i', rightside_up=True, use_clabeltext=True, colors='k') #cf = ax.contourf(lon_2d, lat_2d, wspd250, clevsped250, cmap="gist_ncar", transform=datacrs) #cbar = plt.colorbar(cf, cax=cax, orientation='horizontal', extend='max', extendrect=True,pad=0.2) #cbaxes = fig.add_axes(colorbar_axis) #cbar = plt.colorbar(cf, orientation='horizontal',cax=cbaxes) cs2 = ax.contourf(lon, lat, PV_1st, 100, alpha=0.7, antialiased=True, transform=datacrs, cmap='cubehelix_r') cbaxes = fig.add_axes(colorbar_axis) # [left, bottom, width, height] cbar = plt.colorbar(cs2, orientation='horizontal', cax=cbaxes) ax.set_extent(extent, datacrs) plt.close(fig) #--------------------------------------------------------------------------------------------------- #--------------------------------------------------------------------------------------------------- PV_Jet = im_save_path + "GFS/PV_Jet/" if not os.path.isdir(PV_Jet): os.makedirs(PV_Jet) fig.savefig(PV_Jet + "Jet_PV_" + file_time + ".png", bbox_inches='tight', dpi=120) print('done.')
# Surface dewpoint # # 700-hPa dewpoint depression # # 12-hr surface pressure falls and 500-hPa height changes # 500 hPa CVA dx, dy = mpcalc.lat_lon_grid_spacing(lon, lat) vort_adv_500 = mpcalc.advection(avor_500, [u_500.to('m/s'), v_500.to('m/s')], (dx, dy), dim_order='yx') * 1e9 vort_adv_500_smooth = gaussian_filter(vort_adv_500, 4) #################################### # For the jet axes, we will calculate the windspeed at each level, and plot the highest values wspd_300 = gaussian_filter(mpcalc.get_wind_speed(u_300, v_300), 5) wspd_500 = gaussian_filter(mpcalc.get_wind_speed(u_500, v_500), 5) wspd_850 = gaussian_filter(mpcalc.get_wind_speed(u_850, v_850), 5) ################################# # 850-hPa dewpoint will be calculated from RH and Temperature_isobaric Td_850 = mpcalc.dewpoint_rh(tmp_850, rh_850 / 100.) ################################ # 700-hPa dewpoint depression will be calculated from Temperature_isobaric and RH Td_dep_700 = tmp_700 - mpcalc.dewpoint_rh(tmp_700, rh_700 / 100.) ###################################### # 12-hr surface pressure falls and 500-hPa height changes pmsl_change = pmsl - pmsl_00z hgt_500_change = hgt_500 - hgt_500_00z
skew.plot_barbs(p[ix], u[ix], v[ix]) skew.ax.set_ylim(1075, 100) skew.ax.set_ylabel('Pressure (hPa)') lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) #LCL pwat = mpcalc.precipitable_water(Td, p, 500 * units.hectopascal).to('in') #PWAT cape, cin = mpcalc.most_unstable_cape_cin(p[:], T[:], Td[:]) #MUCAPE cape_sfc, cin_sfc = mpcalc.surface_based_cape_cin(p, T, Td) #SBCAPE prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') #parcel profile equiv_pot_temp = mpcalc.equivalent_potential_temperature(p, T, Td) #equivalent potential temperature el_pressure, el_temperature = mpcalc.el(p, T, Td) #elevated level lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td) #LFC #calculates shear u_threekm_bulk_shear, v_threekm_bulk_shear = mpcalc.bulk_shear(p, u, v, hgt, bottom = min(hgt), depth = 3000 * units.meter) threekm_bulk_shear = mpcalc.get_wind_speed(u_threekm_bulk_shear, v_threekm_bulk_shear) u_onekm_bulk_shear, v_onekm_bulk_shear = mpcalc.bulk_shear(p, u, v, hgt, bottom = min(hgt), depth = 1000 * units.meter) onekm_bulk_shear = mpcalc.get_wind_speed(u_onekm_bulk_shear, v_onekm_bulk_shear) #shows the level of the LCL, LFC, and EL. skew.ax.text(T[0].magnitude, p[0].magnitude + 5, str(int(np.round(T[0].to('degF').magnitude))), fontsize = 'medium', horizontalalignment = 'left', verticalalignment = 'top', color = 'red') skew.ax.text(Td[0].magnitude, p[0].magnitude + 5, str(int(np.round(Td[0].to('degF').magnitude))), fontsize = 'medium', horizontalalignment = 'right', verticalalignment = 'top', color = 'green') skew.ax.text(lcl_temperature.magnitude + 5, lcl_pressure.magnitude, "---- LCL", fontsize = 'medium', verticalalignment = 'center') skew.ax.text(Td[0].magnitude - 10, p[0].magnitude, 'SFC: {}hPa ----'.format(p[0].magnitude), fontsize = 'medium', horizontalalignment = 'right', verticalalignment = 'center', color = 'black') if str(lfc_temperature.magnitude) != 'nan': #checks to see if LFC/EL exists. If not, skip. skew.ax.text(lfc_temperature.magnitude + 5, lfc_pressure.magnitude, "---- LFC", fontsize = 'medium', verticalalignment = 'center') skew.ax.text(el_temperature.magnitude + 5, el_pressure.magnitude, "---- EL", fontsize = 'medium', verticalalignment = 'center') skew.plot(p, prof, 'k-', linewidth=1) #plots parcel profile skew.shade_cape(p, T, prof) #shades cape