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_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 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_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