Beispiel #1
0
def test_julian(YEAR, MONTH):
    #-- days per month in a leap and a standard year
    #-- only difference is February (29 vs. 28)
    dpm_leap = np.array([31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31])
    dpm_stnd = np.array([31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31])
    DPM = dpm_stnd if np.mod(YEAR, 4) else dpm_leap
    #-- calculate Modified Julian Day (MJD) from calendar date
    DAY = np.random.randint(1, DPM[MONTH - 1] + 1)
    HOUR = np.random.randint(0, 23 + 1)
    MINUTE = np.random.randint(0, 59 + 1)
    SECOND = 60.0 * np.random.random_sample(1)
    MJD = pyTMD.time.convert_calendar_dates(YEAR,
                                            MONTH,
                                            DAY,
                                            hour=HOUR,
                                            minute=MINUTE,
                                            second=SECOND,
                                            epoch=(1858, 11, 17, 0, 0, 0))
    #-- convert MJD to calendar date
    YY, MM, DD, HH, MN, SS = convert_julian(np.squeeze(MJD) + 2400000.5,
                                            FORMAT='tuple',
                                            ASTYPE=np.float)
    #-- assert dates
    eps = np.finfo(np.float16).eps
    assert (YY == YEAR)
    assert (MM == MONTH)
    assert (DD == DAY)
    assert (HH == HOUR)
    assert (MN == MINUTE)
    assert (np.abs(SS - SECOND) < eps)
