def compare_potential_temp(sounding, date): theta1 = thermo.theta1(K=sounding.TE, hPa=sounding.P) theta2 = thermo.theta2(K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR / 1000) thetaeq1 = thermo.theta_equiv1(K=sounding.TE, hPa=sounding.P) thetaeq2 = thermo.theta_equiv2(K=sounding.TE, hPa=sounding.P, relh=sounding.RH, mixing_ratio=sounding.MR / 1000) foo = pd.DataFrame({ 'theta1': theta1, 'thetaeq1': thetaeq1, 'theta2': theta2, 'thetaeq2': thetaeq2 }) y = foo.index.values fig, ax = plt.subplots(figsize=(8.5, 11)) ln1 = ax.plot(theta1, y, label='theta=f(temp,press) - W&H') ln2 = ax.plot(theta2, y, label='theta=f(temp,press, w) - Bolton 1980') ln3 = ax.plot(thetaeq1, y, label='thetaeq=f(temp,press,ws) - W&H') ln4 = ax.plot(thetaeq2, y, label='thetaeq=f(temp,press, w, rh) - Bolton 1980') ax.set_xlim([280, 320]) ax.set_ylim([0, 5000]) ax.set_xlabel('Temperature [K]') ax.set_ylabel('Altitude [m]') ax2 = ax.twiny() ln5 = ax2.plot(sounding.MR, y, sns.xkcd_rgb["amber"], label='mixing ratio') ax2.set_xlim([0, 8]) ax2.set_ylim([0, 5000]) ax2.grid(False) ax2.set_xlabel('Mixing ratio [g kg-1]') ax3 = ax.twiny() ln6 = ax3.plot(sounding.RH, y, sns.xkcd_rgb["plum purple"], label='relative humidity') ax3.set_xlim([0, 100]) ax3.set_ylim([0, 5000]) ax3.grid(False) ax3.set_xlabel('Relative humidity [%]') ax3.xaxis.set_label_coords(0.5, 1.07) ax3.tick_params(direction='out', pad=35) lns = ln1 + ln2 + ln3 + ln4 + ln5 + ln6 labs = [l.get_label() for l in lns] ax3.legend(lns, labs, loc=0) plt.subplots_adjust(bottom=0.05, top=0.89) datestr = date.strftime('%Y%m%d_%H%M%S') plt.title('Comparison of Potential Temperature BBY sounding ' + datestr, y=0.99) plt.draw()
def thetaeq(self, filled=True, cmap=None, **kwargs): self.initialize_plot() self.level = kwargs['level']*100 clevels = kwargs['clevels'] t_arrays = read_files(self, 'temperature') # [C] q_arrays = read_files(self, 'sphum') # [kg/kg] rh_arrays = read_files(self, 'relhumid') press = np.zeros(rh_arrays[0].shape)+kwargs['level'] # [hPa] X, Y = np.meshgrid(self.lons, self.lats) self.series['thetaeq'] = [] for i in range(len(self.dates)): mixr = thermo.mixing_ratio(specific_humidity=q_arrays[i]) theta = thermo.theta_equiv2(C=t_arrays[i], hPa=press, mixing_ratio=mixr, relh=rh_arrays[i]) val = get_value_at(-123., 38.5, theta, self) # closest to BBY self.series['thetaeq'].append(val) if filled: cf = self.axes[i].contourf(X, Y, theta, clevels, cmap=cmap) try: self.axes[i].cax.colorbar(cf, ticks=clevels[::4]) except AttributeError: add_colorbar(self.axes[i], cf) else: cs = self.axes[i].contour(X, Y, theta, clevels, colors='r', linewidths=0.6) clabels = self.axes[i].clabel(cs, clevels[::5], fontweight='bold', fontsize=10, fmt='%1.0f') [txt.set_color('r') for txt in clabels] set_limits(self, i) self.add_date(i) txt = 'Equivalent Potential Temperature [K] at {} hPa\n' self.title += txt.format(str(self.level/100))
def get_meteo(self,start_time, end_time): start = self.df.index.searchsorted(start_time) end = self.df.index.searchsorted(end_time) # print meteo.columns.tolist() cols=[0,1,2,3,6,7,8,9,13,14,15] meteo=self.df.ix[start:end,cols].copy() ''' pressure ''' pres = meteo.apres.values ''' add relative humidity ''' temp = meteo.atemp.values dewp = meteo.dewp.values relh = thermo.relative_humidity(C=temp,Dewp=dewp) # [%] meteo.loc[:,'relh'] = pd.Series(relh,index=meteo.index) ''' mixing ratio ''' satmixr=thermo.sat_mix_ratio(C=temp,hPa=pres) mixr=relh*satmixr/100 ''' add theta ''' theta = thermo.theta2(C=temp,hPa=pres,mixing_ratio=mixr) meteo.loc[:,'theta'] = pd.Series(theta,index=meteo.index) ''' add thetav ''' thetav = thermo.virtual_temperature(theta=theta,mixing_ratio=mixr) meteo.loc[:,'thetav'] = pd.Series(thetav,index=meteo.index) ''' add thetae ''' thetaeq = thermo.theta_equiv2(C=temp,hPa=pres, mixing_ratio=mixr,relh=relh) meteo.loc[:,'thetaeq'] = pd.Series(thetaeq,index=meteo.index) return meteo
def air_density(): Rd = 287. # [J K-1 kg-1] # density values do not vary significantly Tv = tm.virtual_temperature(C=stemp, mixing_ratio=smixr / 1000.) + 273.15 air_density1 = (spress * 100.) / (Rd * Tv) Tv = tm.virtual_temperature(C=mtemp, mixing_ratio=smixr / 1000.) + 273.15 air_density2 = (mpress * 100.) / (Rd * Tv)
def air_density(): Rd = 287. # [J K-1 kg-1] # density values do not vary significantly Tv = tm.virtual_temperature(C=stemp, mixing_ratio=smixr/1000.)+273.15 air_density1 = (spress*100.)/(Rd*Tv) Tv = tm.virtual_temperature(C=mtemp, mixing_ratio=smixr/1000.)+273.15 air_density2 = (mpress*100.)/(Rd*Tv)
def compare_potential_temp(sounding, date): theta1 = thermo.theta1(K=sounding.TE, hPa=sounding.P) theta2 = thermo.theta2( K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR/1000) thetaeq1 = thermo.theta_equiv1(K=sounding.TE, hPa=sounding.P) thetaeq2 = thermo.theta_equiv2(K=sounding.TE, hPa=sounding.P, relh=sounding.RH, mixing_ratio=sounding.MR/1000) foo = pd.DataFrame( {'theta1': theta1, 'thetaeq1': thetaeq1, 'theta2': theta2, 'thetaeq2': thetaeq2}) y = foo.index.values fig, ax = plt.subplots(figsize=(8.5, 11)) ln1 = ax.plot(theta1, y, label='theta=f(temp,press) - W&H') ln2 = ax.plot(theta2, y, label='theta=f(temp,press, w) - Bolton 1980') ln3 = ax.plot(thetaeq1, y, label='thetaeq=f(temp,press,ws) - W&H') ln4 = ax.plot( thetaeq2, y, label='thetaeq=f(temp,press, w, rh) - Bolton 1980') ax.set_xlim([280, 320]) ax.set_ylim([0, 5000]) ax.set_xlabel('Temperature [K]') ax.set_ylabel('Altitude [m]') ax2 = ax.twiny() ln5 = ax2.plot(sounding.MR, y, sns.xkcd_rgb["amber"], label='mixing ratio') ax2.set_xlim([0, 8]) ax2.set_ylim([0, 5000]) ax2.grid(False) ax2.set_xlabel('Mixing ratio [g kg-1]') ax3 = ax.twiny() ln6 = ax3.plot( sounding.RH, y, sns.xkcd_rgb["plum purple"], label='relative humidity') ax3.set_xlim([0, 100]) ax3.set_ylim([0, 5000]) ax3.grid(False) ax3.set_xlabel('Relative humidity [%]') ax3.xaxis.set_label_coords(0.5, 1.07) ax3.tick_params(direction='out', pad=35) lns = ln1+ln2+ln3+ln4+ln5+ln6 labs = [l.get_label() for l in lns] ax3.legend(lns, labs, loc=0) plt.subplots_adjust(bottom=0.05, top=0.89) datestr = date.strftime('%Y%m%d_%H%M%S') plt.title( 'Comparison of Potential Temperature BBY sounding '+datestr, y=0.99) plt.draw()
def theta(self, **kwargs): self.initialize_plot() self.level = kwargs['level']*100 cmap = kwargs['cmap'] t_arrays = read_files(self, 'temperature') # [C] q_arrays = read_files(self, 'sphum') # [kg/kg] X, Y = np.meshgrid(self.lons, self.lats) clevels = kwargs['clevels'] self.series['theta'] = [] for i in range(len(self.dates)): mixr = thermo.mixing_ratio(specific_humidity=q_arrays[i]) press = np.zeros(mixr.shape)+kwargs['level'] # [hPa] theta = thermo.theta2(C=t_arrays[i], hPa=press, mixing_ratio=mixr) val = get_value_at(-123., 38.5, theta, self) # closest to BBY self.series['theta'].append(val) cf = self.axes[i].contourf(X, Y, theta, clevels, cmap=cmap) self.axes[i].cax.colorbar(cf, ticks=clevels[::4]) set_limits(self, i) self.add_date(i) self.l1 = 'Potential Temperature [K] at ' + \ str(self.level/100) + ' hPa'
def parse_sounding(file_sound): col_names = get_var_names(file_sound) # col_units = get_var_units(file_sound) ''' read tabular file ''' raw_sounding = pd.read_table(file_sound, skiprows=36, header=None) raw_sounding.drop(19, axis=1, inplace=True) raw_sounding.columns = col_names sounding = raw_sounding[ ['Height', 'TE', 'TD', 'RH', 'u', 'v', 'P', 'MR', 'DD']] sounding.units = {'Height': 'm', 'TE': 'K', 'TD': 'K', 'RH': '%', 'u': 'm s-1', 'v': 'm s-1', 'P': 'hPa', 'MR': 'g kg-1'} ''' replace nan values ''' nan_value = -32768.00 sounding = sounding.applymap(lambda x: np.nan if x == nan_value else x) ''' QC soundings that include descening trayectories; criteria is 3 consecutive values descending ''' sign = np.sign(np.diff(sounding['Height'])) rep = find_repeats(sign.tolist(), -1, 3) try: lastgood = np.where(rep)[0][0]-1 sounding = sounding.ix[0:lastgood] except IndexError: ''' all good''' pass ''' set index ''' sounding = sounding.set_index('Height') ''' QC ''' sounding = sounding.groupby(sounding.index).first() sounding.dropna(how='all', inplace=True) sounding.RH = sounding.RH.apply(lambda x: 100 if x > 100 else x) u_nans = nan_fraction(sounding.u) v_nans = nan_fraction(sounding.v) if u_nans > 0. or v_nans > 0.: sounding.u.interpolate(method='linear', inplace=True) sounding.v.interpolate(method='linear', inplace=True) rh_nans = nan_fraction(sounding.RH) td_nans = nan_fraction(sounding.TD) mr_nans = nan_fraction(sounding.MR) if rh_nans < 5. and td_nans > 50. and mr_nans > 50.: sat_mixr = tm.sat_mix_ratio(K=sounding.TE, hPa=sounding.P) mixr = (sounding.RH/100)*sat_mixr*1000 sounding.loc[:, 'MR'] = mixr # [g kg-1] ''' add potential temperature ''' theta = tm.theta2( K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR/1000) thetaeq = tm.theta_equiv2(K=sounding.TE, hPa=sounding.P, relh=sounding.RH, mixing_ratio=sounding.MR/1000) sounding.loc[:, 'theta'] = pd.Series(theta, index=sounding.index) sounding.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=sounding.index) ''' add Brunt-Vaisala frequency ''' hgt = sounding.index.values bvf_dry = tm.bv_freq_dry(theta=sounding.theta, agl_m=hgt, depth_m=100, centered=True) bvf_moist = tm.bv_freq_moist(K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR/1000, agl_m=hgt, depth_m=100, centered=True) sounding = pd.merge( sounding, bvf_dry, left_index=True, right_index=True, how='outer') sounding = pd.merge( sounding, bvf_moist, left_index=True, right_index=True, how='outer') ''' interpolate between layer-averaged values ''' sounding.bvf_dry.interpolate(method='linear', inplace=True) sounding.bvf_moist.interpolate(method='linear', inplace=True) sounding.loc[sounding.MR.isnull(), 'bvf_dry'] = np.nan sounding.loc[sounding.MR.isnull(), 'bvf_moist'] = np.nan ''' NOTE: if sounding hgt jumps from 12 to 53m then 12m bvf values are NaN since there are no data between 12 and 53m to calculate a layer-based value. ''' return sounding
def parse_sounding2(file_sound): ''' This version make a resample of vertical gates and uses make_layer2 in bvf calculations (Thermodyn module) ''' col_names = get_var_names(file_sound) # col_units = get_var_units(file_sound) ''' read tabular file ''' raw_sounding = pd.read_table(file_sound, skiprows=36, header=None) raw_sounding.drop(19, axis=1, inplace=True) raw_sounding.columns = col_names sounding = raw_sounding[ ['Height', 'TE', 'TD', 'RH', 'u', 'v', 'P', 'MR', 'DD']] sounding.units = {'Height': 'm', 'TE': 'K', 'TD': 'K', 'RH': '%', 'u': 'm s-1', 'v': 'm s-1', 'P': 'hPa', 'MR': 'g kg-1'} ''' replace nan values ''' nan_value = -32768.00 sounding = sounding.applymap(lambda x: np.nan if x == nan_value else x) ''' QC soundings that include descening trayectories; criteria is 3 consecutive values descending ''' sign = np.sign(np.diff(sounding['Height'])) rep = find_repeats(sign.tolist(), -1, 3) try: lastgood = np.where(rep)[0][0]-1 sounding = sounding.ix[0:lastgood] except IndexError: ''' all good''' pass # print sounding ''' resample to constant height values ''' resamp = 2 # [m] sounding = sounding.set_index('Height') hgt = sounding.index.values[-1] resample = np.arange(10, hgt, resamp) soundres = sounding.loc[resample] soundres.iloc[0] = sounding.iloc[0] # copy first value soundres.iloc[-1] = sounding.iloc[-1] # copy last value soundres.interpolate( method='linear', inplace=True, limit=80, limit_direction='backward') soundres = soundres.reset_index().drop_duplicates( subset='Height', keep='first') soundres = soundres.set_index('Height') ''' QC ''' soundres.RH = soundres.RH.apply(lambda x: 100 if x > 100 else x) rh_nans = nan_fraction(soundres.RH) # [%] td_nans = nan_fraction(soundres.TD) # [%] mr_nans = nan_fraction(soundres.MR) # [%] if rh_nans < 5. and td_nans > 50. and mr_nans > 50.: sat_mixr = tm.sat_mix_ratio(K=soundres.TE, hPa=soundres.P) mixr = (soundres.RH/100.)*sat_mixr*1000 soundres.loc[:, 'MR'] = mixr # [g kg-1] ''' add potential temperature ''' theta = tm.theta2(K=soundres.TE, hPa=soundres.P, mixing_ratio=soundres.MR/1000) thetaeq = tm.theta_equiv2(K=soundres.TE, hPa=soundres.P, relh=soundres.RH, mixing_ratio=soundres.MR/1000) soundres.loc[:, 'theta'] = pd.Series(theta, index=soundres.index) soundres.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=soundres.index) ''' add Brunt-Vaisala frequency ''' hgt = soundres.index.values depth = 100 # [m] bvf_dry = tm.bv_freq_dry(theta=soundres.theta, agl_m=hgt, depth_m=depth) bvf_moist = tm.bv_freq_moist(K=soundres.TE, hPa=soundres.P, mixing_ratio=soundres.MR/1000, agl_m=hgt, depth_m=depth) soundres = pd.merge( soundres, bvf_dry, left_index=True, right_index=True, how='outer') soundres = pd.merge( soundres, bvf_moist, left_index=True, right_index=True, how='outer') ''' interpolate between layer-averaged values ''' soundres.bvf_dry.interpolate(method='cubic', inplace=True) soundres.bvf_moist.interpolate(method='cubic', inplace=True) return soundres
def plot_thermo(**kwargs): hgt = kwargs['hgt'] #[hPa] pres = kwargs['press'] #[hPa] TE = kwargs['temp'] # [C] TD = kwargs['dewp'] # [C] U = kwargs['u'] # [m s-1] V = kwargs['v'] # [m s-1] date = kwargs['date'] loc = kwargs['loc'] theta = kwargs['theta'] thetaeq = kwargs['thetaeq'] BVFd = kwargs['bvf_dry'] BVFm = kwargs['bvf_moist'] hgt_lim = kwargs['top'] relh = thermo.relative_humidity(C=TE, Dewp=TD) sat_mixr = thermo.sat_mix_ratio(C=TD, hPa=pres) mixr = relh * sat_mixr / 100. fig, ax = plt.subplots(1, 5, sharey=True, figsize=(11, 8.5)) n = 0 ax[n].plot(TE, hgt, label='Temp') ax[n].plot(TD, hgt, label='Dewp') ax[n].legend() ax[n].set_xlim([-30, 20]) ax[n].set_ylim([0, hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('T [C]') ax[n].set_ylabel('Altitude [m]') n = 1 ln1 = ax[n].plot(mixr * 1000., hgt, label='mixr') ax[n].set_xlim([0, 8]) ax[n].set_ylim([0, hgt_lim]) add_minor_grid(ax[n]) for label in ax[n].xaxis.get_ticklabels()[::2]: label.set_visible(False) ax[n].set_xlabel('MR [g kg-1]') axt = ax[n].twiny() ln2 = axt.plot(relh, hgt, 'g', label='relh') axt.set_xlim([0, 100]) axt.set_ylim([0, hgt_lim]) axt.set_xlabel('RH [%]') axt.xaxis.set_label_coords(0.5, 1.04) axt.grid(False) lns = ln1 + ln2 labs = [l.get_label() for l in lns] axt.legend(lns, labs, loc=0) n = 2 ax[n].plot(theta, hgt, label='Theta') ax[n].plot(thetaeq, hgt, label='ThetaEq') ax[n].legend() ax[n].set_xlim([280, 320]) ax[n].set_ylim([0, hgt_lim]) add_minor_grid(ax[n]) for label in ax[n].xaxis.get_ticklabels()[::2]: label.set_visible(False) ax[n].set_xlabel('Theta [K]') n = 3 ax[n].plot(U, hgt, label='u') ax[n].plot(V, hgt, label='v') ax[n].axvline(x=0, linestyle=':', color='r') ax[n].legend() ax[n].set_xlim([-10, 40]) ax[n].set_ylim([0, hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('WS [ms-1]') n = 4 ax[n].plot(BVFd * 10000., hgt, label='dry') ax[n].plot(BVFm * 10000., hgt, label='moist') ax[n].axvline(x=0, linestyle=':', color='r') ax[n].legend(loc=2) ax[n].set_xlim([-6, 6]) ax[n].set_ylim([0, hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('BVF (x10^-4) [s-1]') l1 = 'Sounding from NOAA P3' l2 = '\nIni: ' + date[0].strftime('%Y-%b-%d %H:%M:%S UTC') l3 = '\nEnd: ' + date[1].strftime('%Y-%b-%d %H:%M:%S UTC') l4 = '\nLat: ' + '{:.2f}'.format(loc[0]) + ' Lon: ' + '{:.2f}'.format( loc[1]) plt.suptitle(l1 + l2 + l3 + l4, horizontalalignment='right', x=0.9) plt.subplots_adjust(bottom=0.06, top=0.89) plt.draw()
def parse_surface_met(file_met, index_field=None, name_field=None, locelevation=None): from scipy import stats ''' Process surface meteorological files with .met extension Output dataframe assumes: - Each file is a 24h period observation - Frequency of observation is constant ''' casename = file_met.split('/')[-2] station_id = file_met.split('/')[-1][:3] usr_case = str(int(casename[-2:])) if usr_case in ['1', '2']: index_field = { 'bby': [3, 4, 10, 5, 6, 11, 13], 'czc': [3, 4, 10, 5, 6, 11, 13] } elif usr_case in ['3', '4', '5', '6', '7']: index_field = { 'bby': [3, 5, 8, 10, 12, 17, 26], 'czc': [3, 4, 5, 6, 8, 13, 22] } else: index_field = { 'bby': [3, 4, 5, 6, 8, 13, 15], 'czc': [3, 4, 5, 6, 8, 13, 15], 'frs': [3, 4, 5, 6, 8, 13, 15] } elev = {'bby': 15, 'czc': 462, 'frs': 45} name_field = ['press', 'temp', 'rh', 'wspd', 'wdir', 'precip', 'mixr'] index_field = index_field[station_id] locelevation = elev[station_id] ''' read the csv file ''' raw_dframe = pd.read_csv(file_met, header=None) ''' parse date columns into a single date col ''' dates_col = [0, 1, 2] raw_dates = raw_dframe.ix[:, dates_col] raw_dates.columns = ['Y', 'j', 'HHMM'] raw_dates['HHMM'] = raw_dates['HHMM'].apply(lambda x: '{0:0>4}'.format(x)) raw_dates = raw_dates.apply(lambda x: '%s %s %s' % (x['Y'], x['j'], x['HHMM']), axis=1) dates_fmt = '%Y %j %H%M' dates = raw_dates.apply(lambda x: datetime.strptime(x, dates_fmt)) ''' make meteo df, assign datetime index, and name columns ''' meteo = raw_dframe.ix[:, index_field] meteo.index = dates meteo.columns = name_field ''' create a dataframe with regular and continuous 24h period time index (this works as a QC for time gaps) ''' nano = 1000000000 time_diff = np.diff(meteo.index) sample_freq = (stats.mode(time_diff)[0][0] / nano).astype(int) # [seconds] fidx = meteo.index[0] # (start date for dataframe) fidx_str = pd.to_datetime(fidx.year * 10000 + fidx.month * 100 + fidx.day, format='%Y%m%d') periods = (24 * 60 * 60) / sample_freq ts = pd.date_range(fidx_str, periods=periods, freq=str(sample_freq) + 's') nanarray = np.empty((periods, 1)) nanarray[:] = np.nan df = pd.DataFrame(nanarray, index=ts) meteo = df.join(meteo, how='outer') meteo.drop(0, axis=1, inplace=True) ''' make field with hourly acum precip ''' hour = pd.TimeGrouper('H') preciph = meteo.precip.groupby(hour).sum() meteo = meteo.join(preciph, how='outer', rsuffix='h') ''' add thermodynamics ''' theta = tm.theta1(C=meteo.temp, hPa=meteo.press) thetaeq = tm.theta_equiv1(C=meteo.temp, hPa=meteo.press) meteo.loc[:, 'theta'] = pd.Series(theta, index=meteo.index) meteo.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=meteo.index) ''' add sea level pressure ''' Tv = tm.virtual_temperature(C=meteo.temp, mixing_ratio=meteo.mixr / 1000.) slp = tm.sea_level_press(K=Tv + 273.15, Pa=meteo.press * 100, m=locelevation) meteo.loc[:, 'sea_levp'] = slp ''' assign metadata (prototype, not really used) ''' units = { 'press': 'mb', 'temp': 'C', 'rh': '%', 'wspd': 'm s-1', 'wdir': 'deg', 'precip': 'mm', 'mixr': 'g kg-1' } agl = { 'press': 'NaN', 'temp': '10 m', 'rh': '10 m', 'wspd': 'NaN', 'wdir': 'NaN', 'precip': 'NaN', 'mixr': 'NaN' } for n in name_field: meteo[n].units = units[n] meteo[n].agl = agl[n] meteo[n].nan = -9999.999 meteo[n].sampling_freq = '2 minute' return meteo
def parse_sounding(file_sound): col_names = get_var_names(file_sound) # col_units = get_var_units(file_sound) ''' read tabular file ''' raw_sounding = pd.read_table(file_sound, skiprows=36, header=None) raw_sounding.drop(19, axis=1, inplace=True) raw_sounding.columns = col_names sounding = raw_sounding[[ 'Height', 'TE', 'TD', 'RH', 'u', 'v', 'P', 'MR', 'DD' ]] sounding.units = { 'Height': 'm', 'TE': 'K', 'TD': 'K', 'RH': '%', 'u': 'm s-1', 'v': 'm s-1', 'P': 'hPa', 'MR': 'g kg-1' } ''' replace nan values ''' nan_value = -32768.00 sounding = sounding.applymap(lambda x: np.nan if x == nan_value else x) ''' QC soundings that include descening trayectories; criteria is 3 consecutive values descending ''' sign = np.sign(np.diff(sounding['Height'])) rep = find_repeats(sign.tolist(), -1, 3) try: lastgood = np.where(rep)[0][0] - 1 sounding = sounding.ix[0:lastgood] except IndexError: ''' all good''' pass ''' set index ''' sounding = sounding.set_index('Height') ''' QC ''' sounding = sounding.groupby(sounding.index).first() sounding.dropna(how='all', inplace=True) sounding.RH = sounding.RH.apply(lambda x: 100 if x > 100 else x) u_nans = nan_fraction(sounding.u) v_nans = nan_fraction(sounding.v) if u_nans > 0. or v_nans > 0.: sounding.u.interpolate(method='linear', inplace=True) sounding.v.interpolate(method='linear', inplace=True) rh_nans = nan_fraction(sounding.RH) td_nans = nan_fraction(sounding.TD) mr_nans = nan_fraction(sounding.MR) if rh_nans < 5. and td_nans > 50. and mr_nans > 50.: sat_mixr = tm.sat_mix_ratio(K=sounding.TE, hPa=sounding.P) mixr = (sounding.RH / 100) * sat_mixr * 1000 sounding.loc[:, 'MR'] = mixr # [g kg-1] ''' add potential temperature ''' theta = tm.theta2(K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR / 1000) thetaeq = tm.theta_equiv2(K=sounding.TE, hPa=sounding.P, relh=sounding.RH, mixing_ratio=sounding.MR / 1000) sounding.loc[:, 'theta'] = pd.Series(theta, index=sounding.index) sounding.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=sounding.index) ''' add Brunt-Vaisala frequency ''' hgt = sounding.index.values bvf_dry = tm.bv_freq_dry(theta=sounding.theta, agl_m=hgt, depth_m=100, centered=True) bvf_moist = tm.bv_freq_moist(K=sounding.TE, hPa=sounding.P, mixing_ratio=sounding.MR / 1000, agl_m=hgt, depth_m=100, centered=True) sounding = pd.merge(sounding, bvf_dry, left_index=True, right_index=True, how='outer') sounding = pd.merge(sounding, bvf_moist, left_index=True, right_index=True, how='outer') ''' interpolate between layer-averaged values ''' sounding.bvf_dry.interpolate(method='linear', inplace=True) sounding.bvf_moist.interpolate(method='linear', inplace=True) sounding.loc[sounding.MR.isnull(), 'bvf_dry'] = np.nan sounding.loc[sounding.MR.isnull(), 'bvf_moist'] = np.nan ''' NOTE: if sounding hgt jumps from 12 to 53m then 12m bvf values are NaN since there are no data between 12 and 53m to calculate a layer-based value. ''' return sounding
def parse_sounding2(file_sound): ''' This version make a resample of vertical gates and uses make_layer2 in bvf calculations (Thermodyn module) ''' col_names = get_var_names(file_sound) # col_units = get_var_units(file_sound) ''' read tabular file ''' raw_sounding = pd.read_table(file_sound, skiprows=36, header=None) raw_sounding.drop(19, axis=1, inplace=True) raw_sounding.columns = col_names sounding = raw_sounding[[ 'Height', 'TE', 'TD', 'RH', 'u', 'v', 'P', 'MR', 'DD' ]] sounding.units = { 'Height': 'm', 'TE': 'K', 'TD': 'K', 'RH': '%', 'u': 'm s-1', 'v': 'm s-1', 'P': 'hPa', 'MR': 'g kg-1' } ''' replace nan values ''' nan_value = -32768.00 sounding = sounding.applymap(lambda x: np.nan if x == nan_value else x) ''' QC soundings that include descening trayectories; criteria is 3 consecutive values descending ''' sign = np.sign(np.diff(sounding['Height'])) rep = find_repeats(sign.tolist(), -1, 3) try: lastgood = np.where(rep)[0][0] - 1 sounding = sounding.ix[0:lastgood] except IndexError: ''' all good''' pass # print sounding ''' resample to constant height values ''' resamp = 2 # [m] sounding = sounding.set_index('Height') hgt = sounding.index.values[-1] resample = np.arange(10, hgt, resamp) soundres = sounding.loc[resample] soundres.iloc[0] = sounding.iloc[0] # copy first value soundres.iloc[-1] = sounding.iloc[-1] # copy last value soundres.interpolate(method='linear', inplace=True, limit=80, limit_direction='backward') soundres = soundres.reset_index().drop_duplicates(subset='Height', keep='first') soundres = soundres.set_index('Height') ''' QC ''' soundres.RH = soundres.RH.apply(lambda x: 100 if x > 100 else x) rh_nans = nan_fraction(soundres.RH) # [%] td_nans = nan_fraction(soundres.TD) # [%] mr_nans = nan_fraction(soundres.MR) # [%] if rh_nans < 5. and td_nans > 50. and mr_nans > 50.: sat_mixr = tm.sat_mix_ratio(K=soundres.TE, hPa=soundres.P) mixr = (soundres.RH / 100.) * sat_mixr * 1000 soundres.loc[:, 'MR'] = mixr # [g kg-1] ''' add potential temperature ''' theta = tm.theta2(K=soundres.TE, hPa=soundres.P, mixing_ratio=soundres.MR / 1000) thetaeq = tm.theta_equiv2(K=soundres.TE, hPa=soundres.P, relh=soundres.RH, mixing_ratio=soundres.MR / 1000) soundres.loc[:, 'theta'] = pd.Series(theta, index=soundres.index) soundres.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=soundres.index) ''' add Brunt-Vaisala frequency ''' hgt = soundres.index.values depth = 100 # [m] bvf_dry = tm.bv_freq_dry(theta=soundres.theta, agl_m=hgt, depth_m=depth) bvf_moist = tm.bv_freq_moist(K=soundres.TE, hPa=soundres.P, mixing_ratio=soundres.MR / 1000, agl_m=hgt, depth_m=depth) soundres = pd.merge(soundres, bvf_dry, left_index=True, right_index=True, how='outer') soundres = pd.merge(soundres, bvf_moist, left_index=True, right_index=True, how='outer') ''' interpolate between layer-averaged values ''' soundres.bvf_dry.interpolate(method='cubic', inplace=True) soundres.bvf_moist.interpolate(method='cubic', inplace=True) return soundres
def plot_thermo(**kwargs): hgt=kwargs['hgt'] #[hPa] pres=kwargs['press'] #[hPa] TE=kwargs['temp'] # [C] TD=kwargs['dewp'] # [C] U=kwargs['u'] # [m s-1] V=kwargs['v'] # [m s-1] date=kwargs['date'] loc=kwargs['loc'] theta=kwargs['theta'] thetaeq=kwargs['thetaeq'] BVFd=kwargs['bvf_dry'] BVFm=kwargs['bvf_moist'] hgt_lim=kwargs['top'] relh=thermo.relative_humidity(C=TE,Dewp=TD) sat_mixr= thermo.sat_mix_ratio(C=TD, hPa=pres) mixr = relh*sat_mixr/100. fig,ax = plt.subplots(1,5,sharey=True,figsize=(11,8.5)) n=0 ax[n].plot(TE,hgt,label='Temp') ax[n].plot(TD,hgt,label='Dewp') ax[n].legend() ax[n].set_xlim([-30,20]) ax[n].set_ylim([0,hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('T [C]') ax[n].set_ylabel('Altitude [m]') n=1 ln1=ax[n].plot(mixr*1000.,hgt,label='mixr') ax[n].set_xlim([0,8]) ax[n].set_ylim([0,hgt_lim]) add_minor_grid(ax[n]) for label in ax[n].xaxis.get_ticklabels()[::2]: label.set_visible(False) ax[n].set_xlabel('MR [g kg-1]') axt=ax[n].twiny() ln2=axt.plot(relh,hgt,'g',label='relh') axt.set_xlim([0,100]) axt.set_ylim([0,hgt_lim]) axt.set_xlabel('RH [%]') axt.xaxis.set_label_coords(0.5, 1.04) axt.grid(False) lns = ln1+ln2 labs = [l.get_label() for l in lns] axt.legend(lns, labs, loc=0) n=2 ax[n].plot(theta,hgt,label='Theta') ax[n].plot(thetaeq,hgt,label='ThetaEq') ax[n].legend() ax[n].set_xlim([280,320]) ax[n].set_ylim([0,hgt_lim]) add_minor_grid(ax[n]) for label in ax[n].xaxis.get_ticklabels()[::2]: label.set_visible(False) ax[n].set_xlabel('Theta [K]') n=3 ax[n].plot(U,hgt,label='u') ax[n].plot(V,hgt,label='v') ax[n].axvline(x=0,linestyle=':',color='r') ax[n].legend() ax[n].set_xlim([-10,40]) ax[n].set_ylim([0,hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('WS [ms-1]') n=4 ax[n].plot(BVFd*10000.,hgt,label='dry') ax[n].plot(BVFm*10000.,hgt,label='moist') ax[n].axvline(x=0,linestyle=':',color='r') ax[n].legend(loc=2) ax[n].set_xlim([-6,6]) ax[n].set_ylim([0,hgt_lim]) add_minor_grid(ax[n]) ax[n].set_xlabel('BVF (x10^-4) [s-1]') l1='Sounding from NOAA P3' l2='\nIni: ' + date[0].strftime('%Y-%b-%d %H:%M:%S UTC') l3='\nEnd: ' + date[1].strftime('%Y-%b-%d %H:%M:%S UTC') l4='\nLat: '+'{:.2f}'.format(loc[0])+' Lon: '+'{:.2f}'.format(loc[1]) plt.suptitle(l1+l2+l3+l4,horizontalalignment='right',x=0.9) plt.subplots_adjust(bottom=0.06,top=0.89) plt.draw()
def cross_section(self, **kwargs): field = kwargs['field'] clevels = kwargs['clevels'] cmap = kwargs['cmap'] self.orientation = kwargs['orientation'] self.initialize_plot() self.horizontal = False t_arrays = read_files(self, 'temperature') # [C] q_arrays = read_files(self, 'sphum') # [kg/kg] rh_arrays = read_files(self, 'relhumid') isob = get_vertical_array(self)/100. # to [hPa] z, n = t_arrays[0].shape press = np.tile(np.array([isob]).transpose(), (1, n)) X, Y = np.meshgrid(range(len(self.lons)), range(len(isob))) if len(clevels) == 2: foo = clevels[0] boundsc = clevels[1] clevels = foo ''' make a color map of fixed colors ''' vmin = min(clevels) vmax = max(clevels) bounds = clevels snsmap = sns.color_palette(cmap, n_colors=len(bounds)) cmap = colors.ListedColormap(snsmap) norm = colors.BoundaryNorm(bounds, cmap.N) plot_field = [] if field == 'thetaeq': for i in range(6): mixr = thermo.mixing_ratio(specific_humidity=q_arrays[i]) theta = thermo.theta_equiv2( C=t_arrays[i], hPa=press, mixing_ratio=mixr, relh=rh_arrays[i]) theta[theta > 320] = np.nan plot_field.append(theta) plot_fieldc = plot_field cboundaries = bounds cticks = bounds boundsc = bounds ti = ' - Equivalent potential temperature [K]' elif field == 'q': for i in range(6): q = q_arrays[i] plot_field.append(q*1000.) # [g kg-1] plot_fieldc = plot_field cboundaries = bounds cticks = bounds boundsc = bounds ti = ' - Specific humidity [g kg-1]' elif field == 'U': plot_field = read_files(self, 'u') plot_fieldc = plot_field cboundaries = bounds cticks = bounds boundsc = bounds ti = ' - Wind speed zonal component [m s-1]' elif field == 'V': plot_field = read_files(self, 'v') plot_fieldc = plot_field cboundaries = bounds cticks = bounds boundsc = bounds ti = ' - Wind speed meridional component [m s-1]' elif field == 'thetaeq+U': for i in range(6): mixr = thermo.mixing_ratio(specific_humidity=q_arrays[i]) theta = thermo.theta_equiv2( C=t_arrays[i], hPa=press, mixing_ratio=mixr, relh=rh_arrays[i]) theta[theta > 320] = np.nan plot_field.append(theta) plot_fieldc = read_files(self, 'u') cboundaries = bounds cticks = bounds t0 = '\nEquivalent potential temperature [K] (color coded)' t1 = '\nWind speed zonal component [m s-1] (contour lines)' ti = t0+t1 elif field == 'thetaeq+V': for i in range(6): mixr = thermo.mixing_ratio(specific_humidity=q_arrays[i]) theta = thermo.theta_equiv2( C=t_arrays[i], hPa=press, mixing_ratio=mixr, relh=rh_arrays[i]) theta[theta > 320] = np.nan plot_field.append(theta) plot_fieldc = read_files(self, 'v') cboundaries = bounds cticks = bounds t0 = '\nEquivalent potential temperature [K] (color coded)' t1 = '\nWind speed meridional component [m s-1] (contour lines)' ti = t0+t1 for i in range(6): im = self.axes[i].imshow(plot_field[i], interpolation='none', vmin=vmin, vmax=vmax, cmap=cmap, norm=norm) self.axes[i].cax.colorbar(im, cmap=cmap, norm=norm, boundaries=cboundaries, ticks=cticks[::4]) xticks = self.lons[::10] xticklabs = [str(x) for x in xticks] xticklabs.reverse() xticklabs.append(' ') xticklabs.reverse() self.axes[i].set_xticklabels(xticklabs) yidx = np.where(isob == self.zboundary)[0] self.axes[i].set_ylim([36, yidx]) yticks = self.axes[i].get_yticks() isob_yticks = [isob[y] for y in yticks] if i == 0: yticklabs = [str(x) for x in isob_yticks] else: yticklabs = [' ' for x in isob_yticks] self.axes[i].set_yticklabels(yticklabs) ''' add contour lines ''' cs = self.axes[i].contour(X, Y, plot_fieldc[i], origin='lower', levels=boundsc, colors='k', linewidths=0.5) if field in ['thetaeq+U', 'thetaeq+V']: self.axes[i].clabel(cs, boundsc, fmt='%1.0f', fontsize=10) self.axes[i].set_ylim([36, yidx]) ''' add vertical line ''' xidx = np.where(self.lons == -123.0) self.axes[i].axvline(xidx, color='k', linestyle=':') ''' add date to subplot ''' self.add_date(i) ''' add axis label ''' self.axes[i].set_xlabel('Longitude [deg]') if i == 0: self.axes[i].set_ylabel('Pressure level [hPa]') t1 = 'Climate Forecast System Reanalysis'+ti if self.orientation[0] == 'zonal': t2 = '\nLatitude: ' + str(self.orientation[1]) elif self.orientation[0] == 'meridional': t2 = '\nLongitude: ' + str(self.orientation[1]) plt.suptitle(t1+t2)
def parse_surface_met(file_met, index_field=None, name_field=None, locelevation=None): from scipy import stats ''' Process surface meteorological files with .met extension Output dataframe assumes: - Each file is a 24h period observation - Frequency of observation is constant ''' casename = file_met.split('/')[-2] station_id = file_met.split('/')[-1][:3] usr_case = str(int(casename[-2:])) if usr_case in ['1', '2']: index_field = {'bby': [3, 4, 10, 5, 6, 11, 13], 'czc': [3, 4, 10, 5, 6, 11, 13]} elif usr_case in ['3', '4', '5', '6', '7']: index_field = {'bby': [3, 5, 8, 10, 12, 17, 26], 'czc': [3, 4, 5, 6, 8, 13, 22]} else: index_field = {'bby': [3, 4, 5, 6, 8, 13, 15], 'czc': [3, 4, 5, 6, 8, 13, 15], 'frs': [3, 4, 5, 6, 8, 13, 15]} elev = {'bby': 15, 'czc': 462, 'frs': 45} name_field = ['press', 'temp', 'rh', 'wspd', 'wdir', 'precip', 'mixr'] index_field = index_field[station_id] locelevation = elev[station_id] ''' read the csv file ''' raw_dframe = pd.read_csv(file_met, header=None) ''' parse date columns into a single date col ''' dates_col = [0, 1, 2] raw_dates = raw_dframe.ix[:, dates_col] raw_dates.columns = ['Y', 'j', 'HHMM'] raw_dates['HHMM'] = raw_dates['HHMM'].apply(lambda x: '{0:0>4}'.format(x)) raw_dates = raw_dates.apply( lambda x: '%s %s %s' % (x['Y'], x['j'], x['HHMM']), axis=1) dates_fmt = '%Y %j %H%M' dates = raw_dates.apply(lambda x: datetime.strptime(x, dates_fmt)) ''' make meteo df, assign datetime index, and name columns ''' meteo = raw_dframe.ix[:, index_field] meteo.index = dates meteo.columns = name_field ''' create a dataframe with regular and continuous 24h period time index (this works as a QC for time gaps) ''' nano = 1000000000 time_diff = np.diff(meteo.index) sample_freq = (stats.mode(time_diff)[0][0]/nano).astype(int) # [seconds] fidx = meteo.index[0] # (start date for dataframe) fidx_str = pd.to_datetime( fidx.year*10000 + fidx.month*100 + fidx.day, format='%Y%m%d') periods = (24*60*60)/sample_freq ts = pd.date_range(fidx_str, periods=periods, freq=str(sample_freq)+'s') nanarray = np.empty((periods, 1)) nanarray[:] = np.nan df = pd.DataFrame(nanarray, index=ts) meteo = df.join(meteo, how='outer') meteo.drop(0, axis=1, inplace=True) ''' make field with hourly acum precip ''' hour = pd.TimeGrouper('H') preciph = meteo.precip.groupby(hour).sum() meteo = meteo.join(preciph, how='outer', rsuffix='h') ''' add thermodynamics ''' theta = tm.theta1(C=meteo.temp, hPa=meteo.press) thetaeq = tm.theta_equiv1(C=meteo.temp, hPa=meteo.press) meteo.loc[:, 'theta'] = pd.Series(theta, index=meteo.index) meteo.loc[:, 'thetaeq'] = pd.Series(thetaeq, index=meteo.index) ''' add sea level pressure ''' Tv = tm.virtual_temperature(C=meteo.temp, mixing_ratio=meteo.mixr/1000.) slp = tm.sea_level_press(K=Tv+273.15, Pa=meteo.press*100, m=locelevation) meteo.loc[:, 'sea_levp'] = slp ''' assign metadata (prototype, not really used) ''' units = {'press': 'mb', 'temp': 'C', 'rh': '%', 'wspd': 'm s-1', 'wdir': 'deg', 'precip': 'mm', 'mixr': 'g kg-1'} agl = {'press': 'NaN', 'temp': '10 m', 'rh': '10 m', 'wspd': 'NaN', 'wdir': 'NaN', 'precip': 'NaN', 'mixr': 'NaN'} for n in name_field: meteo[n].units = units[n] meteo[n].agl = agl[n] meteo[n].nan = -9999.999 meteo[n].sampling_freq = '2 minute' return meteo
def parse_acft_sounding(flight_level_file, req_ini, req_end, return_interp): raw = pd.read_table(flight_level_file, engine='python', delimiter='\s*') ini_raw = raw['TIME'].iloc[0] end_raw = raw['TIME'].iloc[-1] timestamp = pd.date_range( '2001-01-23 '+ini_raw, '2001-01-24 '+end_raw, freq='s') raw.index = timestamp raw.drop(['TIME'], axis=1, inplace=True) ''' req_ini and req_end are python datatime variables ''' st = raw.index.searchsorted(req_ini) en = raw.index.searchsorted(req_end) data = raw[['PRES_ALT', 'AIR_PRESS', 'AIR_TEMP', 'DEW_POINT', 'WIND_SPD', 'WIND_DIR', 'LAT', 'LON']].ix[st:en] x = data['PRES_ALT'].values xnew = np.linspace(min(x), max(x), x.size) if x[0] > x[-1]: descening = True data = data.iloc[::-1] if return_interp: ''' flight sounding might include constant height levels or descening trayectories, so we interpolate data to a common vertical grid ''' data2 = data.drop_duplicates(subset='PRES_ALT') x2 = data2['PRES_ALT'].values ''' interpolate each field ''' for n in ['AIR_PRESS', 'AIR_TEMP', 'DEW_POINT', 'WIND_SPD', 'WIND_DIR']: y = data2[n].values # spl = UnivariateSpline(x2,y,k=4) # data[n]= spl(xnew) rbf = Rbf(x2, y, smooth=1.0) ynew = rbf(xnew) data[n] = ynew '''' update values ''' data['PRES_ALT'] = xnew ''' set index ''' data = data.set_index('PRES_ALT') ''' compute thermo ''' hgt = data.index.values Tc = data['AIR_TEMP'] Tk = Tc+273.15 press = data['AIR_PRESS'] dewp = data['DEW_POINT'] Rh = tm.relative_humidity(C=Tc, Dewp=dewp) Sat_mixr = tm.sat_mix_ratio(C=Tc, hPa=press) Mr = Rh*Sat_mixr/100. theta = tm.theta2(K=Tk, hPa=press, mixing_ratio=Mr) thetaeq = tm.theta_equiv2(K=Tk, hPa=press, relh=Rh, mixing_ratio=Mr) data['theta'] = theta.values data['thetaeq'] = thetaeq.values bvf_dry = tm.bv_freq_dry( theta=theta, agl_m=hgt, depth_m=100, centered=True) bvf_moist = tm.bv_freq_moist(K=Tk, hPa=press, mixing_ratio=Mr, agl_m=hgt, depth_m=100, centered=True) data = pd.merge( data, bvf_dry, left_index=True, right_index=True, how='outer') data = pd.merge( data, bvf_moist, left_index=True, right_index=True, how='outer') data.bvf_dry.interpolate(method='linear', inplace=True) data.bvf_moist.interpolate(method='linear', inplace=True) ''' drop last incorrect decreasing (increasing) altitude (pressure) value ''' data2 = data.ix[:xnew[-2]] ''' return dataframe ''' return data2 else: hgt = data['PRES_ALT'] Tc = data['AIR_TEMP'] Tk = Tc+273.15 press = data['AIR_PRESS'] dewp = data['DEW_POINT'] Rh = tm.relative_humidity(C=Tc, Dewp=dewp) Sat_mixr = tm.sat_mix_ratio(C=Tc, hPa=press) Mr = Rh*Sat_mixr/100. theta = tm.theta2(K=Tk, hPa=press, mixing_ratio=Mr) thetaeq = tm.theta_equiv2(K=Tk, hPa=press, relh=Rh, mixing_ratio=Mr) data['theta'] = theta.values data['thetaeq'] = thetaeq.values data['bvf_dry'] = np.nan data['bvf_moist'] = np.nan return data
def parse_acft_sounding(flight_level_file, req_ini, req_end, return_interp): raw = pd.read_table(flight_level_file, engine='python', delimiter='\s*') ini_raw = raw['TIME'].iloc[0] end_raw = raw['TIME'].iloc[-1] timestamp = pd.date_range('2001-01-23 ' + ini_raw, '2001-01-24 ' + end_raw, freq='s') raw.index = timestamp raw.drop(['TIME'], axis=1, inplace=True) ''' req_ini and req_end are python datatime variables ''' st = raw.index.searchsorted(req_ini) en = raw.index.searchsorted(req_end) data = raw[[ 'PRES_ALT', 'AIR_PRESS', 'AIR_TEMP', 'DEW_POINT', 'WIND_SPD', 'WIND_DIR', 'LAT', 'LON' ]].ix[st:en] x = data['PRES_ALT'].values xnew = np.linspace(min(x), max(x), x.size) if x[0] > x[-1]: descening = True data = data.iloc[::-1] if return_interp: ''' flight sounding might include constant height levels or descening trayectories, so we interpolate data to a common vertical grid ''' data2 = data.drop_duplicates(subset='PRES_ALT') x2 = data2['PRES_ALT'].values ''' interpolate each field ''' for n in [ 'AIR_PRESS', 'AIR_TEMP', 'DEW_POINT', 'WIND_SPD', 'WIND_DIR' ]: y = data2[n].values # spl = UnivariateSpline(x2,y,k=4) # data[n]= spl(xnew) rbf = Rbf(x2, y, smooth=1.0) ynew = rbf(xnew) data[n] = ynew '''' update values ''' data['PRES_ALT'] = xnew ''' set index ''' data = data.set_index('PRES_ALT') ''' compute thermo ''' hgt = data.index.values Tc = data['AIR_TEMP'] Tk = Tc + 273.15 press = data['AIR_PRESS'] dewp = data['DEW_POINT'] Rh = tm.relative_humidity(C=Tc, Dewp=dewp) Sat_mixr = tm.sat_mix_ratio(C=Tc, hPa=press) Mr = Rh * Sat_mixr / 100. theta = tm.theta2(K=Tk, hPa=press, mixing_ratio=Mr) thetaeq = tm.theta_equiv2(K=Tk, hPa=press, relh=Rh, mixing_ratio=Mr) data['theta'] = theta.values data['thetaeq'] = thetaeq.values bvf_dry = tm.bv_freq_dry(theta=theta, agl_m=hgt, depth_m=100, centered=True) bvf_moist = tm.bv_freq_moist(K=Tk, hPa=press, mixing_ratio=Mr, agl_m=hgt, depth_m=100, centered=True) data = pd.merge(data, bvf_dry, left_index=True, right_index=True, how='outer') data = pd.merge(data, bvf_moist, left_index=True, right_index=True, how='outer') data.bvf_dry.interpolate(method='linear', inplace=True) data.bvf_moist.interpolate(method='linear', inplace=True) ''' drop last incorrect decreasing (increasing) altitude (pressure) value ''' data2 = data.ix[:xnew[-2]] ''' return dataframe ''' return data2 else: hgt = data['PRES_ALT'] Tc = data['AIR_TEMP'] Tk = Tc + 273.15 press = data['AIR_PRESS'] dewp = data['DEW_POINT'] Rh = tm.relative_humidity(C=Tc, Dewp=dewp) Sat_mixr = tm.sat_mix_ratio(C=Tc, hPa=press) Mr = Rh * Sat_mixr / 100. theta = tm.theta2(K=Tk, hPa=press, mixing_ratio=Mr) thetaeq = tm.theta_equiv2(K=Tk, hPa=press, relh=Rh, mixing_ratio=Mr) data['theta'] = theta.values data['thetaeq'] = thetaeq.values data['bvf_dry'] = np.nan data['bvf_moist'] = np.nan return data