def get_severe(self): ''' Function to calculate special severe weather indices. Requires calling get_parcels() and get_kinematics(). Returns nothing, but sets the following variables: self.right_stp_fixed - fixed layer significant tornado parameter (computed with SRH relative to the right-mover vector) self.left_stp_fixed - fixed layer significant tornado parameter (computed with SRH relative to the left-mover vector) self.right_stp_cin - effective layer significant tornado parameter (computed with SRH relative to the right-mover vector) self.left_stp_cin - effective layer significant tornado parameter (computed with SRH relative to the left-mover vector) self.right_scp - right moving supercell composite parameter self.left_scp - left moving supercell composite parameter Parameters ---------- None Returns ------- None ''' wspd = utils.mag(self.sfc_6km_shear[0], self.sfc_6km_shear[1]) self.right_stp_fixed = params.stp_fixed(self.sfcpcl.bplus, self.sfcpcl.lclhght, self.right_srh1km[0], utils.KTS2MS(wspd)) self.left_stp_fixed = params.stp_fixed(self.sfcpcl.bplus, self.sfcpcl.lclhght, self.left_srh1km[0], utils.KTS2MS(wspd)) self.sherbe = params.sherb(self, effective=True) if self.etop is np.ma.masked or self.ebottom is np.ma.masked: self.right_scp = 0.0; self.left_scp = 0.0 self.right_stp_cin = 0.0; self.left_stp_cin = 0.0 else: self.right_scp = params.scp( self.mupcl.bplus, self.right_esrh[0], utils.KTS2MS(self.ebwspd)) self.left_scp = params.scp( self.mupcl.bplus, self.left_esrh[0], utils.KTS2MS(self.ebwspd)) right_esrh = self.right_esrh[0] left_esrh = self.left_esrh[0] if self.latitude < 0: right_esrh = -right_esrh left_esrh = -left_esrh self.right_stp_cin = params.stp_cin(self.mlpcl.bplus, right_esrh, utils.KTS2MS(self.ebwspd), self.mlpcl.lclhght, self.mlpcl.bminus) self.left_stp_cin = params.stp_cin(self.mlpcl.bplus, left_esrh, utils.KTS2MS(self.ebwspd), self.mlpcl.lclhght, self.mlpcl.bminus) if self.latitude < 0: self.right_stp_cin = -self.right_stp_cin self.left_stp_cin = -self.left_stp_cin if self.latitude < 0: self.stp_fixed = self.left_stp_fixed self.stp_cin = self.left_stp_cin self.scp = self.left_scp else: self.stp_fixed = self.right_stp_fixed self.stp_cin = self.right_stp_cin self.scp = self.right_scp
def get_severe(self): ''' Function to calculate special severe weather indices. Requires calling get_parcels() and get_kinematics(). Returns nothing, but sets the following variables: self.stp_fixed - fixed layer significant tornado parameter self.stp_cin - effective layer significant tornado parameter self.right_scp - right moving supercell composite parameter self.left_scp - left moving supercell composite parameter Parameters ---------- None Returns ------- None ''' wspd = utils.mag(self.sfc_6km_shear[0], self.sfc_6km_shear[1]) self.stp_fixed = params.stp_fixed(self.sfcpcl.bplus, self.sfcpcl.lclhght, self.srh1km[0], utils.KTS2MS(wspd)) if self.etop is np.ma.masked or self.ebottom is np.ma.masked: self.right_scp = 0.0; self.left_scp = 0.0 self.stp_cin = 0.0 else: self.right_scp = params.scp( self.mupcl.bplus, self.right_esrh[0], utils.KTS2MS(self.ebwspd)) self.left_scp = params.scp( self.mupcl.bplus, self.left_esrh[0], utils.KTS2MS(self.ebwspd)) self.stp_cin = params.stp_cin(self.mlpcl.bplus, self.right_esrh[0], utils.KTS2MS(self.ebwspd), self.mlpcl.lclhght, self.mlpcl.bminus)
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)
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, etop_hght, stu=srwind[0], stv=srwind[1]) ebwd = winds.wind_shear(prof, pbot=eff_inflow[0], ptop=eff_inflow[1]) ebwspd = utils.mag(ebwd[0], ebwd[1]) scp = params.scp(mupcl.bplus, effective_srh[0], ebwspd) stp_cin = params.stp_cin(mlpcl.bplus, effective_srh[0], ebwspd, mlpcl.lclhght, mlpcl.bminus)