def test_wind_shear(): agl1 = 0 agl2 = 1000 msl1 = interp.to_msl(prof, agl1) msl2 = interp.to_msl(prof, agl2) pbot = interp.pres(prof, msl1) ptop = interp.pres(prof, msl2) correct_u, correct_v = -2.625075135691132, 10.226725739920353 returned = winds.wind_shear(prof, pbot, ptop) npt.assert_almost_equal(returned, [correct_u, correct_v])
def bunkers_storm_motion(prof, pbot=None, **kwargs): ''' Compute the Bunkers Storm Motion for a Right Moving Supercell using a parcel based approach. Inputs ------ prof (profile object) Profile Object pbot (float) Base of effective-inflow layer (hPa) Returns ------- rstu (float) Right Storm Motion U-component rstv (float) Right Storm Motion V-component lstu (float) Left Storm Motion U-component lstv (float) Left Storm Motion V-component ''' d = MS2KTS(7.5) # Deviation value emperically derived as 7.5 m/s # If MUPCL provided, use it, otherwise create MUPCL if 'mupcl' in kwargs: mupcl = kwargs.get('mupcl') else: mulplvals = params.DefineParcel(3, prof, pres=400) mupcl = params.parcelx(-1, -1, mulplvals.pres, mulplvals.temp, mulplvals.dwpt, prof, lplvals=mulplvals) mucape = mupcl.bplus mucinh = mupcl.bminus muel = mupcl.elhght if not pbot: pbot, ptop = effective_inflow_layer(100, -250, prof) base = interp.agl(interp.hght(pbot, prof), prof) if mucape > 100. and QC(muel) and base >= 750: depth = muel - base htop = base + depth / 2. ptop = interp.pres(interp.msl(base + htop, prof), prof) mnu, mnv = winds.mean_wind_npw(pbot, ptop, prof) sru, srv = winds.wind_shear(pbot, ptop, prof) srmag = vector.mag(sru, srv) uchg = d / srmag * srv vchg = d / srmag * sru rstu = mnu + uchg rstv = mnv - vchg lstu = mnu - uchg lstv = mnv + vchg else: rstu, rstv, lstu, lstv = winds.non_parcel_bunkers_motion(prof) return rstu, rstv, lstu, lstv
def get_kinematics(self): ''' Function to generate the numerous kinematic quantities used for display and calculations. It requires that the parcel calculations have already been called for the lcl to el shear and mean wind vectors, as well as indices that require an effective inflow layer. Parameters ---------- None Returns ------- None ''' sfc = self.pres[self.sfc] heights = np.array([1000., 3000., 4000., 5000., 6000., 8000., 9000.]) p1km, p3km, p4km, p5km, p6km, p8km, p9km = interp.pres( self, interp.to_msl(self, heights)) ## 1km and 6km winds self.wind1km = interp.vec(self, p1km) self.wind6km = interp.vec(self, p6km) ## calcluate wind shear self.sfc_1km_shear = winds.wind_shear(self, pbot=sfc, ptop=p1km) self.sfc_3km_shear = winds.wind_shear(self, pbot=sfc, ptop=p3km) self.sfc_6km_shear = winds.wind_shear(self, pbot=sfc, ptop=p6km) self.sfc_8km_shear = winds.wind_shear(self, pbot=sfc, ptop=p8km) self.sfc_9km_shear = winds.wind_shear(self, pbot=sfc, ptop=p9km) self.lcl_el_shear = winds.wind_shear(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres) ## calculate mean wind self.mean_1km = utils.comp2vec( *winds.mean_wind(self, pbot=sfc, ptop=p1km)) self.mean_3km = utils.comp2vec( *winds.mean_wind(self, pbot=sfc, ptop=p3km)) self.mean_6km = utils.comp2vec( *winds.mean_wind(self, pbot=sfc, ptop=p6km)) self.mean_8km = utils.comp2vec( *winds.mean_wind(self, pbot=sfc, ptop=p8km)) self.mean_lcl_el = utils.comp2vec(*winds.mean_wind( self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres)) ## parameters that depend on the presence of an effective inflow layer if self.etop is ma.masked or self.ebottom is ma.masked: self.etopm = ma.masked self.ebotm = ma.masked self.srwind = winds.non_parcel_bunkers_motion(self) self.eff_shear = [MISSING, MISSING] self.ebwd = [MISSING, MISSING, MISSING] self.ebwspd = MISSING self.mean_eff = [MISSING, MISSING, MISSING] self.mean_ebw = [MISSING, MISSING, MISSING] self.srw_eff = [MISSING, MISSING, MISSING] self.srw_ebw = [MISSING, MISSING, MISSING] self.right_esrh = [ma.masked, ma.masked, ma.masked] self.left_esrh = [ma.masked, ma.masked, ma.masked] self.critical_angle = ma.masked else: self.srwind = params.bunkers_storm_motion(self, mupcl=self.mupcl, pbot=self.ebottom) depth = (self.mupcl.elhght - self.ebotm) / 2 elh = interp.pres(self, interp.to_msl(self, self.ebotm + depth)) ## calculate mean wind self.mean_eff = winds.mean_wind(self, self.ebottom, self.etop) self.mean_ebw = winds.mean_wind(self, pbot=self.ebottom, ptop=elh) ## calculate wind shear of the effective layer self.eff_shear = winds.wind_shear(self, pbot=self.ebottom, ptop=self.etop) self.ebwd = winds.wind_shear(self, pbot=self.ebottom, ptop=elh) self.ebwspd = utils.mag(self.ebwd[0], self.ebwd[1]) ## calculate the mean sr wind self.srw_eff = winds.sr_wind(self, pbot=self.ebottom, ptop=self.etop, stu=self.srwind[0], stv=self.srwind[1]) self.srw_ebw = winds.sr_wind(self, pbot=self.ebottom, ptop=elh, stu=self.srwind[0], stv=self.srwind[1]) self.right_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[0], stv=self.srwind[1]) self.left_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[2], stv=self.srwind[3]) self.critical_angle = winds.critical_angle(self, stu=self.srwind[0], stv=self.srwind[1]) ## calculate mean srw self.srw_1km = utils.comp2vec(*winds.sr_wind( self, pbot=sfc, ptop=p1km, stu=self.srwind[0], stv=self.srwind[1])) self.srw_3km = utils.comp2vec(*winds.sr_wind( self, pbot=sfc, ptop=p3km, stu=self.srwind[0], stv=self.srwind[1])) self.srw_6km = utils.comp2vec(*winds.sr_wind( self, pbot=sfc, ptop=p6km, stu=self.srwind[0], stv=self.srwind[1])) self.srw_8km = utils.comp2vec(*winds.sr_wind( self, pbot=sfc, ptop=p8km, stu=self.srwind[0], stv=self.srwind[1])) self.srw_4_5km = utils.comp2vec(*winds.sr_wind( self, pbot=p4km, ptop=p5km, stu=self.srwind[0], stv=self.srwind[1])) self.srw_lcl_el = utils.comp2vec( *winds.sr_wind(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres, stu=self.srwind[0], stv=self.srwind[1])) # This is for the red, blue, and purple bars that appear on the SR Winds vs. Height plot self.srw_0_2km = winds.sr_wind(self, pbot=sfc, ptop=interp.pres( self, interp.to_msl(self, 2000.)), stu=self.srwind[0], stv=self.srwind[1]) self.srw_4_6km = winds.sr_wind(self, pbot=interp.pres( self, interp.to_msl(self, 4000.)), ptop=p6km, stu=self.srwind[0], stv=self.srwind[1]) self.srw_9_11km = winds.sr_wind( self, pbot=interp.pres(self, interp.to_msl(self, 9000.)), ptop=interp.pres(self, interp.to_msl(self, 11000.)), stu=self.srwind[0], stv=self.srwind[1]) ## calculate upshear and downshear self.upshear_downshear = winds.mbe_vectors(self) self.srh1km = winds.helicity(self, 0, 1000., stu=self.srwind[0], stv=self.srwind[1]) self.srh3km = winds.helicity(self, 0, 3000., stu=self.srwind[0], stv=self.srwind[1])
def indices(prof, debug=False): # return a formatted-string list of stability and kinematic indices sfcpcl = params.parcelx(prof, flag=1) mupcl = params.parcelx(prof, flag=3) # most unstable mlpcl = params.parcelx(prof, flag=4) # 100 mb mean layer parcel pcl = mupcl sfc = prof.pres[prof.sfc] p3km = interp.pres(prof, interp.to_msl(prof, 3000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) mean_3km = winds.mean_wind(prof, pbot=sfc, ptop=p3km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km) sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) #print "0-3 km Pressure-Weighted Mean Wind (kt):", utils.comp2vec(mean_3km[0], mean_3km[1])[1] #print "0-6 km Shear (kt):", utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] srwind = params.bunkers_storm_motion(prof) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) #print "0-3 km Storm Relative Helicity [m2/s2]:",srh3km[0] #### Calculating variables based off of the effective inflow layer: # The effective inflow layer concept is used to obtain the layer of buoyant parcels that feed a storm's inflow. # Here are a few examples of how to compute variables that require the effective inflow layer in order to calculate them: stp_fixed = params.stp_fixed( sfcpcl.bplus, sfcpcl.lclhght, srh1km[0], utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]) ship = params.ship(prof) # If you get an error about not converting masked constant to python int # use the round() function instead of int() - Ahijevych May 11 2016 # 2nd element of list is the # of decimal places indices = { 'SBCAPE': [sfcpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'SBCIN': [sfcpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'SBLCL': [sfcpcl.lclhght, 0, 'm AGL'], 'SBLFC': [sfcpcl.lfchght, 0, 'm AGL'], 'SBEL': [sfcpcl.elhght, 0, 'm AGL'], 'SBLI': [sfcpcl.li5, 0, 'C'], 'MLCAPE': [mlpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'MLCIN': [mlpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'MLLCL': [mlpcl.lclhght, 0, 'm AGL'], 'MLLFC': [mlpcl.lfchght, 0, 'm AGL'], 'MLEL': [mlpcl.elhght, 0, 'm AGL'], 'MLLI': [mlpcl.li5, 0, 'C'], 'MUCAPE': [mupcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'MUCIN': [mupcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'MULCL': [mupcl.lclhght, 0, 'm AGL'], 'MULFC': [mupcl.lfchght, 0, 'm AGL'], 'MUEL': [mupcl.elhght, 0, 'm AGL'], 'MULI': [mupcl.li5, 0, 'C'], '0-1 km SRH': [srh1km[0], 0, '$\mathregular{m^{2}s^{-2}}$'], '0-1 km Shear': [utils.comp2vec(sfc_1km_shear[0], sfc_1km_shear[1])[1], 0, 'kt'], '0-3 km SRH': [srh3km[0], 0, '$\mathregular{m^{2}s^{-2}}$'], '0-6 km Shear': [utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1], 0, 'kt'], 'PWV': [params.precip_water(prof), 2, 'inch'], 'K-index': [params.k_index(prof), 0, ''], 'STP(fix)': [stp_fixed, 1, ''], 'SHIP': [ship, 1, ''] } eff_inflow = params.effective_inflow_layer(prof) if any(eff_inflow): ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0])) etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1])) #print "Effective Inflow Layer Bottom Height (m AGL):", ebot_hght #print "Effective Inflow Layer Top Height (m AGL):", etop_hght effective_srh = winds.helicity(prof, ebot_hght, etop_hght, stu=srwind[0], stv=srwind[1]) indices['Eff. SRH'] = [ effective_srh[0], 0, '$\mathregular{m^{2}s^{-2}}$' ] #print "Effective Inflow Layer SRH (m2/s2):", effective_srh[0] ebwd = winds.wind_shear(prof, pbot=eff_inflow[0], ptop=eff_inflow[1]) ebwspd = utils.mag(*ebwd) indices['EBWD'] = [ebwspd, 0, 'kt'] #print "Effective Bulk Wind Difference:", ebwspd scp = params.scp(mupcl.bplus, effective_srh[0], ebwspd) indices['SCP'] = [scp, 1, ''] stp_cin = params.stp_cin(mlpcl.bplus, effective_srh[0], ebwspd, mlpcl.lclhght, mlpcl.bminus) indices['STP(cin)'] = [stp_cin, 1, ''] #print "Supercell Composite Parameter:", scp #print "Significant Tornado Parameter (w/CIN):", stp_cin #print "Significant Tornado Parameter (fixed):", stp_fixed # Update the indices within the indices dictionary on the side of the plot. string = '' for index, value in sorted(indices.items()): if np.ma.is_masked(value[0]): if debug: print("skipping masked value for index=", index) continue if debug: print("index=", index) print("value=", value) format = '%.' + str(value[1]) + 'f' string += index + ": " + format % value[0] + " " + value[2] + '\n' return string
''' Create the Sounding (Profile) Object '''
def plot_sounding(file, imgName): try: prof, time, location = decode(file) except Exception as e: print( "\n Oops! Couldn't decode the sounding data. No plot produced!\n") print(e) # return None # Open up the text file with the data in columns (e.g. the sample OAX file distributed with SHARPpy) locInfo = location.split('_') title = locInfo[0] + ' ' + locInfo[1] + ' ' + locInfo[ 2] + ' ' + time.strftime('%Y%m%d/%H%M') + ' (Observed)' # Set up the figure in matplotlib. fig = plt.figure(figsize=(14, 7.25)) gs = gridspec.GridSpec(4, 6, width_ratios=[1, 5, 1, 0.5, 3, 3]) ax = plt.subplot(gs[0:3, 0:2], projection='skewx') plt.title(title, fontsize=14, loc='left', color='w') ax.set_facecolor('k') ax.spines['left'].set_color('w') ax.spines['right'].set_color('w') ax.spines['bottom'].set_color('w') ax.spines['top'].set_color('w') # xticks = ax.xaxis.get_major_ticks() #mute a tick label outside plot # xticks[-4].label1.set_visible(False) ax.tick_params(axis='both', colors='w', grid_color='silver') ax.ticklabel_format(style='plain') # ax.xaxis.label.set_color('w') # ax.yaxis.label.set_color('w') ax.grid(True) plt.grid(True) # Ask user for default limits or custom limits pt_plot, t_lower, t_upper = ask_limits(prof.pres[~prof.dwpc.mask], prof.dwpc[~prof.dwpc.mask]) # Bounds of the pressure axis pb_plot = 1050 dp_plot = 10 plevs_plot = np.arange(pb_plot, pt_plot - 1, -dp_plot) # Plot the background variables # presvals = np.arange(1000, 0, -10) #draw mixing ratio lines draw_mixing_ratio_lines(ax) ax.semilogy(prof.tmpc[~prof.tmpc.mask], prof.pres[~prof.tmpc.mask], 'r', lw=2) ax.semilogy(prof.dwpc[~prof.dwpc.mask], prof.pres[~prof.dwpc.mask], 'lime', lw=2) ax.semilogy(prof.vtmp[~prof.dwpc.mask], prof.pres[~prof.dwpc.mask], 'r--', lw=1) ax.semilogy(prof.wetbulb[~prof.dwpc.mask], prof.pres[~prof.dwpc.mask], 'cyan', '-', lw=1) #write sfc temp and dewpoint in F sfcT = prof.tmpc[~prof.tmpc.mask][0] sfcTd = prof.dwpc[~prof.dwpc.mask][0] sfcW = prof.wetbulb[~prof.dwpc.mask][0] sfcP = prof.pres[~prof.tmpc.mask][0] ax.annotate(str(int(sfcW * (9 / 5) + 32)), (sfcW, sfcP), xytext=(-6, -9), textcoords='offset points', color='cyan', weight='black', size=8, path_effects=[pe.withStroke(linewidth=2, foreground="black")]) ax.annotate(str(int(sfcT * (9 / 5) + 32)), (sfcT, sfcP), xytext=(-2, -9), textcoords='offset points', color='r', weight='black', size=8, path_effects=[pe.withStroke(linewidth=2, foreground="black")]) ax.annotate(str(int(sfcTd * (9 / 5) + 32)), (sfcTd, sfcP), xytext=(-12, -9), textcoords='offset points', color='lime', weight='black', size=8, path_effects=[pe.withStroke(linewidth=2, foreground="black")]) #plot significant levels plot_sig_levels(ax, prof) # Plot the parcel trace, but this may fail. If it does so, inform the user. try: ax.semilogy(prof.mupcl.ttrace, prof.mupcl.ptrace, 'w--') except: print("Couldn't plot parcel traces...") # Highlight the 0 C and -20 C isotherms. l = ax.axvline(0, color='b', ls='--') l = ax.axvline(-20, color='b', ls='--') #plot dry adiabats skew.draw_dry_adiabats(ax, color='silver') #draw heights skew.draw_heights(ax, prof) # Disables the log-formatting that comes with semilogy ax.yaxis.set_major_formatter(ScalarFormatter()) pmin = prof.pres[~prof.dwpc.mask][-1] if pmin > 700.: ax.set_yticks(np.arange(100, 1000, 50)) else: ax.set_yticks(np.linspace(100, 1000, 10)) ax.set_ylim(pb_plot, pt_plot) # Plot the hodograph data. # inset_axes = draw_hodo_inset(ax, prof) hodoAx = plt.subplot(gs[0:3, 3:]) hodoAx.set_facecolor('k') hodoAx.axis('off') hodoAx = draw_hodo_inset(hodoAx, prof) # plotHodo(inset_axes, prof.hght, prof.u, prof.v, color='r') plotHodo(hodoAx, prof.hght, prof.u, prof.v, color='r') #plot bunkers motion unless the most unstable EL does not exist srwind = params.bunkers_storm_motion(prof) if isinstance(prof.mupcl.elpres, np.float64): hodoAx.text(srwind[0], srwind[1], 'RM', color='w', fontsize=8) hodoAx.text(srwind[2], srwind[3], 'LM', color='w', fontsize=8) else: print("couldn't plot Bunkers vectors") # inset_axes.text(srwind[0], srwind[1], 'RM', color='r', fontsize=8) # inset_axes.text(srwind[2], srwind[3], 'LM', color='b', fontsize=8) #mask out barbs above the top of the plot below_pmin = np.where(prof.pres >= pt_plot)[0] # Draw the wind barbs axis and everything that comes with it. if pmin > 700.: ax.xaxis.set_major_locator(MultipleLocator(5)) else: ax.xaxis.set_major_locator(MultipleLocator(10)) ax.set_xlim(t_lower, t_upper) ax2 = plt.subplot(gs[0:3, 2]) ax3 = plt.subplot(gs[3, 0:3]) plot_wind_axes(ax2, pb_plot, pt_plot, plevs_plot) #setting the stride for how many wind barbs plot # st = 15 # plot_wind_barbs(ax2, prof.pres[below_pmin][~prof.pres.mask[below_pmin]][::st], # prof.u[below_pmin][~prof.u.mask[below_pmin]][::st], # prof.v[below_pmin][~prof.v.mask[below_pmin]][::st], # pt_plot) plot_wind_barbs(ax2, prof.pres[below_pmin][~prof.pres.mask[below_pmin]], prof.u[below_pmin][~prof.u.mask[below_pmin]], prof.v[below_pmin][~prof.v.mask[below_pmin]], pt_plot) gs.update(left=0.05, bottom=0.05, top=0.95, right=1, wspace=0.025) # Calculate indices to be shown. More indices can be calculated here using the tutorial and reading the params module. p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) sfc = prof.pres[prof.sfc] sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) scp = params.scp(prof.mupcl.bplus, prof.right_esrh[0], prof.ebwspd) stp_cin = params.stp_cin(prof.mlpcl.bplus, prof.right_esrh[0], prof.ebwspd, prof.mlpcl.lclhght, prof.mlpcl.bminus) stp_fixed = params.stp_fixed( prof.sfcpcl.bplus, prof.sfcpcl.lclhght, srh1km[0], utils.comp2vec(prof.sfc_6km_shear[0], prof.sfc_6km_shear[1])[1]) ship = params.ship(prof) # A routine to perform the correct formatting when writing the indices out to the figure. def fmt(value, fmt='int'): if fmt == 'int': try: val = int(value) except: val = str("M") else: try: val = round(value, 1) except: val = "M" return val # Setting a dictionary that is a collection of all of the indices we'll be showing on the figure. # the dictionary includes the index name, the actual value, and the units. indices = {'SBCAPE': [fmt(prof.sfcpcl.bplus), 'J/kg'],\ 'SBCIN': [fmt(prof.sfcpcl.bminus), 'J/kg'],\ 'SBLCL': [fmt(prof.sfcpcl.lclhght), 'm AGL'],\ 'SBLFC': [fmt(prof.sfcpcl.lfchght), 'm AGL'],\ 'SBEL': [fmt(prof.sfcpcl.elhght), 'm AGL'],\ 'SBLI': [fmt(prof.sfcpcl.li5), 'C'],\ 'MLCAPE': [fmt(prof.mlpcl.bplus), 'J/kg'],\ 'MLCIN': [fmt(prof.mlpcl.bminus), 'J/kg'],\ 'MLLCL': [fmt(prof.mlpcl.lclhght), 'm AGL'],\ 'MLLFC': [fmt(prof.mlpcl.lfchght), 'm AGL'],\ 'MLEL': [fmt(prof.mlpcl.elhght), 'm AGL'],\ 'MLLI': [fmt(prof.mlpcl.li5), 'C'],\ 'MUCAPE': [fmt(prof.mupcl.bplus), 'J/kg'],\ 'MUCIN': [fmt(prof.mupcl.bminus), 'J/kg'],\ 'MULCL': [fmt(prof.mupcl.lclhght), 'm AGL'],\ 'MULFC': [fmt(prof.mupcl.lfchght), 'm AGL'],\ 'MUEL': [fmt(prof.mupcl.elhght), 'm AGL'],\ 'MULI': [fmt(prof.mupcl.li5), 'C'],\ '0-1 km SRH': [fmt(srh1km[0]), 'm2/s2'],\ '0-1 km Shear': [fmt(utils.comp2vec(sfc_1km_shear[0], sfc_1km_shear[1])[1]), 'kts'],\ '0-3 km SRH': [fmt(srh3km[0]), 'm2/s2'],\ '0-6 km Shear': [fmt(utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]), 'kts'],\ 'Eff. SRH': [fmt(prof.right_esrh[0]), 'm2/s2'],\ 'EBWD': [fmt(prof.ebwspd), 'kts'],\ 'PWV': [round(prof.pwat, 2), 'inch'],\ 'K-index': [fmt(params.k_index(prof)), ''],\ 'STP(fix)': [fmt(stp_fixed, 'flt'), ''],\ 'SHIP': [fmt(ship, 'flt'), ''],\ 'SCP': [fmt(scp, 'flt'), ''],\ 'STP(cin)': [fmt(stp_cin, 'flt'), '']} # List the indices within the indices dictionary on the side of the plot. trans = transforms.blended_transform_factory(ax.transAxes, ax.transData) # Write out all of the indices to the figure. #print("##############") #print(" INDICES ") #print("##############") string = '' keys = np.sort(list(indices.keys())) x = 0 counter = 0 for key in keys: string = string + key + ': ' + str( indices[key][0]) + ' ' + indices[key][1] + '\n' # print((key + ": " + str(indices[key][0]) + ' ' + indices[key][1])) if counter < 7: counter += 1 continue else: counter = 0 ax3.text(x, 1, string, verticalalignment='top', transform=ax3.transAxes, fontsize=11, color='w') string = '' x += 0.3 ax3.text(x, 1, string, verticalalignment='top', transform=ax3.transAxes, fontsize=11, color='w') ax3.set_axis_off() # Show SARS matches (edited for Keith Sherburn) #try: # supercell_matches = prof.supercell_matches # hail_matches = prof.matches #except: # supercell_matches = prof.right_supercell_matches # hail_matches = prof.right_matches #print() #print("#############") #print(" SARS OUTPUT ") #print("#############") #for mtype, matches in zip(['Supercell', 'Hail'], [supercell_matches, hail_matches]): # print(mtype) # print('-----------') # if len(matches[0]) == 0: # print("NO QUALITY MATCHES") # for i in range(len(matches[0])): # print(matches[0][i] + ' ' + matches[1][i]) # print("Total Loose Matches:", matches[2]) # print("# of Loose Matches that met Criteria:", matches[3]) # print("SVR Probability:", matches[4]) # print() #plot logos im = plt.imread('logo.png') #left, bottom, width, height = [0.25, 0.6, 0.2, 0.2] #left, bottom, width, height = [0.1, 0.175, 0.4, 0.4] #bottom left left, bottom, width, height = [0.035, 0.65, 0.4, 0.4] # ax4 = fig.add_axes([left, bottom, width, height]) ax4 = plt.subplot(gs[3, 4]) implot = ax4.imshow(im, alpha=0.99) ax4.axis('off') ax4.set_facecolor('k') im2 = plt.imread('essc_logo.png') ax5 = plt.subplot(gs[3, 5]) implot = ax5.imshow(im2, alpha=0.99) ax5.axis('off') ax5.set_facecolor('k') #plot SHARPpy acknowledgement # plt.text(1, 1, 'Plotted with SHARPpy', horizontalalignment='right', # verticalalignment='top', transform=ax.transAxes, color='w') hodoAx.annotate( 'Plotted with SHARPpy - https://sharppy.github.io/SHARPpy/', (0.7, 0.96), xycoords='figure fraction', va='center', color='w') #filename for the plot # plotName = os.path.splitext(file)[0] + '.png' # Finalize the image formatting and alignments, and save the image to the file. #gs.tight_layout(fig) plt.style.use('dark_background') fn = time.strftime( '%Y%m%d.%H%M') + '_' + locInfo[0] + '_' + locInfo[1] + '.png' fn = fn.replace('/', '') print('SHARPpy quick-look image output at: ' + imgName) #plt.savefig(fn, bbox_inches='tight', dpi=180) plt.savefig(imgName, dpi=180)
# Convert wind speed and direction to components u, v = get_wind_components(spd, direc) u_std, v_std = get_wind_components(spd_std, direc_std) #PARCEL CALCULATIONS with sharppy sfcpcl = params.parcelx(prof, flag=1) # Surface Parcel fcstpcl = params.parcelx(prof, flag=2) # Forecast Parcel mupcl = params.parcelx(prof, flag=3) # Most-Unstable Parcel mlpcl = params.parcelx(prof, flag=4) # 100 mb Mean Layer Parcel sfc = prof.pres[prof.sfc] p3km = interp.pres(prof, interp.to_msl(prof, 3000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) mean_3km = winds.mean_wind(prof, pbot=sfc, ptop=p3km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km) sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) srwind = params.bunkers_storm_motion(prof) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) stp_fixed = params.stp_fixed( sfcpcl.bplus, sfcpcl.lclhght, srh1km[0], utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]) ship = params.ship(prof) eff_inflow = params.effective_inflow_layer(prof) ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0])) etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1])) effective_srh = winds.helicity(prof, ebot_hght,
def get_kinematics(self): ''' Function to generate the numerous kinematic quantities used for display and calculations. It requires that the parcel calculations have already been called for the lcl to el shear and mean wind vectors, as well as indices that require an effective inflow layer. Parameters ---------- None Returns ------- None ''' sfc = self.pres[self.sfc] heights = np.array([1000., 3000., 4000., 5000., 6000., 8000., 9000.]) p1km, p3km, p4km, p5km, p6km, p8km, p9km = interp.pres(self, interp.to_msl(self, heights)) ## 1km and 6km winds self.wind1km = interp.vec(self, p1km) self.wind6km = interp.vec(self, p6km) ## calcluate wind shear self.sfc_1km_shear = winds.wind_shear(self, pbot=sfc, ptop=p1km) self.sfc_3km_shear = winds.wind_shear(self, pbot=sfc, ptop=p3km) self.sfc_6km_shear = winds.wind_shear(self, pbot=sfc, ptop=p6km) self.sfc_8km_shear = winds.wind_shear(self, pbot=sfc, ptop=p8km) self.sfc_9km_shear = winds.wind_shear(self, pbot=sfc, ptop=p9km) self.lcl_el_shear = winds.wind_shear(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres) ## calculate mean wind self.mean_1km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p1km)) self.mean_3km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p3km)) self.mean_6km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p6km)) self.mean_8km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p8km)) self.mean_lcl_el = utils.comp2vec(*winds.mean_wind(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres)) ## parameters that depend on the presence of an effective inflow layer if self.etop is ma.masked or self.ebottom is ma.masked: self.etopm = ma.masked; self.ebotm = ma.masked self.srwind = winds.non_parcel_bunkers_motion( self ) self.eff_shear = [MISSING, MISSING] self.ebwd = [MISSING, MISSING, MISSING] self.ebwspd = MISSING self.mean_eff = [MISSING, MISSING, MISSING] self.mean_ebw = [MISSING, MISSING, MISSING] self.srw_eff = [MISSING, MISSING, MISSING] self.srw_ebw = [MISSING, MISSING, MISSING] self.right_esrh = [ma.masked, ma.masked, ma.masked] self.left_esrh = [ma.masked, ma.masked, ma.masked] self.critical_angle = ma.masked else: self.srwind = params.bunkers_storm_motion(self, mupcl=self.mupcl, pbot=self.ebottom) depth = ( self.mupcl.elhght - self.ebotm ) / 2 elh = interp.pres(self, interp.to_msl(self, self.ebotm + depth)) ## calculate mean wind self.mean_eff = winds.mean_wind(self, self.ebottom, self.etop ) self.mean_ebw = winds.mean_wind(self, pbot=self.ebottom, ptop=elh ) ## calculate wind shear of the effective layer self.eff_shear = winds.wind_shear(self, pbot=self.ebottom, ptop=self.etop) self.ebwd = winds.wind_shear(self, pbot=self.ebottom, ptop=elh) self.ebwspd = utils.mag( self.ebwd[0], self.ebwd[1] ) ## calculate the mean sr wind self.srw_eff = winds.sr_wind(self, pbot=self.ebottom, ptop=self.etop, stu=self.srwind[0], stv=self.srwind[1] ) self.srw_ebw = winds.sr_wind(self, pbot=self.ebottom, ptop=elh, stu=self.srwind[0], stv=self.srwind[1] ) self.right_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[0], stv=self.srwind[1]) self.left_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[2], stv=self.srwind[3]) self.critical_angle = winds.critical_angle(self, stu=self.srwind[0], stv=self.srwind[1]) ## calculate mean srw self.srw_1km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p1km, stu=self.srwind[0], stv=self.srwind[1] )) self.srw_3km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p3km, stu=self.srwind[0], stv=self.srwind[1] )) self.srw_6km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p6km, stu=self.srwind[0], stv=self.srwind[1] )) self.srw_8km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p8km, stu=self.srwind[0], stv=self.srwind[1] )) self.srw_4_5km = utils.comp2vec(*winds.sr_wind(self, pbot=p4km, ptop=p5km, stu=self.srwind[0], stv=self.srwind[1] )) self.srw_lcl_el = utils.comp2vec(*winds.sr_wind(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres, stu=self.srwind[0], stv=self.srwind[1] )) # This is for the red, blue, and purple bars that appear on the SR Winds vs. Height plot self.srw_0_2km = winds.sr_wind(self, pbot=sfc, ptop=interp.pres(self, interp.to_msl(self, 2000.)), stu=self.srwind[0], stv=self.srwind[1]) self.srw_4_6km = winds.sr_wind(self, pbot=interp.pres(self, interp.to_msl(self, 4000.)), ptop=p6km, stu=self.srwind[0], stv=self.srwind[1]) self.srw_9_11km = winds.sr_wind(self, pbot=interp.pres(self, interp.to_msl(self, 9000.)), ptop=interp.pres(self, interp.to_msl(self, 11000.)), stu=self.srwind[0], stv=self.srwind[1]) ## calculate upshear and downshear self.upshear_downshear = winds.mbe_vectors(self) self.srh1km = winds.helicity(self, 0, 1000., stu=self.srwind[0], stv=self.srwind[1]) self.srh3km = winds.helicity(self, 0, 3000., stu=self.srwind[0], stv=self.srwind[1])
1050, 25) skew.plot_wind_barbs(ax2, p_less, u_less, v_less) srwind = params.bunkers_storm_motion(prof) gs.update(left=0.05, bottom=0.05, top=0.95, right=1, wspace=0.025) ######################### # Calculate indices to be shown. p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) p3km = interp.pres(prof, interp.to_msl(prof, 3000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) p8km = interp.pres(prof, interp.to_msl(prof, 8000.)) p9km = interp.pres(prof, interp.to_msl(prof, 9000.)) sfc = prof.pres[prof.sfc] sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) sfc_8km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p8km) sfc_9km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p9km) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) scp = params.scp(prof.mupcl.bplus, prof.right_esrh[0], prof.ebwspd) stp_cin = params.stp_cin(prof.mlpcl.bplus, prof.right_esrh[0], prof.ebwspd, prof.mlpcl.lclhght, prof.mlpcl.bminus) stp_fixed = params.stp_fixed( prof.sfcpcl.bplus, prof.sfcpcl.lclhght, srh1km[0], utils.comp2vec(prof.sfc_6km_shear[0], prof.sfc_6km_shear[1])[1]) ship = params.ship(prof) #########################
color='r', alpha=0.7, linestyle="None", marker="o", markersize=5, mew=0, label="right mover") # Explanation for red and blue dots. Put only 1 point in the legend entry. bunkerleg = hodo_ax.legend(handles=[bunkerL, bunkerR], fontsize=5, frameon=False, numpoints=1) # show Bunker left/right movers if 0-6km shear magnitude >= 20kts p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) sfc_6km_shear = winds.wind_shear(prof, pbot=prof.pres[prof.sfc], ptop=p6km) if utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] >= 20.: bunkerR.set_visible(True) bunkerL.set_visible(True) bunkerleg.set_visible(True) bunkerR.set_data(srwind[0], srwind[1]) # Update Bunker's Storm motion right mover bunkerL.set_data(srwind[2], srwind[3]) # Update Bunker's Storm motion left mover else: bunkerR.set_visible(False) bunkerL.set_visible(False) bunkerleg.set_visible(False) if debug: print("about to plot wind barbs")
# Update the hodograph on the Skew-T. # Draw the hodograph on the Skew-T. hodo_ax = myskewt.draw_hodo() hodo, AGL = myskewt.add_hodo(hodo_ax, prof) # Plot Bunker's Storm motion left mover as a blue dot bunkerL, = hodo_ax.plot([], [], color='b', alpha=0.7, linestyle="None", marker="o", markersize=5, mew=0, label="left mover") # Plot Bunker's Storm motion right mover as a red dot # The comma after bunkerR de-lists it. bunkerR, = hodo_ax.plot([], [], color='r', alpha=0.7, linestyle="None", marker="o", markersize=5, mew=0, label="right mover") # Explanation for red and blue dots. Put only 1 point in the legend entry. bunkerleg = hodo_ax.legend(handles=[bunkerL,bunkerR], fontsize=5, frameon=False, numpoints=1) # show Bunker left/right movers if 0-6km shear magnitude >= 20kts p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) sfc_6km_shear = winds.wind_shear(prof, pbot=prof.pres[prof.sfc], ptop=p6km) if utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] >= 20.: bunkerR.set_visible(True) bunkerL.set_visible(True) bunkerleg.set_visible(True) bunkerR.set_data(srwind[0], srwind[1]) # Update Bunker's Storm motion right mover bunkerL.set_data(srwind[2], srwind[3]) # Update Bunker's Storm motion left mover else: bunkerR.set_visible(False) bunkerL.set_visible(False) bunkerleg.set_visible(False) # Recreate stack of wind barbs s = [] bot=2000. # Space out wind barbs evenly on log axis.
# Draw the wind barbs axis and everything that comes with it. ax.xaxis.set_major_locator(MultipleLocator(10)) ax.set_xlim(-50, 50) ax2 = plt.subplot(gs[0:3, 2]) ax3 = plt.subplot(gs[3, 0:3]) skew.plot_wind_axes(ax2) skew.plot_wind_barbs(ax2, prof.pres, prof.u, prof.v) srwind = params.bunkers_storm_motion(prof) gs.update(left=0.05, bottom=0.05, top=0.95, right=1, wspace=0.025) # Calculate indices to be shown. More indices can be calculated here using the tutorial and reading the params module. p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) sfc = prof.pres[prof.sfc] sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) scp = params.scp(prof.mupcl.bplus, prof.right_esrh[0], prof.ebwspd) stp_cin = params.stp_cin(prof.mlpcl.bplus, prof.right_esrh[0], prof.ebwspd, prof.mlpcl.lclhght, prof.mlpcl.bminus) stp_fixed = params.stp_fixed( prof.sfcpcl.bplus, prof.sfcpcl.lclhght, srh1km[0], utils.comp2vec(prof.sfc_6km_shear[0], prof.sfc_6km_shear[1])[1]) ship = params.ship(prof) # A routine to perform the correct formatting when writing the indices out to the figure. def fmt(value, fmt='int'): if fmt == 'int':