Beispiel #2
0
def compute_OPT_icebridge_data(tide_dir,
                               arg,
                               METHOD=None,
                               VERBOSE=False,
                               MODE=0o775):

    #-- extract file name and subsetter indices lists
    match_object = re.match(r'(.*?)(\[(.*?)\])?$', arg)
    input_file = os.path.expanduser(match_object.group(1))
    #-- subset input file to indices
    if match_object.group(2):
        #-- decompress ranges and add to list
        input_subsetter = []
        for i in re.findall(r'((\d+)-(\d+)|(\d+))', match_object.group(3)):
            input_subsetter.append(int(i[3])) if i[3] else \
                input_subsetter.extend(range(int(i[1]),int(i[2])+1))
    else:
        input_subsetter = None

    #-- output directory for input_file
    DIRECTORY = os.path.dirname(input_file)
    #-- calculate if input files are from ATM or LVIS (+GH)
    regex = {}
    regex[
        'ATM'] = r'(BLATM2|ILATM2)_(\d+)_(\d+)_smooth_nadir(.*?)(csv|seg|pt)$'
    regex['ATM1b'] = r'(BLATM1b|ILATM1b)_(\d+)_(\d+)(.*?).(qi|TXT|h5)$'
    regex['LVIS'] = r'(BLVIS2|BVLIS2|ILVIS2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    regex['LVGH'] = r'(ILVGH2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    for key, val in regex.items():
        if re.match(val, os.path.basename(input_file)):
            OIB = key

    #-- invalid value
    fill_value = -9999.0
    #-- output netCDF4 and HDF5 file attributes
    #-- will be added to YAML header in csv files
    attrib = {}
    #-- latitude
    attrib['lat'] = {}
    attrib['lat']['long_name'] = 'Latitude_of_measurement'
    attrib['lat']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lat']['units'] = 'Degrees_North'
    #-- longitude
    attrib['lon'] = {}
    attrib['lon']['long_name'] = 'Longitude_of_measurement'
    attrib['lon']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lon']['units'] = 'Degrees_East'
    #-- ocean pole tides
    attrib['tide_oc_pole'] = {}
    attrib['tide_oc_pole']['long_name'] = 'Ocean_Pole_Tide'
    attrib['tide_oc_pole']['description'] = (
        'Ocean_pole_tide_radial_'
        'displacements_at_the_measurement_position_at_the_acquisition_time_due_'
        'to_polar_motion')
    attrib['tide_oc_pole']['reference'] = (
        'ftp://tai.bipm.org/iers/conv2010/'
        'chapter7/opoleloadcoefcmcor.txt.gz')
    attrib['tide_oc_pole']['units'] = 'meters'
    #-- Modified Julian Days
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1858-11-17T00:00:00'
    attrib['time']['description'] = 'Modified Julian Days'
    attrib['time']['calendar'] = 'standard'

    #-- extract information from first input file
    #-- acquisition year, month and day
    #-- number of points
    #-- instrument (PRE-OIB ATM or LVIS, OIB ATM or LVIS)
    if OIB in ('ATM', 'ATM1b'):
        M1, YYMMDD1, HHMMSS1, AX1, SF1 = re.findall(regex[OIB],
                                                    input_file).pop()
        #-- early date strings omitted century and millenia (e.g. 93 for 1993)
        if (len(YYMMDD1) == 6):
            ypre, MM1, DD1 = YYMMDD1[:2], YYMMDD1[2:4], YYMMDD1[4:]
            if (np.float(ypre) >= 90):
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 1900.0)
            else:
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 2000.0)
        elif (len(YYMMDD1) == 8):
            YY1, MM1, DD1 = YYMMDD1[:4], YYMMDD1[4:6], YYMMDD1[6:]
    elif OIB in ('LVIS', 'LVGH'):
        M1, RG1, YY1, MMDD1, RLD1, SS1 = re.findall(regex[OIB],
                                                    input_file).pop()
        MM1, DD1 = MMDD1[:2], MMDD1[2:]

    #-- read data from input_file
    print('{0} -->'.format(input_file)) if VERBOSE else None
    if (OIB == 'ATM'):
        #-- load IceBridge ATM data from input_file
        dinput, file_lines, HEM = read_ATM_icessn_file(input_file,
                                                       input_subsetter)
    elif (OIB == 'ATM1b'):
        #-- load IceBridge Level-1b ATM data from input_file
        dinput, file_lines, HEM = read_ATM_qfit_file(input_file,
                                                     input_subsetter)
    elif OIB in ('LVIS', 'LVGH'):
        #-- load IceBridge LVIS data from input_file
        dinput, file_lines, HEM = read_LVIS_HDF5_file(input_file,
                                                      input_subsetter)

    #-- extract lat/lon
    lon = dinput['lon'][:]
    lat = dinput['lat'][:]
    #-- convert time from UTC time of day to modified julian days (MJD)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    t = dinput['time'][:] / 86400.0 + 51544.5
    #-- convert from MJD to calendar dates
    YY, MM, DD, HH, MN, SS = convert_julian(t + 2400000.5, FORMAT='tuple')
    #-- convert calendar dates into year decimal
    tdec = convert_calendar_decimal(YY,
                                    MM,
                                    DAY=DD,
                                    HOUR=HH,
                                    MINUTE=MN,
                                    SECOND=SS)
    #-- elevation
    h1 = dinput['data'][:]

    #-- degrees to radians and arcseconds to radians
    dtr = np.pi / 180.0
    atr = np.pi / 648000.0
    #-- earth and physical parameters (IERS)
    G = 6.67428e-11  #-- universal constant of gravitation [m^3/(kg*s^2)]
    GM = 3.986004418e14  #-- geocentric gravitational constant [m^3/s^2]
    ge = 9.7803278  #-- mean equatorial gravity [m/s^2]
    a_axis = 6378136.6  #-- equatorial radius of the Earth [m]
    flat = 1.0 / 298.257223563  #-- flattening of the ellipsoid
    omega = 7.292115e-5  #-- mean rotation rate of the Earth [radians/s]
    rho_w = 1025.0  #-- density of sea water [kg/m^3]
    ge = 9.7803278  #-- mean equatorial gravitational acceleration [m/s^2]
    #-- Linear eccentricity and first numerical eccentricity
    lin_ecc = np.sqrt((2.0 * flat - flat**2) * a_axis**2)
    ecc1 = lin_ecc / a_axis
    #-- tidal love number differential (1 + kl - hl) for pole tide frequencies
    gamma = 0.6870 + 0.0036j

    #-- convert from geodetic latitude to geocentric latitude
    #-- geodetic latitude in radians
    latitude_geodetic_rad = lat * dtr
    #-- prime vertical radius of curvature
    N = a_axis / np.sqrt(1.0 - ecc1**2.0 * np.sin(latitude_geodetic_rad)**2.0)
    #-- calculate X, Y and Z from geodetic latitude and longitude
    X = (N + h1) * np.cos(latitude_geodetic_rad) * np.cos(lon * dtr)
    Y = (N + h1) * np.cos(latitude_geodetic_rad) * np.sin(lon * dtr)
    Z = (N * (1.0 - ecc1**2.0) + h1) * np.sin(latitude_geodetic_rad)
    rr = np.sqrt(X**2.0 + Y**2.0 + Z**2.0)
    #-- calculate geocentric latitude and convert to degrees
    latitude_geocentric = np.arctan(Z / np.sqrt(X**2.0 + Y**2.0)) / dtr

    #-- pole tide displacement scale factor
    Hp = np.sqrt(8.0 * np.pi / 15.0) * (omega**2 * a_axis**4) / GM
    K = 4.0 * np.pi * G * rho_w * Hp * a_axis / (3.0 * ge)
    K1 = 4.0 * np.pi * G * rho_w * Hp * a_axis**3 / (3.0 * GM)

    #-- read ocean pole tide map from Desai (2002)
    ocean_pole_tide_file = get_data_path(['data', 'opoleloadcoefcmcor.txt.gz'])
    iur, iun, iue, ilon, ilat = read_ocean_pole_tide(ocean_pole_tide_file)

    #-- pole tide files (mean and daily)
    # mean_pole_file = os.path.join(tide_dir,'mean-pole.tab')
    mean_pole_file = os.path.join(tide_dir, 'mean_pole_2017-10-23.tab')
    pole_tide_file = os.path.join(tide_dir, 'finals_all_2017-09-01.tab')

    #-- read IERS daily polar motion values
    EOP = read_iers_EOP(pole_tide_file)
    #-- create cubic spline interpolations of daily polar motion values
    xSPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['x'], k=3, s=0)
    ySPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['y'], k=3, s=0)
    #-- bad value
    fill_value = -9999.0

    #-- output ocean pole tide HDF5 file
    #-- form: rg_NASA_OCEAN_POLE_TIDE_WGS84_fl1yyyymmddjjjjj.H5
    #-- where rg is the hemisphere flag (GR or AN) for the region
    #-- fl1 and fl2 are the data flags (ATM, LVIS, GLAS)
    #-- yymmddjjjjj is the year, month, day and second of the input file
    #-- output region flags: GR for Greenland and AN for Antarctica
    hem_flag = {'N': 'GR', 'S': 'AN'}
    #-- use starting second to distinguish between files for the day
    JJ1 = np.min(dinput['time']) % 86400
    #-- output file format
    args = (hem_flag[HEM], 'OCEAN_POLE_TIDE', OIB, YY1, MM1, DD1, JJ1)
    FILENAME = '{0}_NASA_{1}_WGS84_{2}{3}{4}{5}{6:05.0f}.H5'.format(*args)
    #-- print file information
    print('\t{0}'.format(FILENAME)) if VERBOSE else None

    #-- open output HDF5 file
    fid = h5py.File(os.path.join(DIRECTORY, FILENAME), 'w')

    #-- interpolate ocean pole tide map from Desai (2002)
    if (METHOD == 'spline'):
        #-- use scipy bivariate splines to interpolate to output points
        f1 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].real,
                                                   kx=1,
                                                   ky=1)
        f2 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].imag,
                                                   kx=1,
                                                   ky=1)
        UR = np.zeros((file_lines), dtype=np.complex128)
        UR.real = f1.ev(lon, latitude_geocentric)
        UR.imag = f2.ev(lon, latitude_geocentric)
    else:
        #-- use scipy regular grid to interpolate values for a given method
        r1 = scipy.interpolate.RegularGridInterpolator((ilon, ilat[::-1]),
                                                       iur[:, ::-1],
                                                       method=METHOD)
        UR = r1.__call__(np.c_[lon, latitude_geocentric])

    #-- calculate angular coordinates of mean pole at time tdec
    mpx, mpy, fl = iers_mean_pole(mean_pole_file, tdec, '2015')
    #-- interpolate daily polar motion values to t using cubic splines
    px = xSPL(t)
    py = ySPL(t)
    #-- calculate differentials from mean pole positions
    mx = px - mpx
    my = -(py - mpy)
    #-- calculate radial displacement at time
    Urad = np.ma.zeros((file_lines), fill_value=fill_value)
    Urad.data[:] = K * atr * np.real(
        (mx * gamma.real + my * gamma.imag) * UR.real +
        (my * gamma.real - mx * gamma.imag) * UR.imag)
    #-- replace fill values
    Urad.mask = np.isnan(Urad.data)
    Urad.data[Urad.mask] = Urad.fill_value

    #-- add latitude and longitude to output file
    for key in ['lat', 'lon']:
        #-- Defining the HDF5 dataset variables for lat/lon
        h5 = fid.create_dataset(key, (file_lines, ),
                                data=dinput[key][:],
                                dtype=dinput[key].dtype,
                                compression='gzip')
        #-- add HDF5 variable attributes
        for att_name, att_val in attrib[key].items():
            h5.attrs[att_name] = att_val
        #-- attach dimensions
        h5.dims[0].label = 'RECORD_SIZE'

    #-- output tides to HDF5 dataset
    h5 = fid.create_dataset('tide_oc_pole', (file_lines, ),
                            data=Urad,
                            dtype=Urad.dtype,
                            fillvalue=fill_value,
                            compression='gzip')
    #-- add HDF5 variable attributes
    h5.attrs['_FillValue'] = fill_value
    for att_name, att_val in attrib['tide_oc_pole'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- output days to HDF5 dataset
    h5 = fid.create_dataset('time', (file_lines, ),
                            data=t,
                            dtype=t.dtype,
                            compression='gzip')
    #-- add HDF5 variable attributes
    for att_name, att_val in attrib['time'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- HDF5 file attributes
    fid.attrs['featureType'] = 'trajectory'
    fid.attrs['title'] = 'Tidal_correction_for_elevation_measurements'
    fid.attrs['summary'] = ('Ocean_pole_tide_radial_displacements_'
                            'computed_at_elevation_measurements.')
    fid.attrs['project'] = 'NASA_Operation_IceBridge'
    fid.attrs['processing_level'] = '4'
    fid.attrs['date_created'] = time.strftime('%Y-%m-%d', time.localtime())
    #-- add attributes for input files
    fid.attrs['elevation_file'] = os.path.basename(input_file)
    #-- add geospatial and temporal attributes
    fid.attrs['geospatial_lat_min'] = dinput['lat'].min()
    fid.attrs['geospatial_lat_max'] = dinput['lat'].max()
    fid.attrs['geospatial_lon_min'] = dinput['lon'].min()
    fid.attrs['geospatial_lon_max'] = dinput['lon'].max()
    fid.attrs['geospatial_lat_units'] = "degrees_north"
    fid.attrs['geospatial_lon_units'] = "degrees_east"
    fid.attrs['geospatial_ellipsoid'] = "WGS84"
    fid.attrs['time_type'] = 'UTC'

    #-- convert start/end time from MJD into Julian days
    JD_start = np.min(t) + 2400000.5
    JD_end = np.max(t) + 2400000.5
    #-- convert to calendar date with convert_julian.py
    cal = convert_julian(np.array([JD_start, JD_end]), ASTYPE=np.int)
    #-- add attributes with measurement date start, end and duration
    args = (cal['hour'][0], cal['minute'][0], cal['second'][0])
    fid.attrs['RangeBeginningTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['hour'][-1], cal['minute'][-1], cal['second'][-1])
    fid.attrs['RangeEndingTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['year'][0], cal['month'][0], cal['day'][0])
    fid.attrs['RangeBeginningDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    args = (cal['year'][-1], cal['month'][-1], cal['day'][-1])
    fid.attrs['RangeEndingDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    duration = np.round(JD_end * 86400.0 - JD_start * 86400.0)
    fid.attrs['DurationTimeSeconds'] = '{0:0.0f}'.format(duration)
    #-- close the output HDF5 dataset
    fid.close()
    #-- change the permissions level to MODE
    os.chmod(os.path.join(DIRECTORY, FILENAME), MODE)
def HDF5_ATL06_tide_write(IS2_atl06_tide,
                          IS2_atl06_attrs,
                          INPUT=None,
                          FILENAME='',
                          FILL_VALUE=None,
                          CLOBBER='Y'):
    #-- setting HDF5 clobber attribute
    if CLOBBER in ('Y', 'y'):
        clobber = 'w'
    else:
        clobber = 'w-'

    #-- open output HDF5 file
    fileID = h5py.File(os.path.expanduser(FILENAME), clobber)

    #-- create HDF5 records
    h5 = {}

    #-- number of GPS seconds between the GPS epoch (1980-01-06T00:00:00Z UTC)
    #-- and ATLAS Standard Data Product (SDP) epoch (2018-01-01T00:00:00Z UTC)
    h5['ancillary_data'] = {}
    for k, v in IS2_atl06_tide['ancillary_data'].items():
        #-- Defining the HDF5 dataset variables
        val = 'ancillary_data/{0}'.format(k)
        h5['ancillary_data'][k] = fileID.create_dataset(val,
                                                        np.shape(v),
                                                        data=v,
                                                        dtype=v.dtype,
                                                        compression='gzip')
        #-- add HDF5 variable attributes
        for att_name, att_val in IS2_atl06_attrs['ancillary_data'][k].items():
            h5['ancillary_data'][k].attrs[att_name] = att_val

    #-- write each output beam
    beams = [
        k for k in IS2_atl06_tide.keys() if bool(re.match(r'gt\d[lr]', k))
    ]
    for gtx in beams:
        fileID.create_group(gtx)
        #-- add HDF5 group attributes for beam
        for att_name in [
                'Description', 'atlas_pce', 'atlas_beam_type',
                'groundtrack_id', 'atmosphere_profile', 'atlas_spot_number',
                'sc_orientation'
        ]:
            fileID[gtx].attrs[att_name] = IS2_atl06_attrs[gtx][att_name]
        #-- create land_ice_segments group
        fileID[gtx].create_group('land_ice_segments')
        h5[gtx] = dict(land_ice_segments={})
        for att_name in ['Description', 'data_rate']:
            att_val = IS2_atl06_attrs[gtx]['land_ice_segments'][att_name]
            fileID[gtx]['land_ice_segments'].attrs[att_name] = att_val

        #-- delta_time
        v = IS2_atl06_tide[gtx]['land_ice_segments']['delta_time']
        attrs = IS2_atl06_attrs[gtx]['land_ice_segments']['delta_time']
        #-- Defining the HDF5 dataset variables
        val = '{0}/{1}/{2}'.format(gtx, 'land_ice_segments', 'delta_time')
        h5[gtx]['land_ice_segments']['delta_time'] = fileID.create_dataset(
            val, np.shape(v), data=v, dtype=v.dtype, compression='gzip')
        #-- add HDF5 variable attributes
        for att_name, att_val in attrs.items():
            h5[gtx]['land_ice_segments']['delta_time'].attrs[
                att_name] = att_val

        #-- geolocation and segment_id variables
        for k in ['latitude', 'longitude', 'segment_id']:
            #-- values and attributes
            v = IS2_atl06_tide[gtx]['land_ice_segments'][k]
            attrs = IS2_atl06_attrs[gtx]['land_ice_segments'][k]
            fillvalue = FILL_VALUE[gtx]['land_ice_segments'][k]
            #-- Defining the HDF5 dataset variables
            val = '{0}/{1}/{2}'.format(gtx, 'land_ice_segments', k)
            h5[gtx]['land_ice_segments'][k] = fileID.create_dataset(
                val,
                np.shape(v),
                data=v,
                dtype=v.dtype,
                fillvalue=fillvalue,
                compression='gzip')
            #-- attach dimensions
            for dim in ['delta_time']:
                h5[gtx]['land_ice_segments'][k].dims.create_scale(
                    h5[gtx]['land_ice_segments'][dim], dim)
                h5[gtx]['land_ice_segments'][k].dims[0].attach_scale(
                    h5[gtx]['land_ice_segments'][dim])
            #-- add HDF5 variable attributes
            for att_name, att_val in attrs.items():
                h5[gtx]['land_ice_segments'][k].attrs[att_name] = att_val

        #-- add to geophysical corrections
        key = 'geophysical'
        fileID[gtx]['land_ice_segments'].create_group(key)
        h5[gtx]['land_ice_segments'][key] = {}
        for att_name in ['Description', 'data_rate']:
            att_val = IS2_atl06_attrs[gtx]['land_ice_segments'][key][att_name]
            fileID[gtx]['land_ice_segments'][key].attrs[att_name] = att_val
        for k, v in IS2_atl06_tide[gtx]['land_ice_segments'][key].items():
            #-- attributes
            attrs = IS2_atl06_attrs[gtx]['land_ice_segments'][key][k]
            fillvalue = FILL_VALUE[gtx]['land_ice_segments'][key][k]
            #-- Defining the HDF5 dataset variables
            val = '{0}/{1}/{2}/{3}'.format(gtx, 'land_ice_segments', key, k)
            if fillvalue:
                h5[gtx]['land_ice_segments'][key][k] = \
                 fileID.create_dataset(val, np.shape(v), data=v,
                 dtype=v.dtype, fillvalue=fillvalue, compression='gzip')
            else:
                h5[gtx]['land_ice_segments'][key][k] = \
                 fileID.create_dataset(val, np.shape(v), data=v,
                 dtype=v.dtype, compression='gzip')
            #-- attach dimensions
            for dim in ['delta_time']:
                h5[gtx]['land_ice_segments'][key][k].dims.create_scale(
                    h5[gtx]['land_ice_segments'][dim], dim)
                h5[gtx]['land_ice_segments'][key][k].dims[0].attach_scale(
                    h5[gtx]['land_ice_segments'][dim])
            #-- add HDF5 variable attributes
            for att_name, att_val in attrs.items():
                h5[gtx]['land_ice_segments'][key][k].attrs[att_name] = att_val

    #-- HDF5 file title
    fileID.attrs['featureType'] = 'trajectory'
    fileID.attrs['title'] = 'ATLAS/ICESat-2 Land Ice Height'
    fileID.attrs['summary'] = (
        'Estimates of the ice-sheet tidal parameters '
        'needed to interpret and assess the quality of land height estimates.')
    fileID.attrs['description'] = (
        'Land ice parameters for each beam.  All '
        'parameters are calculated for the same along-track increments for '
        'each beam and repeat.')
    date_created = datetime.datetime.today()
    fileID.attrs['date_created'] = date_created.isoformat()
    project = 'ICESat-2 > Ice, Cloud, and land Elevation Satellite-2'
    fileID.attrs['project'] = project
    platform = 'ICESat-2 > Ice, Cloud, and land Elevation Satellite-2'
    fileID.attrs['project'] = platform
    #-- add attribute for elevation instrument and designated processing level
    instrument = 'ATLAS > Advanced Topographic Laser Altimeter System'
    fileID.attrs['instrument'] = instrument
    fileID.attrs['source'] = 'Spacecraft'
    fileID.attrs['references'] = 'http://nsidc.org/data/icesat2/data.html'
    fileID.attrs['processing_level'] = '4'
    #-- add attributes for input ATL03 and ATL09 files
    fileID.attrs['input_files'] = ','.join(
        [os.path.basename(i) for i in INPUT])
    #-- find geospatial and temporal ranges
    lnmn, lnmx, ltmn, ltmx, tmn, tmx = (np.inf, -np.inf, np.inf, -np.inf,
                                        np.inf, -np.inf)
    for gtx in beams:
        lon = IS2_atl06_tide[gtx]['land_ice_segments']['longitude']
        lat = IS2_atl06_tide[gtx]['land_ice_segments']['latitude']
        delta_time = IS2_atl06_tide[gtx]['land_ice_segments']['delta_time']
        #-- setting the geospatial and temporal ranges
        lnmn = lon.min() if (lon.min() < lnmn) else lnmn
        lnmx = lon.max() if (lon.max() > lnmx) else lnmx
        ltmn = lat.min() if (lat.min() < ltmn) else ltmn
        ltmx = lat.max() if (lat.max() > ltmx) else ltmx
        tmn = delta_time.min() if (delta_time.min() < tmn) else tmn
        tmx = delta_time.max() if (delta_time.max() > tmx) else tmx
    #-- add geospatial and temporal attributes
    fileID.attrs['geospatial_lat_min'] = ltmn
    fileID.attrs['geospatial_lat_max'] = ltmx
    fileID.attrs['geospatial_lon_min'] = lnmn
    fileID.attrs['geospatial_lon_max'] = lnmx
    fileID.attrs['geospatial_lat_units'] = "degrees_north"
    fileID.attrs['geospatial_lon_units'] = "degrees_east"
    fileID.attrs['geospatial_ellipsoid'] = "WGS84"
    fileID.attrs['date_type'] = 'UTC'
    fileID.attrs['time_type'] = 'CCSDS UTC-A'
    #-- convert start and end time from ATLAS SDP seconds into Julian days
    atlas_sdp_gps_epoch = IS2_atl06_tide['ancillary_data'][
        'atlas_sdp_gps_epoch']
    gps_seconds = atlas_sdp_gps_epoch + np.array([tmn, tmx])
    time_leaps = count_leap_seconds(gps_seconds)
    time_julian = 2444244.5 + (gps_seconds - time_leaps) / 86400.0
    #-- convert to calendar date with convert_julian.py
    YY, MM, DD, HH, MN, SS = convert_julian(time_julian, FORMAT='tuple')
    #-- add attributes with measurement date start, end and duration
    tcs = datetime.datetime(np.int(YY[0]), np.int(MM[0]), np.int(DD[0]),
                            np.int(HH[0]), np.int(MN[0]), np.int(SS[0]),
                            np.int(1e6 * (SS[0] % 1)))
    fileID.attrs['time_coverage_start'] = tcs.isoformat()
    tce = datetime.datetime(np.int(YY[1]), np.int(MM[1]), np.int(DD[1]),
                            np.int(HH[1]), np.int(MN[1]), np.int(SS[1]),
                            np.int(1e6 * (SS[1] % 1)))
    fileID.attrs['time_coverage_end'] = tce.isoformat()
    fileID.attrs['time_coverage_duration'] = '{0:0.0f}'.format(tmx - tmn)
    #-- Closing the HDF5 file
    fileID.close()
Beispiel #4
0
def compute_OPT_displacements(tide_dir,
                              input_file,
                              output_file,
                              METHOD=None,
                              VERBOSE=False,
                              MODE=0775):

    #-- read input *.csv file to extract MJD, latitude, longitude and elevation
    dtype = dict(names=('MJD', 'lat', 'lon', 'h'),
                 formats=('f', 'f', 'f', 'f'))
    dinput = np.loadtxt(input_file, delimiter=',', dtype=dtype)
    file_lines, = np.shape(dinput['h'])
    #-- convert from MJD to calendar dates, then to year-decimal
    YY, MM, DD, HH, MN, SS = convert_julian(dinput['MJD'] + 2400000.5,
                                            FORMAT='tuple')
    tdec = convert_calendar_decimal(YY,
                                    MM,
                                    DAY=DD,
                                    HOUR=HH,
                                    MINUTE=MN,
                                    SECOND=SS)

    #-- degrees to radians and arcseconds to radians
    dtr = np.pi / 180.0
    atr = np.pi / 648000.0
    #-- earth and physical parameters (IERS and WGS84)
    G = 6.67428e-11  #-- universal constant of gravitation [m^3/(kg*s^2)]
    GM = 3.98004418e14  #-- geocentric gravitational constant [m^3/s^2]
    a_axis = 6378136.6  #-- WGS84 equatorial radius of the Earth [m]
    flat = 1.0 / 298.257223563  #-- flattening of the WGS84 ellipsoid
    omega = 7.292115e-5  #-- mean rotation rate of the Earth [radians/s]
    rho_w = 1025.0  #-- density of sea water [kg/m^3]
    #-- Linear eccentricity and first numerical eccentricity
    lin_ecc = np.sqrt((2.0 * flat - flat**2) * a_axis**2)
    ecc1 = lin_ecc / a_axis
    #-- tidal love number differential (1 + kl - hl) for pole tide frequencies
    gamma = 0.6870 + 0.0036j

    #-- convert from geodetic latitude to geocentric latitude
    #-- geodetic latitude in radians
    latitude_geodetic_rad = dinput['lat'] * dtr
    #-- prime vertical radius of curvature
    N = a_axis / np.sqrt(1.0 - ecc1**2.0 * np.sin(latitude_geodetic_rad)**2.0)
    #-- calculate X, Y and Z from geodetic latitude and longitude
    X = (N + dinput['h']) * np.cos(latitude_geodetic_rad) * np.cos(
        dinput['lon'] * dtr)
    Y = (N + dinput['h']) * np.cos(latitude_geodetic_rad) * np.sin(
        dinput['lon'] * dtr)
    Z = (N * (1.0 - ecc1**2.0) + dinput['h']) * np.sin(latitude_geodetic_rad)
    #-- calculate geocentric latitude and convert to degrees
    latitude_geocentric = np.arctan(Z / np.sqrt(X**2.0 + Y**2.0)) / dtr

    #-- pole tide displacement scale factor
    Hp = np.sqrt(8.0 * np.pi / 15.0) * (omega**2 * a_axis**4) / GM
    K = 4.0 * np.pi * G * rho_w * Hp * a_axis**3 / (3.0 * GM)

    #-- pole tide files (mean and daily)
    mean_pole_file = os.path.join(tide_dir, 'mean_pole_2017-10-23.tab')
    pole_tide_file = os.path.join(tide_dir, 'finals_all_2017-09-01.tab')
    #-- calculate angular coordinates of mean pole at time tdec
    mpx, mpy, fl = iers_mean_pole(mean_pole_file, tdec, '2015')
    #-- read IERS daily polar motion values
    EOP = read_iers_EOP(pole_tide_file)
    #-- interpolate daily polar motion values to t1 using cubic splines
    xSPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['x'], k=3, s=0)
    ySPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['y'], k=3, s=0)
    px = xSPL(dinput['MJD'])
    py = ySPL(dinput['MJD'])
    #-- calculate differentials from mean pole positions
    mx = px - mpx
    my = -(py - mpy)

    #-- read ocean pole tide map from Desai (2002)
    ocean_pole_tide_file = os.path.join(tide_dir, 'opoleloadcoefcmcor.txt.gz')
    iur, ilon, ilat = read_ocean_pole_tide(ocean_pole_tide_file)
    #-- interpolate ocean pole tide map from Desai (2002)
    if (METHOD == 'spline'):
        #-- use scipy bivariate splines to interpolate to output points
        f1 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].real,
                                                   kx=1,
                                                   ky=1)
        f2 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].imag,
                                                   kx=1,
                                                   ky=1)
        UR = np.zeros((file_lines), dtype=np.complex128)
        UR.real = f1.ev(dinput['lon'], latitude_geocentric)
        UR.imag = f2.ev(dinput['lon'], latitude_geocentric)
    else:
        #-- create mesh grids of latitude and longitude
        gridlon, gridlat = np.meshgrid(ilon, ilat, indexing='ij')
        interp_points = zip(gridlon.flatten(), gridlat.flatten())
        #-- use scipy griddata to interpolate to output points
        UR = scipy.interpolate.griddata(interp_points,
                                        iur.flatten(),
                                        zip(dinput['lon'],
                                            latitude_geocentric),
                                        method=METHOD)

    #-- calculate radial displacement at time
    Urad = K * atr * np.real((mx * gamma.real + my * gamma.imag) * UR.real +
                             (my * gamma.real - mx * gamma.imag) * UR.imag)

    #-- output to file
    with open(output_file) as f:
        for d, lt, ln, u in zip(dinput['MJD'], dinput['lat'], dinput['lon'],
                                Urad):
            print('{0:g},{1:g},{2:g},{3:f}'.format(d, lt, ln, u), file=f)
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
def compute_OPT_displacements(tide_dir,
                              input_file,
                              output_file,
                              FORMAT='csv',
                              VARIABLES=['time', 'lat', 'lon', 'data'],
                              TIME_UNITS='days since 1858-11-17T00:00:00',
                              PROJECTION='4326',
                              METHOD='spline',
                              VERBOSE=False,
                              MODE=0o775):

    #-- invalid value
    fill_value = -9999.0
    #-- output netCDF4 and HDF5 file attributes
    #-- will be added to YAML header in csv files
    attrib = {}
    #-- latitude
    attrib['lat'] = {}
    attrib['lat']['long_name'] = 'Latitude'
    attrib['lat']['units'] = 'Degrees_North'
    #-- longitude
    attrib['lon'] = {}
    attrib['lon']['long_name'] = 'Longitude'
    attrib['lon']['units'] = 'Degrees_East'
    #-- ocean pole tides
    attrib['tide_oc_pole'] = {}
    attrib['tide_oc_pole']['long_name'] = 'Ocean_Pole_Tide'
    attrib['tide_oc_pole']['description'] = (
        'Ocean_pole_tide_radial_'
        'displacements_time_due_to_polar_motion')
    attrib['tide_oc_pole']['reference'] = (
        'ftp://tai.bipm.org/iers/conv2010/'
        'chapter7/opoleloadcoefcmcor.txt.gz')
    attrib['tide_oc_pole']['units'] = 'meters'
    attrib['tide_oc_pole']['_FillValue'] = fill_value
    #-- Modified Julian Days
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1858-11-17T00:00:00'
    attrib['time']['description'] = 'Modified Julian Days'
    attrib['time']['calendar'] = 'standard'

    #-- read input file to extract time, spatial coordinates and data
    if (FORMAT == 'csv'):
        dinput = pyTMD.spatial.from_ascii(input_file,
                                          columns=VARIABLES,
                                          header=0,
                                          verbose=VERBOSE)
    elif (FORMAT == 'netCDF4'):
        dinput = pyTMD.spatial.from_netCDF4(input_file,
                                            timename=VARIABLES[0],
                                            xname=VARIABLES[2],
                                            yname=VARIABLES[1],
                                            varname=VARIABLES[3],
                                            verbose=VERBOSE)
    elif (FORMAT == 'HDF5'):
        dinput = pyTMD.spatial.from_HDF5(input_file,
                                         timename=VARIABLES[0],
                                         xname=VARIABLES[2],
                                         yname=VARIABLES[1],
                                         varname=VARIABLES[3],
                                         verbose=VERBOSE)

    #-- converting x,y from projection to latitude/longitude
    #-- could try to extract projection attributes from netCDF4 and HDF5 files
    try:
        crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(PROJECTION)))
    except (ValueError, pyproj.exceptions.CRSError):
        crs1 = pyproj.CRS.from_string(PROJECTION)
    crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326))
    transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)
    lon, lat = transformer.transform(dinput['x'].flatten(),
                                     dinput['y'].flatten())

    #-- extract time units from netCDF4 and HDF5 attributes or from TIME_UNITS
    try:
        time_string = dinput['attributes']['time']['units']
    except (TypeError, KeyError):
        epoch1, to_secs = pyTMD.time.parse_date_string(TIME_UNITS)
    else:
        epoch1, to_secs = pyTMD.time.parse_date_string(time_string)
    #-- convert dates to Modified Julian days (days since 1858-11-17T00:00:00)
    MJD = pyTMD.time.convert_delta_time(to_secs * dinput['time'].flatten(),
                                        epoch1=epoch1,
                                        epoch2=(1858, 11, 17, 0, 0, 0),
                                        scale=1.0 / 86400.0)
    #-- add offset to convert to Julian days and then convert to calendar dates
    Y, M, D, h, m, s = convert_julian(2400000.5 + MJD, FORMAT='tuple')
    #-- calculate time in year-decimal format
    time_decimal = convert_calendar_decimal(Y,
                                            M,
                                            DAY=D,
                                            HOUR=h,
                                            MINUTE=m,
                                            SECOND=s)
    #-- number of data points
    n_time = len(time_decimal)

    #-- degrees to radians and arcseconds to radians
    dtr = np.pi / 180.0
    atr = np.pi / 648000.0
    #-- earth and physical parameters (IERS and WGS84)
    G = 6.67428e-11  #-- universal constant of gravitation [m^3/(kg*s^2)]
    GM = 3.986004418e14  #-- geocentric gravitational constant [m^3/s^2]
    a_axis = 6378136.6  #-- WGS84 equatorial radius of the Earth [m]
    flat = 1.0 / 298.257223563  #-- flattening of the WGS84 ellipsoid
    omega = 7.292115e-5  #-- mean rotation rate of the Earth [radians/s]
    rho_w = 1025.0  #-- density of sea water [kg/m^3]
    ge = 9.7803278  #-- mean equatorial gravitational acceleration [m/s^2]
    #-- Linear eccentricity and first numerical eccentricity
    lin_ecc = np.sqrt((2.0 * flat - flat**2) * a_axis**2)
    ecc1 = lin_ecc / a_axis
    #-- tidal love number differential (1 + kl - hl) for pole tide frequencies
    gamma = 0.6870 + 0.0036j

    #-- convert from geodetic latitude to geocentric latitude
    #-- geodetic latitude in radians
    latitude_geodetic_rad = lat * dtr
    #-- prime vertical radius of curvature
    N = a_axis / np.sqrt(1.0 - ecc1**2.0 * np.sin(latitude_geodetic_rad)**2.0)
    #-- calculate X, Y and Z from geodetic latitude and longitude
    X = (N + dinput['data']) * np.cos(latitude_geodetic_rad) * np.cos(
        lon * dtr)
    Y = (N + dinput['data']) * np.cos(latitude_geodetic_rad) * np.sin(
        lon * dtr)
    Z = (N *
         (1.0 - ecc1**2.0) + dinput['data']) * np.sin(latitude_geodetic_rad)
    #-- calculate geocentric latitude and convert to degrees
    latitude_geocentric = np.arctan(Z / np.sqrt(X**2.0 + Y**2.0)) / dtr

    #-- pole tide displacement scale factor
    Hp = np.sqrt(8.0 * np.pi / 15.0) * (omega**2 * a_axis**4) / GM
    K = 4.0 * np.pi * G * rho_w * Hp * a_axis / (3.0 * ge)
    K1 = 4.0 * np.pi * G * rho_w * Hp * a_axis**3 / (3.0 * GM)

    #-- pole tide files (mean and daily)
    mean_pole_file = os.path.join(tide_dir, 'mean_pole_2017-10-23.tab')
    pole_tide_file = os.path.join(tide_dir, 'finals_all_2017-09-01.tab')
    #-- calculate angular coordinates of mean pole at time
    mpx, mpy, fl = iers_mean_pole(mean_pole_file, time_decimal, '2015')
    #-- read IERS daily polar motion values
    EOP = read_iers_EOP(pole_tide_file)
    #-- interpolate daily polar motion values to t1 using cubic splines
    xSPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['x'], k=3, s=0)
    ySPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['y'], k=3, s=0)
    px = xSPL(MJD)
    py = ySPL(MJD)
    #-- calculate differentials from mean pole positions
    mx = px - mpx
    my = -(py - mpy)

    #-- read ocean pole tide map from Desai (2002)
    ocean_pole_tide_file = get_data_path(['data', 'opoleloadcoefcmcor.txt.gz'])
    iur, iun, iue, ilon, ilat = read_ocean_pole_tide(ocean_pole_tide_file)
    #-- interpolate ocean pole tide map from Desai (2002)
    if (METHOD == 'spline'):
        #-- use scipy bivariate splines to interpolate to output points
        f1 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].real,
                                                   kx=1,
                                                   ky=1)
        f2 = scipy.interpolate.RectBivariateSpline(ilon,
                                                   ilat[::-1],
                                                   iur[:, ::-1].imag,
                                                   kx=1,
                                                   ky=1)
        UR = np.zeros((n_time), dtype=np.complex128)
        UR.real = f1.ev(lon, latitude_geocentric)
        UR.imag = f2.ev(lon, latitude_geocentric)
    else:
        #-- use scipy regular grid to interpolate values for a given method
        r1 = scipy.interpolate.RegularGridInterpolator((ilon, ilat[::-1]),
                                                       iur[:, ::-1],
                                                       method=METHOD)
        UR = r1.__call__(np.c_[lon, latitude_geocentric])

    #-- calculate radial displacement at time
    Urad = np.ma.zeros((n_time), fill_value=fill_value)
    Urad.data[:] = K * atr * np.real(
        (mx * gamma.real + my * gamma.imag) * UR.real +
        (my * gamma.real - mx * gamma.imag) * UR.imag)
    #-- replace fill values
    Urad.mask = np.isnan(Urad.data)
    Urad.data[Urad.mask] = Urad.fill_value

    #-- output to file
    output = dict(time=MJD, lon=lon, lat=lat, tide_oc_pole=Urad)
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output,
                               attrib,
                               output_file,
                               delimiter=',',
                               columns=['time', 'lat', 'lon', 'tide_oc_pole'],
                               verbose=VERBOSE)
    elif (FORMAT == 'netCDF4'):
        pyTMD.spatial.to_netCDF4(output, attrib, output_file, verbose=VERBOSE)
    elif (FORMAT == 'HDF5'):
        pyTMD.spatial.to_HDF5(output, attrib, output_file, verbose=VERBOSE)
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
def compute_LPT_icebridge_data(tide_dir, arg, VERBOSE=False, MODE=0o775):

    #-- extract file name and subsetter indices lists
    match_object = re.match('(.*?)(\[(.*?)\])?$', arg)
    input_file = os.path.expanduser(match_object.group(1))
    #-- subset input file to indices
    if match_object.group(2):
        #-- decompress ranges and add to list
        input_subsetter = []
        for i in re.findall('((\d+)-(\d+)|(\d+))', match_object.group(3)):
            input_subsetter.append(int(i[3])) if i[3] else \
             input_subsetter.extend(range(int(i[1]),int(i[2])+1))
    else:
        input_subsetter = None

    #-- output directory for input_file
    DIRECTORY = os.path.dirname(input_file)
    #-- calculate if input files are from ATM or LVIS (+GH)
    regex = {}
    regex['ATM'] = '(BLATM2|ILATM2)_(\d+)_(\d+)_smooth_nadir(.*?)(csv|seg|pt)$'
    regex['ATM1b'] = '(BLATM1b|ILATM1b)_(\d+)_(\d+)(.*?).(qi|TXT|h5)$'
    regex['LVIS'] = '(BLVIS2|BVLIS2|ILVIS2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    regex['LVGH'] = '(ILVGH2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    for key, val in regex.items():
        if re.match(val, os.path.basename(input_file)):
            OIB = key

    #-- HDF5 file attributes
    attrib = {}
    #-- latitude
    attrib['lat'] = {}
    attrib['lat']['long_name'] = 'Latitude_of_measurement'
    attrib['lat']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lat']['units'] = 'Degrees_North'
    #-- longitude
    attrib['lon'] = {}
    attrib['lon']['long_name'] = 'Longitude_of_measurement'
    attrib['lon']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lon']['units'] = 'Degrees_East'
    #-- load pole tides
    attrib['tide_pole'] = {}
    attrib['tide_pole']['long_name'] = 'Solid_Earth_Pole_Tide'
    attrib['tide_pole']['description'] = (
        'Solid_Earth_pole_tide_radial_'
        'displacements_at_the_measurement_position_at_the_acquisition_'
        'time_due_to_polar_motion')
    attrib['tide_pole']['reference'] = ('ftp://tai.bipm.org/iers/conv2010/'
                                        'chapter7/opoleloadcoefcmcor.txt.gz')
    attrib['tide_pole']['units'] = 'meters'
    #-- Modified Julian Days
    attrib['MJD'] = {}
    attrib['MJD']['long_name'] = 'Time'
    attrib['MJD']['description'] = 'Modified Julian Days'
    attrib['MJD']['units'] = 'Days'

    #-- extract information from first input file
    #-- acquisition year, month and day
    #-- number of points
    #-- instrument (PRE-OIB ATM or LVIS, OIB ATM or LVIS)
    if OIB in ('ATM', 'ATM1b'):
        M1, YYMMDD1, HHMMSS1, AX1, SF1 = re.findall(regex[OIB],
                                                    input_file).pop()
        #-- early date strings omitted century and millenia (e.g. 93 for 1993)
        if (len(YYMMDD1) == 6):
            ypre, MM1, DD1 = YYMMDD1[:2], YYMMDD1[2:4], YYMMDD1[4:]
            if (np.float(ypre) >= 90):
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 1900.0)
            else:
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 2000.0)
        elif (len(YYMMDD1) == 8):
            YY1, MM1, DD1 = YYMMDD1[:4], YYMMDD1[4:6], YYMMDD1[6:]
    elif OIB in ('LVIS', 'LVGH'):
        M1, RG1, YY1, MMDD1, RLD1, SS1 = re.findall(regex[OIB],
                                                    input_file).pop()
        MM1, DD1 = MMDD1[:2], MMDD1[2:]

    #-- read data from input_file
    print('{0} -->'.format(input_file)) if VERBOSE else None
    if (OIB == 'ATM'):
        #-- load IceBridge ATM data from input_file
        dinput, file_lines, HEM = read_ATM_icessn_file(input_file,
                                                       input_subsetter)
    elif (OIB == 'ATM1b'):
        #-- load IceBridge Level-1b ATM data from input_file
        dinput, file_lines, HEM = read_ATM_qfit_file(input_file,
                                                     input_subsetter)
    elif OIB in ('LVIS', 'LVGH'):
        #-- load IceBridge LVIS data from input_file
        dinput, file_lines, HEM = read_LVIS_HDF5_file(input_file,
                                                      input_subsetter)

    #-- extract lat/lon
    lon = dinput['lon'][:]
    lat = dinput['lat'][:]
    #-- convert time from UTC time of day to modified julian days (MJD)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    t = dinput['time'][:] / 86400.0 + 51544.5
    #-- convert from MJD to calendar dates
    YY, MM, DD, HH, MN, SS = convert_julian(t + 2400000.5, FORMAT='tuple')
    #-- convert calendar dates into year decimal
    tdec = convert_calendar_decimal(YY,
                                    MM,
                                    DAY=DD,
                                    HOUR=HH,
                                    MINUTE=MN,
                                    SECOND=SS)
    #-- elevation
    h1 = dinput['data'][:]

    #-- degrees to radians
    dtr = np.pi / 180.0
    atr = np.pi / 648000.0
    #-- earth and physical parameters (IERS and WGS84)
    G = 6.67428e-11  #-- universal constant of gravitation [m^3/(kg*s^2)]
    GM = 3.98004418e14  #-- geocentric gravitational constant [m^3/s^2]
    ge = 9.7803278  #-- mean equatorial gravity [m/s^2]
    a_axis = 6378136.6  #-- semimajor axis of the WGS84 ellipsoid [m]
    flat = 1.0 / 298.257223563  #-- flattening of the WGS84 ellipsoid
    b_axis = (1.0 -
              flat) * a_axis  #-- semiminor axis of the WGS84 ellipsoid [m]
    omega = 7.292115e-5  #-- mean rotation rate of the Earth [radians/s]
    #-- tidal love number appropriate for the load tide
    hb2 = 0.6207
    #-- Linear eccentricity, first and second numerical eccentricity
    lin_ecc = np.sqrt((2.0 * flat - flat**2) * a_axis**2)
    ecc1 = lin_ecc / a_axis
    ecc2 = lin_ecc / b_axis
    #-- m parameter [omega^2*a^2*b/(GM)]. p. 70, Eqn.(2-137)
    m = omega**2 * ((1 - flat) * a_axis**3) / GM
    #-- flattening components
    f_2 = -flat + (5.0/2.0)*m + (1.0/2.0)*flat**2.0 - (26.0/7.0)*flat*m + \
     (15.0/4.0)*m**2.0
    f_4 = -(1.0 / 2.0) * flat**2.0 + (5.0 / 2.0) * flat * m

    #-- convert from geodetic latitude to geocentric latitude
    #-- geodetic latitude in radians
    latitude_geodetic_rad = lat * dtr
    #-- prime vertical radius of curvature
    N = a_axis / np.sqrt(1.0 - ecc1**2.0 * np.sin(latitude_geodetic_rad)**2.0)
    #-- calculate X, Y and Z from geodetic latitude and longitude
    X = (N + h1) * np.cos(latitude_geodetic_rad) * np.cos(lon * dtr)
    Y = (N + h1) * np.cos(latitude_geodetic_rad) * np.sin(lon * dtr)
    Z = (N * (1.0 - ecc1**2.0) + h1) * np.sin(latitude_geodetic_rad)
    rr = np.sqrt(X**2.0 + Y**2.0 + Z**2.0)
    #-- calculate geocentric latitude and convert to degrees
    latitude_geocentric = np.arctan(Z / np.sqrt(X**2.0 + Y**2.0)) / dtr
    #-- colatitude and longitude in radians
    theta = dtr * (90.0 - latitude_geocentric)
    phi = lon * dtr

    #-- compute normal gravity at spatial location and elevation of points.
    #-- normal gravity at the equator. p. 79, Eqn.(2-186)
    gamma_a = (GM / (a_axis * b_axis)) * (1.0 - (3.0 / 2.0) * m -
                                          (3.0 / 14.0) * ecc2**2.0 * m)
    #-- Normal gravity. p. 80, Eqn.(2-199)
    gamma_0 = gamma_a * (1.0 + f_2 * np.cos(theta)**2.0 + f_4 *
                         np.sin(np.pi * latitude_geocentric / 180.0)**4.0)
    #-- Normal gravity at height h. p. 82, Eqn.(2-215)
    gamma_h = gamma_0 * (
        1.0 - (2.0 / a_axis) *
        (1.0 + flat + m - 2.0 * flat * np.cos(theta)**2.0) * h1 +
        (3.0 / a_axis**2.0) * h1**2.0)

    #-- pole tide files (mean and daily)
    # mean_pole_file = os.path.join(tide_dir,'mean-pole.tab')
    mean_pole_file = os.path.join(tide_dir, 'mean_pole_2017-10-23.tab')
    pole_tide_file = os.path.join(tide_dir, 'finals_all_2017-09-01.tab')
    #-- read IERS daily polar motion values
    EOP = read_iers_EOP(pole_tide_file)
    #-- create cubic spline interpolations of daily polar motion values
    xSPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['x'], k=3, s=0)
    ySPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['y'], k=3, s=0)
    #-- bad value
    fill_value = -9999.0

    #-- output load pole tide HDF5 file
    #-- form: rg_NASA_LOAD_POLE_TIDE_WGS84_fl1yyyymmddjjjjj.H5
    #-- where rg is the hemisphere flag (GR or AN) for the region
    #-- fl1 and fl2 are the data flags (ATM, LVIS, GLAS)
    #-- yymmddjjjjj is the year, month, day and second of the input file
    #-- output region flags: GR for Greenland and AN for Antarctica
    hem_flag = {'N': 'GR', 'S': 'AN'}
    #-- use starting second to distinguish between files for the day
    JJ1 = np.min(dinput['time']) % 86400
    #-- output file format
    args = (hem_flag[HEM], 'LOAD_POLE_TIDE', OIB, YY1, MM1, DD1, JJ1)
    FILENAME = '{0}_NASA_{1}_WGS84_{2}{3}{4}{5}{6:05.0f}.H5'.format(*args)
    #-- print file information
    print('\t{0}'.format(FILENAME)) if VERBOSE else None

    #-- open output HDF5 file
    fid = h5py.File(os.path.join(DIRECTORY, FILENAME), 'w')

    #-- calculate angular coordinates of mean pole at time tdec
    mpx, mpy, fl = iers_mean_pole(mean_pole_file, tdec, '2015')
    #-- interpolate daily polar motion values to time using cubic splines
    px = xSPL(t)
    py = ySPL(t)
    #-- calculate differentials from mean pole positions
    mx = px - mpx
    my = -(py - mpy)
    #-- calculate radial displacement at time
    dfactor = -hb2 * atr * (omega**2 * rr**2) / (2.0 * gamma_h)
    Sr = dfactor * np.sin(2.0 * theta) * (mx * np.cos(phi) + my * np.sin(phi))

    #-- add latitude and longitude to output file
    for key in ['lat', 'lon']:
        #-- Defining the HDF5 dataset variables for lat/lon
        h5 = fid.create_dataset(key, (file_lines, ),
                                data=dinput[key][:],
                                dtype=dinput[key].dtype,
                                compression='gzip')
        #-- add HDF5 variable attributes
        for att_name, att_val in attrib[key].items():
            h5.attrs[att_name] = att_val
        #-- attach dimensions
        h5.dims[0].label = 'RECORD_SIZE'

    #-- output tides to HDF5 dataset
    h5 = fid.create_dataset('tide_pole', (file_lines, ),
                            data=Sr,
                            dtype=Sr.dtype,
                            compression='gzip')
    #-- add HDF5 variable attributes
    h5.attrs['_FillValue'] = fill_value
    for att_name, att_val in attrib['tide_pole'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- output days to HDF5 dataset
    h5 = fid.create_dataset('MJD', (file_lines, ),
                            data=t,
                            dtype=t.dtype,
                            compression='gzip')
    #-- add HDF5 variable attributes
    for att_name, att_val in attrib['MJD'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- HDF5 file attributes
    fid.attrs['featureType'] = 'trajectory'
    fid.attrs['title'] = 'Load_Pole_Tide_correction_for_elevation_measurements'
    fid.attrs['summary'] = ('Solid_Earth_pole_tide_radial_displacements_'
                            'computed_at_elevation_measurements.')
    fid.attrs['project'] = 'NASA_Operation_IceBridge'
    fid.attrs['processing_level'] = '4'
    fid.attrs['date_created'] = time.strftime('%Y-%m-%d', time.localtime())
    #-- add attributes for input files
    fid.attrs['elevation_file'] = os.path.basename(input_file)
    #-- add geospatial and temporal attributes
    fid.attrs['geospatial_lat_min'] = dinput['lat'].min()
    fid.attrs['geospatial_lat_max'] = dinput['lat'].max()
    fid.attrs['geospatial_lon_min'] = dinput['lon'].min()
    fid.attrs['geospatial_lon_max'] = dinput['lon'].max()
    fid.attrs['geospatial_lat_units'] = "degrees_north"
    fid.attrs['geospatial_lon_units'] = "degrees_east"
    fid.attrs['geospatial_ellipsoid'] = "WGS84"
    fid.attrs['time_type'] = 'UTC'

    #-- convert start/end time from MJD into Julian days
    JD_start = np.min(t) + 2400000.5
    JD_end = np.max(t) + 2400000.5
    #-- convert to calendar date with convert_julian.py
    cal = convert_julian(np.array([JD_start, JD_end]), ASTYPE=np.int)
    #-- add attributes with measurement date start, end and duration
    args = (cal['hour'][0], cal['minute'][0], cal['second'][0])
    fid.attrs['RangeBeginningTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['hour'][-1], cal['minute'][-1], cal['second'][-1])
    fid.attrs['RangeEndingTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['year'][0], cal['month'][0], cal['day'][0])
    fid.attrs['RangeBeginningDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    args = (cal['year'][-1], cal['month'][-1], cal['day'][-1])
    fid.attrs['RangeEndingDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    duration = np.round(JD_end * 86400.0 - JD_start * 86400.0)
    fid.attrs['DurationTimeSeconds'] = '{0:0.0f}'.format(duration)
    #-- close the output HDF5 dataset
    fid.close()
    #-- change the permissions level to MODE
    os.chmod(os.path.join(DIRECTORY, FILENAME), MODE)
def compute_tides_icebridge_data(tide_dir,
                                 arg,
                                 MODEL,
                                 METHOD=None,
                                 VERBOSE=False,
                                 MODE=0o775):

    #-- extract file name and subsetter indices lists
    match_object = re.match('(.*?)(\[(.*?)\])?$', arg)
    input_file = os.path.expanduser(match_object.group(1))
    #-- subset input file to indices
    if match_object.group(2):
        #-- decompress ranges and add to list
        input_subsetter = []
        for i in re.findall('((\d+)-(\d+)|(\d+))', match_object.group(3)):
            input_subsetter.append(int(i[3])) if i[3] else \
             input_subsetter.extend(range(int(i[1]),int(i[2])+1))
    else:
        input_subsetter = None

    #-- output directory for input_file
    DIRECTORY = os.path.dirname(input_file)
    #-- calculate if input files are from ATM or LVIS (+GH)
    regex = {}
    regex['ATM'] = '(BLATM2|ILATM2)_(\d+)_(\d+)_smooth_nadir(.*?)(csv|seg|pt)$'
    regex['ATM1b'] = '(BLATM1b|ILATM1b)_(\d+)_(\d+)(.*?).(qi|TXT|h5)$'
    regex['LVIS'] = '(BLVIS2|BVLIS2|ILVIS2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    regex['LVGH'] = '(ILVGH2)_(.*?)(\d+)_(\d+)_(R\d+)_(\d+).H5$'
    for key, val in regex.items():
        if re.match(val, os.path.basename(input_file)):
            OIB = key

    #-- HDF5 file attributes
    attrib = dict(lon={}, lat={}, tide={}, day={})
    #-- select between tide models
    if (MODEL == 'CATS0201'):
        grid_file = os.path.join(tide_dir, 'cats0201_tmd', 'grid_CATS')
        model_file = os.path.join(tide_dir, 'cats0201_tmd', 'h0_CATS02_01')
        reference = 'https://mail.esr.org/polar_tide_models/Model_CATS0201.html'
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir, 'CATS2008', 'grid_CATS2008a_opt')
        model_file = os.path.join(tide_dir, 'CATS2008', 'hf.CATS2008.out')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/cats2008/')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        type = 'z'
    elif (MODEL == 'CATS2008_load'):
        grid_file = os.path.join(tide_dir, 'CATS2008a_SPOTL_Load',
                                 'grid_CATS2008a_opt')
        model_file = os.path.join(tide_dir, 'CATS2008a_SPOTL_Load',
                                  'h_CATS2008a_SPOTL_load')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/cats2008/')
        attrib['tide']['long_name'] = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        type = 'z'
    elif (MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas')
        grid_file = 'grid_tpxo9_atlas.nc.gz'
        model_files = [
            'h_q1_tpxo9_atlas_30.nc.gz', 'h_o1_tpxo9_atlas_30.nc.gz',
            'h_p1_tpxo9_atlas_30.nc.gz', 'h_k1_tpxo9_atlas_30.nc.gz',
            'h_n2_tpxo9_atlas_30.nc.gz', 'h_m2_tpxo9_atlas_30.nc.gz',
            'h_s2_tpxo9_atlas_30.nc.gz', 'h_k2_tpxo9_atlas_30.nc.gz',
            'h_m4_tpxo9_atlas_30.nc.gz', 'h_ms4_tpxo9_atlas_30.nc.gz',
            'h_mn4_tpxo9_atlas_30.nc.gz', 'h_2n2_tpxo9_atlas_30.nc.gz'
        ]
        reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'netcdf'
        type = 'z'
        SCALE = 1.0 / 1000.0
    elif (MODEL == 'TPXO9.1'):
        grid_file = os.path.join(tide_dir, 'TPXO9.1', 'DATA', 'grid_tpxo9')
        model_file = os.path.join(tide_dir, 'TPXO9.1', 'DATA', 'h_tpxo9.v1')
        reference = 'http://volkov.oce.orst.edu/tides/global.html'
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (MODEL == 'TPXO8-atlas'):
        grid_file = os.path.join(tide_dir, 'tpxo8_atlas',
                                 'grid_tpxo8atlas_30_v1')
        model_file = os.path.join(tide_dir, 'tpxo8_atlas',
                                  'hf.tpxo8_atlas_30_v1')
        reference = 'http://volkov.oce.orst.edu/tides/tpxo8_atlas.html'
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'ATLAS'
        EPSG = '4326'
        type = 'z'
    elif (MODEL == 'TPXO7.2'):
        grid_file = os.path.join(tide_dir, 'TPXO7.2_tmd', 'grid_tpxo7.2')
        model_file = os.path.join(tide_dir, 'TPXO7.2_tmd', 'h_tpxo7.2')
        reference = 'http://volkov.oce.orst.edu/tides/global.html'
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (MODEL == 'TPXO7.2_load'):
        grid_file = os.path.join(tide_dir, 'TPXO7.2_load', 'grid_tpxo6.2')
        model_file = os.path.join(tide_dir, 'TPXO7.2_load', 'h_tpxo7.2_load')
        reference = 'http://volkov.oce.orst.edu/tides/global.html'
        attrib['tide']['long_name'] = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (MODEL == 'AODTM-5'):
        grid_file = os.path.join(tide_dir, 'aodtm5_tmd', 'grid_Arc5km')
        model_file = os.path.join(tide_dir, 'aodtm5_tmd', 'h0_Arc5km.oce')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/aodtm-5/')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (MODEL == 'AOTIM-5'):
        grid_file = os.path.join(tide_dir, 'aotim5_tmd', 'grid_Arc5km')
        model_file = os.path.join(tide_dir, 'aotim5_tmd', 'h_Arc5km.oce')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/aotim-5/')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (MODEL == 'GOT4.7'):
        model_directory = os.path.join(tide_dir, 'GOT4.7', 'grids_oceantide')
        model_files = [
            'q1.d.gz', 'o1.d.gz', 'p1.d.gz', 'k1.d.gz', 'n2.d.gz', 'm2.d.gz',
            's2.d.gz', 'k2.d.gz', 's1.d.gz', 'm4.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (MODEL == 'GOT4.7_load'):
        model_directory = os.path.join(tide_dir, 'GOT4.7', 'grids_loadtide')
        model_files = [
            'q1load.d.gz', 'o1load.d.gz', 'p1load.d.gz', 'k1load.d.gz',
            'n2load.d.gz', 'm2load.d.gz', 's2load.d.gz', 'k2load.d.gz',
            's1load.d.gz', 'm4load.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (MODEL == 'GOT4.8'):
        model_directory = os.path.join(tide_dir, 'got4.8', 'grids_oceantide')
        model_files = [
            'q1.d.gz', 'o1.d.gz', 'p1.d.gz', 'k1.d.gz', 'n2.d.gz', 'm2.d.gz',
            's2.d.gz', 'k2.d.gz', 's1.d.gz', 'm4.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (MODEL == 'GOT4.8_load'):
        model_directory = os.path.join(tide_dir, 'got4.8', 'grids_loadtide')
        model_files = [
            'q1load.d.gz', 'o1load.d.gz', 'p1load.d.gz', 'k1load.d.gz',
            'n2load.d.gz', 'm2load.d.gz', 's2load.d.gz', 'k2load.d.gz',
            's1load.d.gz', 'm4load.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (MODEL == 'GOT4.10'):
        model_directory = os.path.join(tide_dir, 'GOT4.10c', 'grids_oceantide')
        model_files = [
            'q1.d.gz', 'o1.d.gz', 'p1.d.gz', 'k1.d.gz', 'n2.d.gz', 'm2.d.gz',
            's2.d.gz', 'k2.d.gz', 's1.d.gz', 'm4.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (MODEL == 'GOT4.10_load'):
        model_directory = os.path.join(tide_dir, 'GOT4.10c', 'grids_loadtide')
        model_files = [
            'q1load.d.gz', 'o1load.d.gz', 'p1load.d.gz', 'k1load.d.gz',
            'n2load.d.gz', 'm2load.d.gz', 's2load.d.gz', 'k2load.d.gz',
            's1load.d.gz', 'm4load.d.gz'
        ]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        attrib['tide']['long_name'] = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0

    #-- latitude
    attrib['lat']['long_name'] = 'Latitude_of_measurement'
    attrib['lat']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lat']['units'] = 'Degrees_North'
    #-- longitude
    attrib['lon']['long_name'] = 'Longitude_of_measurement'
    attrib['lon']['description'] = ('Corresponding_to_the_measurement_'
                                    'position_at_the_acquisition_time')
    attrib['lon']['units'] = 'Degrees_East'
    #-- tides
    attrib['tide']['description'] = (
        'Tidal_elevation_from_harmonic_constants_'
        'at_the_measurement_position_at_the_acquisition_time')
    attrib['tide']['reference'] = reference
    attrib['tide']['model'] = MODEL
    attrib['tide']['units'] = 'meters'
    #-- days
    attrib['day']['long_name'] = 'Time'
    attrib['day']['description'] = 'Days relative to 1992-01-01 (MJD:48622)'
    attrib['day']['units'] = 'Days'

    #-- extract information from first input file
    #-- acquisition year, month and day
    #-- number of points
    #-- instrument (PRE-OIB ATM or LVIS, OIB ATM or LVIS)
    if OIB in ('ATM', 'ATM1b'):
        M1, YYMMDD1, HHMMSS1, AX1, SF1 = re.findall(regex[OIB],
                                                    input_file).pop()
        #-- early date strings omitted century and millenia (e.g. 93 for 1993)
        if (len(YYMMDD1) == 6):
            ypre, MM1, DD1 = YYMMDD1[:2], YYMMDD1[2:4], YYMMDD1[4:]
            if (np.float(ypre) >= 90):
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 1900.0)
            else:
                YY1 = '{0:4.0f}'.format(np.float(ypre) + 2000.0)
        elif (len(YYMMDD1) == 8):
            YY1, MM1, DD1 = YYMMDD1[:4], YYMMDD1[4:6], YYMMDD1[6:]
    elif OIB in ('LVIS', 'LVGH'):
        M1, RG1, YY1, MMDD1, RLD1, SS1 = re.findall(regex[OIB],
                                                    input_file).pop()
        MM1, DD1 = MMDD1[:2], MMDD1[2:]

    #-- read data from input_file
    print('{0} -->'.format(input_file)) if VERBOSE else None
    if (OIB == 'ATM'):
        #-- load IceBridge ATM data from input_file
        dinput, file_lines, HEM = read_ATM_icessn_file(input_file,
                                                       input_subsetter)
    elif (OIB == 'ATM1b'):
        #-- load IceBridge Level-1b ATM data from input_file
        dinput, file_lines, HEM = read_ATM_qfit_file(input_file,
                                                     input_subsetter)
    elif OIB in ('LVIS', 'LVGH'):
        #-- load IceBridge LVIS data from input_file
        dinput, file_lines, HEM = read_LVIS_HDF5_file(input_file,
                                                      input_subsetter)

    #-- extract lat/lon
    lon = dinput['lon'][:]
    lat = dinput['lat'][:]
    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    t = dinput['time'][:] / 86400.0 + 2922.5
    #-- elevation
    h1 = dinput['data'][:]

    #-- read tidal constants and interpolate to grid points
    if model_format in ('OTIS', 'ATLAS'):
        amp, ph, D, c = extract_tidal_constants(lon,
                                                lat,
                                                grid_file,
                                                model_file,
                                                EPSG,
                                                type,
                                                METHOD=METHOD,
                                                GRID=model_format)
        deltat = np.zeros_like(t)
    elif model_format in ('netcdf'):
        amp, ph, D, c = extract_netcdf_constants(lon,
                                                 lat,
                                                 model_directory,
                                                 grid_file,
                                                 model_files,
                                                 type,
                                                 METHOD=METHOD,
                                                 SCALE=SCALE)
        deltat = np.zeros_like(t)
    elif (model_format == 'GOT'):
        amp, ph = extract_GOT_constants(lon,
                                        lat,
                                        model_directory,
                                        model_files,
                                        METHOD=METHOD,
                                        SCALE=SCALE)
        #-- convert time to Modified Julian Days for calculating deltat
        delta_file = os.path.join(tide_dir, 'deltat.data')
        deltat = calc_delta_time(delta_file, t + 48622.0)

    cph = -1j * ph * np.pi / 180.0
    hc = amp * np.exp(cph)

    #-- output tidal HDF5 file
    #-- form: rg_NASA_model_TIDES_WGS84_fl1yyyymmddjjjjj.H5
    #-- where rg is the hemisphere flag (GR or AN) for the region
    #-- model is the tidal MODEL flag (e.g. CATS0201)
    #-- fl1 and fl2 are the data flags (ATM, LVIS, GLAS)
    #-- yymmddjjjjj is the year, month, day and second of the input file
    #-- output region flags: GR for Greenland and AN for Antarctica
    hem_flag = {'N': 'GR', 'S': 'AN'}
    #-- use starting second to distinguish between files for the day
    JJ1 = np.min(dinput['time']) % 86400
    #-- output file format
    args = (hem_flag[HEM], MODEL, OIB, YY1, MM1, DD1, JJ1)
    FILENAME = '{0}_NASA_{1}_TIDES_WGS84_{2}{3}{4}{5}{6:05.0f}.H5'.format(
        *args)
    #-- print file information
    print('\t{0}'.format(FILENAME)) if VERBOSE else None

    #-- open output HDF5 file
    fid = h5py.File(os.path.join(DIRECTORY, FILENAME), 'w')

    #-- predict tidal elevations at time and infer minor corrections
    tide = predict_tide_drift(t,
                              hc,
                              c,
                              DELTAT=deltat,
                              CORRECTIONS=model_format)
    tide += infer_minor_corrections(t,
                                    hc,
                                    c,
                                    DELTAT=deltat,
                                    CORRECTIONS=model_format)
    #-- replace invalid values with fill value
    fill_value = -9999.0
    tide.data[tide.mask] = fill_value

    #-- add latitude and longitude to output file
    for key in ['lat', 'lon']:
        #-- Defining the HDF5 dataset variables for lat/lon
        h5 = fid.create_dataset(key, (file_lines, ),
                                data=dinput[key][:],
                                dtype=dinput[key].dtype,
                                compression='gzip')
        #-- add HDF5 variable attributes
        for att_name, att_val in attrib[key].items():
            h5.attrs[att_name] = att_val
        #-- attach dimensions
        h5.dims[0].label = 'RECORD_SIZE'

    #-- output tides to HDF5 dataset
    h5 = fid.create_dataset('tide', (file_lines, ),
                            data=tide,
                            dtype=tide.dtype,
                            fillvalue=fill_value,
                            compression='gzip')
    #-- add HDF5 variable attributes
    tide_count = np.count_nonzero(tide != fill_value)
    h5.attrs['tide_count'] = tide_count
    h5.attrs['_FillValue'] = fill_value
    for att_name, att_val in attrib['tide'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- output days to HDF5 dataset
    h5 = fid.create_dataset('day', (file_lines, ),
                            data=t,
                            dtype=t.dtype,
                            compression='gzip')
    #-- add HDF5 variable attributes
    for att_name, att_val in attrib['day'].items():
        h5.attrs[att_name] = att_val
    #-- attach dimensions
    h5.dims[0].label = 'RECORD_SIZE'

    #-- HDF5 file attributes
    fid.attrs['featureType'] = 'trajectory'
    fid.attrs['title'] = 'Tidal_correction_for_elevation_measurements'
    fid.attrs['summary'] = ('Tidal_correction_computed_at_elevation_'
                            'measurements_using_a_tidal_model_driver.')
    fid.attrs['project'] = 'NASA_Operation_IceBridge'
    fid.attrs['processing_level'] = '4'
    fid.attrs['date_created'] = time.strftime('%Y-%m-%d', time.localtime())
    #-- add attributes for input files
    fid.attrs['elevation_file'] = os.path.basename(input_file)
    fid.attrs['tide_model'] = MODEL
    #-- add geospatial and temporal attributes
    fid.attrs['geospatial_lat_min'] = lat.min()
    fid.attrs['geospatial_lat_max'] = lat.max()
    fid.attrs['geospatial_lon_min'] = lon.min()
    fid.attrs['geospatial_lon_max'] = lon.max()
    fid.attrs['geospatial_lat_units'] = "degrees_north"
    fid.attrs['geospatial_lon_units'] = "degrees_east"
    fid.attrs['geospatial_ellipsoid'] = "WGS84"
    fid.attrs['time_type'] = 'UTC'

    #-- convert start/end time from days since 1992-01-01 into Julian days
    JD_start = np.min(t) + 2448622.5
    JD_end = np.max(t) + 2448622.5
    #-- convert to calendar date with convert_julian.py
    cal = convert_julian(np.array([JD_start, JD_end]), ASTYPE=np.int)
    #-- add attributes with measurement date start, end and duration
    args = (cal['hour'][0], cal['minute'][0], cal['second'][0])
    fid.attrs['RangeBeginningTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['hour'][-1], cal['minute'][-1], cal['second'][-1])
    fid.attrs['RangeEndingTime'] = '{0:02d}:{1:02d}:{2:02d}'.format(*args)
    args = (cal['year'][0], cal['month'][0], cal['day'][0])
    fid.attrs['RangeBeginningDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    args = (cal['year'][-1], cal['month'][-1], cal['day'][-1])
    fid.attrs['RangeEndingDate'] = '{0:4d}-{1:02d}-{2:02d}'.format(*args)
    duration = np.round(JD_end * 86400.0 - JD_start * 86400.0)
    fid.attrs['DurationTimeSeconds'] = '{0:0.0f}'.format(duration)
    #-- close the output HDF5 dataset
    fid.close()
    #-- change the permissions level to MODE
    os.chmod(os.path.join(DIRECTORY, FILENAME), MODE)
def compute_LPT_displacements(tide_dir,
                              input_file,
                              output_file,
                              FORMAT='csv',
                              VARIABLES=['time', 'lat', 'lon', 'data'],
                              TIME_UNITS='days since 1858-11-17T00:00:00',
                              PROJECTION='4326',
                              VERBOSE=False,
                              MODE=0o775):

    #-- invalid value
    fill_value = -9999.0
    #-- output netCDF4 and HDF5 file attributes
    #-- will be added to YAML header in csv files
    attrib = {}
    #-- latitude
    attrib['lat'] = {}
    attrib['lat']['long_name'] = 'Latitude'
    attrib['lat']['units'] = 'Degrees_North'
    #-- longitude
    attrib['lon'] = {}
    attrib['lon']['long_name'] = 'Longitude'
    attrib['lon']['units'] = 'Degrees_East'
    #-- load pole tides
    attrib['tide_pole'] = {}
    attrib['tide_pole']['long_name'] = 'Solid_Earth_Pole_Tide'
    attrib['tide_pole']['description'] = ('Solid_Earth_pole_tide_radial_'
                                          'displacements_due_to_polar_motion')
    attrib['tide_pole']['reference'] = ('ftp://tai.bipm.org/iers/conv2010/'
                                        'chapter7/opoleloadcoefcmcor.txt.gz')
    attrib['tide_pole']['units'] = 'meters'
    attrib['tide_pole']['_FillValue'] = fill_value
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1858-11-17T00:00:00'
    attrib['time']['description'] = 'Modified Julian Days'
    attrib['time']['calendar'] = 'standard'

    #-- read input file to extract time, spatial coordinates and data
    if (FORMAT == 'csv'):
        dinput = pyTMD.spatial.from_ascii(input_file,
                                          columns=VARIABLES,
                                          header=0,
                                          verbose=VERBOSE)
    elif (FORMAT == 'netCDF4'):
        dinput = pyTMD.spatial.from_netCDF4(input_file,
                                            timename=VARIABLES[0],
                                            xname=VARIABLES[2],
                                            yname=VARIABLES[1],
                                            varname=VARIABLES[3],
                                            verbose=VERBOSE)
    elif (FORMAT == 'HDF5'):
        dinput = pyTMD.spatial.from_HDF5(input_file,
                                         timename=VARIABLES[0],
                                         xname=VARIABLES[2],
                                         yname=VARIABLES[1],
                                         varname=VARIABLES[3],
                                         verbose=VERBOSE)

    #-- converting x,y from projection to latitude/longitude
    #-- could try to extract projection attributes from netCDF4 and HDF5 files
    try:
        crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(PROJECTION)))
    except (ValueError, pyproj.exceptions.CRSError):
        crs1 = pyproj.CRS.from_string(PROJECTION)
    crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326))
    transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)
    lon, lat = transformer.transform(dinput['x'].flatten(),
                                     dinput['y'].flatten())

    #-- extract time units from netCDF4 and HDF5 attributes or from TIME_UNITS
    try:
        time_string = dinput['attributes']['time']['units']
    except (TypeError, KeyError):
        epoch1, to_secs = pyTMD.time.parse_date_string(TIME_UNITS)
    else:
        epoch1, to_secs = pyTMD.time.parse_date_string(time_string)
    #-- convert dates to Modified Julian days (days since 1858-11-17T00:00:00)
    MJD = pyTMD.time.convert_delta_time(to_secs * dinput['time'].flatten(),
                                        epoch1=epoch1,
                                        epoch2=(1858, 11, 17, 0, 0, 0),
                                        scale=1.0 / 86400.0)
    #-- add offset to convert to Julian days and then convert to calendar dates
    Y, M, D, h, m, s = convert_julian(2400000.5 + MJD, FORMAT='tuple')
    #-- calculate time in year-decimal format
    time_decimal = convert_calendar_decimal(Y,
                                            M,
                                            DAY=D,
                                            HOUR=h,
                                            MINUTE=m,
                                            SECOND=s)
    #-- number of data points
    n_time = len(time_decimal)

    #-- degrees to radians
    dtr = np.pi / 180.0
    atr = np.pi / 648000.0
    #-- earth and physical parameters (IERS and WGS84)
    GM = 3.986004418e14  #-- geocentric gravitational constant [m^3/s^2]
    a_axis = 6378136.6  #-- semimajor axis of the WGS84 ellipsoid [m]
    flat = 1.0 / 298.257223563  #-- flattening of the WGS84 ellipsoid
    b_axis = (1.0 -
              flat) * a_axis  #-- semiminor axis of the WGS84 ellipsoid [m]
    omega = 7.292115e-5  #-- mean rotation rate of the Earth [radians/s]
    #-- tidal love number appropriate for the load tide
    hb2 = 0.6207
    #-- Linear eccentricity, first and second numerical eccentricity
    lin_ecc = np.sqrt((2.0 * flat - flat**2) * a_axis**2)
    ecc1 = lin_ecc / a_axis
    ecc2 = lin_ecc / b_axis
    #-- m parameter [omega^2*a^2*b/(GM)]. p. 70, Eqn.(2-137)
    m = omega**2 * ((1 - flat) * a_axis**3) / GM
    #-- flattening components
    f_2 = -flat + (5.0/2.0)*m + (1.0/2.0)*flat**2.0 - (26.0/7.0)*flat*m + \
        (15.0/4.0)*m**2.0
    f_4 = -(1.0 / 2.0) * flat**2.0 + (5.0 / 2.0) * flat * m

    #-- convert from geodetic latitude to geocentric latitude
    #-- geodetic latitude in radians
    latitude_geodetic_rad = lat * dtr
    #-- prime vertical radius of curvature
    N = a_axis / np.sqrt(1.0 - ecc1**2.0 * np.sin(latitude_geodetic_rad)**2.0)
    #-- calculate X, Y and Z from geodetic latitude and longitude
    X = (N + dinput['data']) * np.cos(latitude_geodetic_rad) * np.cos(
        lon * dtr)
    Y = (N + dinput['data']) * np.cos(latitude_geodetic_rad) * np.sin(
        lon * dtr)
    Z = (N *
         (1.0 - ecc1**2.0) + dinput['data']) * np.sin(latitude_geodetic_rad)
    rr = np.sqrt(X**2.0 + Y**2.0 + Z**2.0)
    #-- calculate geocentric latitude and convert to degrees
    latitude_geocentric = np.arctan(Z / np.sqrt(X**2.0 + Y**2.0)) / dtr
    #-- geocentric colatitude and longitude in radians
    theta = dtr * (90.0 - latitude_geocentric)
    phi = lon * dtr

    #-- compute normal gravity at spatial location and elevation of points.
    #-- normal gravity at the equator. p. 79, Eqn.(2-186)
    gamma_a = (GM / (a_axis * b_axis)) * (1.0 - (3.0 / 2.0) * m -
                                          (3.0 / 14.0) * ecc2**2.0 * m)
    #-- Normal gravity. p. 80, Eqn.(2-199)
    gamma_0 = gamma_a * (1.0 + f_2 * np.cos(theta)**2.0 + f_4 *
                         np.sin(np.pi * latitude_geocentric / 180.0)**4.0)
    #-- Normal gravity at height h. p. 82, Eqn.(2-215)
    gamma_h = gamma_0 * (
        1.0 - (2.0 / a_axis) *
        (1.0 + flat + m - 2.0 * flat * np.cos(theta)**2.0) * dinput['data'] +
        (3.0 / a_axis**2.0) * dinput['data']**2.0)

    #-- pole tide files (mean and daily)
    mean_pole_file = os.path.join(tide_dir, 'mean_pole_2017-10-23.tab')
    pole_tide_file = os.path.join(tide_dir, 'finals_all_2017-09-01.tab')
    #-- calculate angular coordinates of mean pole at time
    mpx, mpy, fl = iers_mean_pole(mean_pole_file, time_decimal, '2015')
    #-- read IERS daily polar motion values
    EOP = read_iers_EOP(pole_tide_file)
    #-- interpolate daily polar motion values to t1 using cubic splines
    xSPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['x'], k=3, s=0)
    ySPL = scipy.interpolate.UnivariateSpline(EOP['MJD'], EOP['y'], k=3, s=0)
    px = xSPL(MJD)
    py = ySPL(MJD)
    #-- calculate differentials from mean pole positions
    mx = px - mpx
    my = -(py - mpy)

    #-- calculate radial displacement at time
    dfactor = -hb2 * atr * (omega**2 * rr**2) / (2.0 * gamma_h)
    Srad = np.ma.zeros((n_time), fill_value=fill_value)
    Srad.data[:] = dfactor * np.sin(
        2.0 * theta) * (mx * np.cos(phi) + my * np.sin(phi))
    #-- replace fill values
    Srad.mask = np.isnan(Srad.data)
    Srad.data[Srad.mask] = Srad.fill_value

    #-- output to file
    output = dict(time=MJD, lon=lon, lat=lat, tide_pole=Srad)
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output,
                               attrib,
                               output_file,
                               delimiter=',',
                               columns=['time', 'lat', 'lon', 'tide_pole'],
                               verbose=VERBOSE)
    elif (FORMAT == 'netCDF4'):
        pyTMD.spatial.to_netCDF4(output, attrib, output_file, verbose=VERBOSE)
    elif (FORMAT == 'HDF5'):
        pyTMD.spatial.to_HDF5(output, attrib, output_file, verbose=VERBOSE)
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)