def get_sars(self): ''' Function to get the SARS analogues from the hail and supercell databases. Requires calling get_kinematics() and get_parcels() first. Also calculates the significant hail parameter. Function returns nothing, but sets the following variables: self.matches - the matches from SARS HAIL self.ship - significant hail parameter self.supercell_matches - the matches from SARS SUPERCELL Parameters ---------- None Returns ------- None ''' sfc_6km_shear = utils.KTS2MS( utils.mag(self.sfc_6km_shear[0], self.sfc_6km_shear[1])) sfc_3km_shear = utils.KTS2MS( utils.mag(self.sfc_3km_shear[0], self.sfc_3km_shear[1])) sfc_9km_shear = utils.KTS2MS( utils.mag(self.sfc_9km_shear[0], self.sfc_9km_shear[1])) h500t = interp.temp(self, 500.) lapse_rate = params.lapse_rate(self, 700., 500., pres=True) srh3km = self.srh3km[0] srh1km = self.srh1km[0] mucape = self.mupcl.bplus mlcape = self.mlpcl.bplus mllcl = self.mlpcl.lclhght mumr = thermo.mixratio(self.mupcl.pres, self.mupcl.dwpc) self.ship = params.ship(self) ## Cambios para el hemisferio sur JP JP if self.latitude < 0: srh1km = -srh1km srh3km = -srh3km self.hail_database = 'sars_hail.txt' self.supercell_database = 'sars_supercell.txt' try: self.matches = hail(self.hail_database, mumr, mucape, h500t, lapse_rate, sfc_6km_shear, sfc_9km_shear, sfc_3km_shear, srh3km) except: self.matches = ([], [], 0, 0, 0) try: self.supercell_matches = supercell(self.supercell_database, mlcape, mllcl, h500t, lapse_rate, utils.MS2KTS(sfc_6km_shear), srh1km, utils.MS2KTS(sfc_3km_shear), utils.MS2KTS(sfc_9km_shear), srh3km) except Exception as e: self.supercell_matches = ([], [], 0, 0, 0)
def non_parcel_bunkers_motion_experimental(prof): ''' Compute the Bunkers Storm Motion for a Right Moving Supercell Parameters ---------- prof : profile object Profile Object Returns ------- rstu : number Right Storm Motion U-component (kts) rstv : number Right Storm Motion V-component (kts) lstu : number Left Storm Motion U-component (kts) lstv : number Left Storm Motion V-component (kts) ''' if prof.wdir.count() == 0: return ma.masked, ma.masked, ma.masked, ma.masked d = utils.MS2KTS(7.5) # Deviation value emperically derived as 7.5 m/s ## get the msl height of 500m, 5.5km, and 6.0km above the surface msl500m = interp.to_msl(prof, 500.) msl5500m = interp.to_msl(prof, 5500.) msl6000m = interp.to_msl(prof, 6000.) ## get the pressure of the surface, 500m, 5.5km, and 6.0km levels psfc = prof.pres[prof.sfc] p500m = interp.pres(prof, msl500m) p5500m = interp.pres(prof, msl5500m) p6000m = interp.pres(prof, msl6000m) ## sfc-500m Mean Wind mnu500m, mnv500m = mean_wind(prof, psfc, p500m) ## 5.5km-6.0km Mean Wind mnu5500m_6000m, mnv5500m_6000m = mean_wind(prof, p5500m, p6000m) # shear vector of the two mean winds shru = mnu5500m_6000m - mnu500m shrv = mnv5500m_6000m - mnv500m # SFC-6km Mean Wind mnu6, mnv6 = mean_wind(prof, psfc, p6000m) # Bunkers Right Motion tmp = d / utils.mag(shru, shrv) rstu = mnu6 + (tmp * shrv) rstv = mnv6 - (tmp * shru) lstu = mnu6 - (tmp * shrv) lstv = mnv6 + (tmp * shru) return rstu, rstv, lstu, lstv
def non_parcel_bunkers_motion(prof): ''' Compute the Bunkers Storm Motion for a Right Moving Supercell Inputs ------ prof : profile object Profile Object Returns ------- rstu : number Right Storm Motion U-component rstv : number Right Storm Motion V-component lstu : number Left Storm Motion U-component lstv : number Left Storm Motion V-component ''' d = utils.MS2KTS(7.5) # Deviation value emperically derived as 7.5 m/s msl6km = interp.to_msl(prof, 6000.) p6km = interp.pres(prof, msl6km) # SFC-6km Mean Wind mnu6, mnv6 = mean_wind_npw(prof, prof.pres[prof.sfc], p6km) # SFC-6km Shear Vector shru, shrv = wind_shear(prof, prof.pres[prof.sfc], p6km) # Bunkers Right Motion tmp = d / utils.mag(shru, shrv) # Cambios para el hemisferio sur JP JP if prof.latitude < 0: lstu = mnu6 + (tmp * shrv) lstv = mnv6 - (tmp * shru) rstu = mnu6 - (tmp * shrv) rstv = mnv6 + (tmp * shru) else: rstu = mnu6 + (tmp * shrv) rstv = mnv6 - (tmp * shru) lstu = mnu6 - (tmp * shrv) lstv = mnv6 + (tmp * shru) return rstu, rstv, lstu, lstv
def parseCLS(sfile): ## read in the file data = np.array([l.strip() for l in sfile.split('\n')]) latitude = float(data[3].split(',')[5]) longitude = float(data[3].split(',')[4]) ## necessary index points start_idx = 15 finish_idx = len(data) ## put it all together for StringIO full_data = '\n'.join(data[start_idx:finish_idx][:]) sound_data = StringIO(full_data) ## read the data into arrays data = np.genfromtxt(sound_data) clean_data = [] for i in data: if i[1] != 9999 and i[2] != 999 and i[3] != 999 and i[7] != 999 and i[ 8] != 999 and i[14] != 99999: clean_data.append(i) p = np.array([i[1] for i in clean_data]) h = np.array([i[14] for i in clean_data]) T = np.array([i[2] for i in clean_data]) Td = np.array([i[3] for i in clean_data]) wdir = np.array([i[8] for i in clean_data]) wspd = np.array([i[7] for i in clean_data]) wspd = utils.MS2KTS(wspd) wdir[ wdir == 360] = 0. # Some wind directions are 360. Like in /glade/p/work/ahijevyc/GFS/Joaquin/g132325165.frd max_points = 250 s = p.size / max_points if s == 0: s = 1 print("stride=", s) return p[::s], h[::s], T[::s], Td[:: s], wdir[:: s], wspd[:: s], latitude, longitude
def non_parcel_bunkers_motion(prof): ''' Compute the Bunkers Storm Motion for a Right Moving Supercell Parameters ---------- prof : profile object Profile Object Returns ------- rstu : number Right Storm Motion U-component (kts) rstv : number Right Storm Motion V-component (kts) lstu : number Left Storm Motion U-component (kts) lstv : number Left Storm Motion V-component (kts) ''' if prof.wdir.count() == 0: return ma.masked, ma.masked, ma.masked, ma.masked d = utils.MS2KTS(7.5) # Deviation value emperically derived as 7.5 m/s msl6km = interp.to_msl(prof, 6000.) p6km = interp.pres(prof, msl6km) # SFC-6km Mean Wind mnu6, mnv6 = mean_wind_npw(prof, prof.pres[prof.sfc], p6km) # SFC-6km Shear Vector shru, shrv = wind_shear(prof, prof.pres[prof.sfc], p6km) # Bunkers Right Motion tmp = d / utils.mag(shru, shrv) rstu = mnu6 + (tmp * shrv) rstv = mnv6 - (tmp * shru) lstu = mnu6 - (tmp * shrv) lstv = mnv6 + (tmp * shru) return rstu, rstv, lstu, lstv
''' Create the Sounding (Profile) Object '''
def _parse(self): """ Parse the netCDF file according to the variable naming and dimmensional conventions of the WRF-ARW. """ ## open the file and also store the lat/lon of the selected point file_data = self._downloadFile() gridx = self._file_name[1] gridy = self._file_name[2] ## calculate the nearest grid point to the map point idx = self._find_nearest_point(file_data, gridx, gridy) ## check to see if this is a 4D netCDF4 that includes all available times. ## If it does, open and compute the variables as 4D variables if len(file_data.variables["T"][:].shape) == 4: ## read in the data from the WRF file and conduct necessary processing theta = file_data.variables["T"][:, :, idx[0], idx[1]] + 300.0 qvapr = file_data.variables["QVAPOR"][:, :, idx[0], idx[1]] * 10**3 #g/kg mpres = (file_data.variables["P"][:, :, idx[0], idx[1]] + file_data.variables["PB"][:, :, idx[0], idx[1]]) * .01 mhght = file_data.variables[ "PH"][:, :, idx[0], idx[1]] + file_data.variables["PHB"][:, :, idx[0], idx[1]] / G ## unstagger the height grid mhght = (mhght[:, :-1, :, :] + mhght[:, 1:, :, :]) / 2. muwin = file_data.variables["U"][:, :, idx[0], idx[1]] mvwin = file_data.variables["V"][:, :, idx[0], idx[1]] ## convert the potential temperature to air temperature mtmpc = thermo.theta(1000.0, theta - 273.15, p2=mpres) ## convert the mixing ratio to dewpoint mdwpc = thermo.temp_at_mixrat(qvapr, mpres) ## convert the grid relative wind to earth relative U = muwin * file_data.variables['COSALPHA'][ 0, idx[0], idx[1]] - mvwin * file_data.variables['SINALPHA'][ 0, idx[0], idx[1]] V = mvwin * file_data.variables['COSALPHA'][ 0, idx[0], idx[1]] + muwin * file_data.variables['SINALPHA'][ 0, idx[0], idx[1]] ## convert from m/s to kts muwin = utils.MS2KTS(U) mvwin = utils.MS2KTS(V) ## if the data is not 4D, then it must be assumed that this is a file containing only a single time else: ## read in the data from the WRF file and conduct necessary processing theta = file_data.variables["T"][:, idx[0], idx[1]] + 300.0 qvapr = file_data.variables["QVAPOR"][:, idx[0], idx[1]] * 10**3 #g/kg mpres = (file_data.variables["P"][:, idx[0], idx[1]] + file_data.variables["PB"][:, idx[0], idx[1]]) * .01 mhght = file_data.variables["PH"][:, idx[0], idx[1]] + file_data.variables[ "PHB"][:, idx[0], idx[1]] / G ## unstagger the height grid mhght = (mhght[:-1, :, :] + mhght[1:, :, :]) / 2. muwin = file_data.variables["U"][:, idx[0], idx[1]] mvwin = file_data.variables["V"][:, idx[0], idx[1]] ## convert the potential temperature to air temperature mtmpc = thermo.theta(1000.0, theta - 273.15, p2=mpres) ## convert the mixing ratio to dewpoint mdwpc = thermo.temp_at_mixrat(qvapr, mpres) ## convert the grid relative wind to earth relative U = muwin * file_data.variables['COSALPHA'][ 0, idx[0], idx[1]] - mvwin * file_data.variables['SINALPHA'][ 0, idx[0], idx[1]] V = mvwin * file_data.variables['COSALPHA'][ 0, idx[0], idx[1]] + muwin * file_data.variables['SINALPHA'][ 0, idx[0], idx[1]] ## convert from m/s to kts muwin = utils.MS2KTS(U) mvwin = utils.MS2KTS(V) ## get the model start time of the file inittime = dattim.datetime.strptime(str(file_data.START_DATE), '%Y-%m-%d_%H:%M:%S') profiles = [] dates = [] ## loop over the available times for i in range(file_data.variables["T"][:].shape[0]): ## make sure the arrays are 1D prof_pres = mpres[i].flatten() prof_hght = mhght[i].flatten() prof_tmpc = mtmpc[i].flatten() prof_dwpc = mdwpc[i].flatten() prof_uwin = muwin[i].flatten() prof_vwin = mvwin[i].flatten() ## compute the time of the profile try: delta = dattim.timedelta( minutes=int(file_data.variables["XTIME"][i])) curtime = inittime + delta except KeyError: var = ''.join( np.asarray(file_data.variables['Times'][i], dtype=str)) curtime = dattim.datetime.strptime(var, '%Y-%m-%d_%H:%M:%S') date_obj = curtime ## construct the profile object prof = profile.create_profile(profile="raw", pres=prof_pres, hght=prof_hght, tmpc=prof_tmpc, dwpc=prof_dwpc, u=prof_uwin, v=prof_vwin, location=str(gridx) + "," + str(gridy), date=date_obj, missing=-999.0, latitude=gridy, strictQC=False) ## append the dates and profiles profiles.append(prof) dates.append(date_obj) ## create a profile collection - dictionary has no key since this ## is not an ensemble model prof_coll = prof_collection.ProfCollection({'': profiles}, dates) return prof_coll