예제 #1
0
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()
예제 #2
0
    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))
예제 #3
0
    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
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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()
예제 #7
0
    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'
예제 #8
0
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
예제 #9
0
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
예제 #10
0
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()
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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
예제 #14
0
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()
예제 #15
0
    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)
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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