def compute_LPET_ICESat2(INPUT_FILE, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd', level=loglevel)

    #-- read data from input file
    logger.info('{0} -->'.format(INPUT_FILE))
    IS2_atl03_mds, IS2_atl03_attrs, IS2_atl03_beams = read_HDF5_ATL03_main(
        INPUT_FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$')
    try:
        SUB, PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output long-period equilibrium tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        OUTPUT_FILE = '{0}_{1}{2}'.format(fileBasename, 'LPET', fileExtension)
    else:
        #-- output long-period equilibrium tide HDF5 file for ASAS/NSIDC granules
        args = (PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX)
        file_format = '{0}_LPET_{1}{2}{3}{4}{5}{6}_{7}{8}{9}_{10}_{11}{12}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl03_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl03_tide = {}
    IS2_atl03_fill = {}
    IS2_atl03_dims = {}
    IS2_atl03_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl03_tide['ancillary_data'] = {}
    IS2_atl03_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl03_tide['ancillary_data'][key] = IS2_atl03_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl03_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl03_attrs['ancillary_data'][key].items(
        ):
            IS2_atl03_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl03_beams):
        #-- output data dictionaries for beam
        IS2_atl03_tide[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_fill[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_dims[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_tide_attrs[gtx] = dict(geolocation={}, geophys_corr={})

        #-- read data and attributes for beam
        val, attrs = read_HDF5_ATL03_beam(INPUT_FILE, gtx, ATTRIBUTES=True)
        #-- number of segments
        n_seg = len(val['geolocation']['segment_id'])
        #-- extract variables for computing equilibrium tides
        segment_id = val['geolocation']['segment_id'].copy()
        delta_time = val['geolocation']['delta_time'].copy()
        lon = val['geolocation']['reference_photon_lon'].copy()
        lat = val['geolocation']['reference_photon_lat'].copy()
        #-- invalid value
        fv = attrs['geolocation']['sigma_h']['_FillValue']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + delta_time
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- interpolate delta times from calendar dates to tide time
        delta_file = pyTMD.utilities.get_data_path(
            ['data', 'merged_deltat.data'])
        deltat = calc_delta_time(delta_file, tide_time)

        #-- predict long-period equilibrium tides at latitudes and time
        tide_lpe = compute_equilibrium_tide(tide_time + deltat, lat)

        #-- group attributes for beam
        IS2_atl03_tide_attrs[gtx]['Description'] = attrs['Description']
        IS2_atl03_tide_attrs[gtx]['atlas_pce'] = attrs['atlas_pce']
        IS2_atl03_tide_attrs[gtx]['atlas_beam_type'] = attrs['atlas_beam_type']
        IS2_atl03_tide_attrs[gtx]['groundtrack_id'] = attrs['groundtrack_id']
        IS2_atl03_tide_attrs[gtx]['atmosphere_profile'] = attrs[
            'atmosphere_profile']
        IS2_atl03_tide_attrs[gtx]['atlas_spot_number'] = attrs[
            'atlas_spot_number']
        IS2_atl03_tide_attrs[gtx]['sc_orientation'] = attrs['sc_orientation']

        #-- group attributes for geolocation
        IS2_atl03_tide_attrs[gtx]['geolocation']['Description'] = (
            "Contains parameters related to "
            "geolocation.  The rate of all of these parameters is at the rate corresponding to the "
            "ICESat-2 Geolocation Along Track Segment interval (nominally 20 m along-track)."
        )
        IS2_atl03_tide_attrs[gtx]['geolocation']['data_rate'] = (
            "Data within this group are "
            "stored at the ICESat-2 20m segment rate.")
        #-- group attributes for geophys_corr
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['Description'] = (
            "Contains parameters used to "
            "correct photon heights for geophysical effects, such as tides.  These parameters are "
            "posted at the same interval as the ICESat-2 Geolocation Along-Track Segment interval "
            "(nominally 20m along-track).")
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['data_rate'] = (
            "These parameters are stored at "
            "the ICESat-2 Geolocation Along Track Segment rate (nominally every 20 m along-track)."
        )

        #-- geolocation, time and segment ID
        #-- delta time in geolocation group
        IS2_atl03_tide[gtx]['geolocation']['delta_time'] = delta_time
        IS2_atl03_fill[gtx]['geolocation']['delta_time'] = None
        IS2_atl03_dims[gtx]['geolocation']['delta_time'] = None
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'standard_name'] = "time"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'calendar'] = "standard"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time']['description'] = (
            "Elapsed seconds "
            "from the ATLAS SDP GPS Epoch, corresponding to the transmit time of the reference "
            "photon. The ATLAS Standard Data Products (SDP) epoch offset is defined within "
            "/ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds between the GPS epoch "
            "(1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By adding the offset "
            "contained within atlas_sdp_gps_epoch to delta time parameters, the time in gps_seconds "
            "relative to the GPS epoch can be computed.")
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time']['coordinates'] = \
            "segment_id reference_photon_lat reference_photon_lon"
        #-- delta time in geophys_corr group
        IS2_atl03_tide[gtx]['geophys_corr']['delta_time'] = delta_time
        IS2_atl03_fill[gtx]['geophys_corr']['delta_time'] = None
        IS2_atl03_dims[gtx]['geophys_corr']['delta_time'] = None
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'] = {}
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'standard_name'] = "time"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'calendar'] = "standard"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time']['description'] = (
            "Elapsed seconds "
            "from the ATLAS SDP GPS Epoch, corresponding to the transmit time of the reference "
            "photon. The ATLAS Standard Data Products (SDP) epoch offset is defined within "
            "/ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds between the GPS epoch "
            "(1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By adding the offset "
            "contained within atlas_sdp_gps_epoch to delta time parameters, the time in gps_seconds "
            "relative to the GPS epoch can be computed.")
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time']['coordinates'] = (
            "../geolocation/segment_id "
            "../geolocation/reference_photon_lat ../geolocation/reference_photon_lon"
        )

        #-- latitude
        IS2_atl03_tide[gtx]['geolocation']['reference_photon_lat'] = lat
        IS2_atl03_fill[gtx]['geolocation']['reference_photon_lat'] = None
        IS2_atl03_dims[gtx]['geolocation']['reference_photon_lat'] = [
            'delta_time'
        ]
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'units'] = "degrees_north"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'contentType'] = "physicalMeasurement"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'long_name'] = "Latitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'standard_name'] = "latitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'description'] = (
                "Latitude of each "
                "reference photon. Computed from the ECF Cartesian coordinates of the bounce point."
            )
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'valid_min'] = -90.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'valid_max'] = 90.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat']['coordinates'] = \
            "segment_id delta_time reference_photon_lon"
        #-- longitude
        IS2_atl03_tide[gtx]['geolocation']['reference_photon_lon'] = lon
        IS2_atl03_fill[gtx]['geolocation']['reference_photon_lon'] = None
        IS2_atl03_dims[gtx]['geolocation']['reference_photon_lon'] = [
            'delta_time'
        ]
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'units'] = "degrees_east"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'contentType'] = "physicalMeasurement"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'long_name'] = "Longitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'standard_name'] = "longitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'description'] = (
                "Longitude of each "
                "reference photon. Computed from the ECF Cartesian coordinates of the bounce point."
            )
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'valid_min'] = -180.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'valid_max'] = 180.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon']['coordinates'] = \
            "segment_id delta_time reference_photon_lat"
        #-- segment ID
        IS2_atl03_tide[gtx]['geolocation']['segment_id'] = segment_id
        IS2_atl03_fill[gtx]['geolocation']['segment_id'] = None
        IS2_atl03_dims[gtx]['geolocation']['segment_id'] = ['delta_time']
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['units'] = "1"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'][
            'contentType'] = "referenceInformation"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'][
            'long_name'] = "Along-track segment ID number"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['description'] = (
            "A 7 digit number "
            "identifying the along-track geolocation segment number.  These are sequential, starting with "
            "1 for the first segment after an ascending equatorial crossing node. Equal to the segment_id for "
            "the second of the two 20m ATL03 segments included in the 40m ATL03 segment"
        )
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['coordinates'] = \
            "delta_time reference_photon_lat reference_photon_lon"

        #-- computed long-period equilibrium tide
        IS2_atl03_tide[gtx]['geophys_corr']['tide_equilibrium'] = tide_lpe
        IS2_atl03_fill[gtx]['geophys_corr']['tide_equilibrium'] = None
        IS2_atl03_dims[gtx]['geophys_corr']['tide_equilibrium'] = [
            'delta_time'
        ]
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium'] = {}
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium'][
            'units'] = "meters"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium'][
            'contentType'] = "referenceInformation"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium'][
            'description'] = (
                "Long-period "
                "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
            )
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['tide_equilibrium']['coordinates'] = \
            ("../geolocation/segment_id ../geolocation/delta_time "
            "../geolocation/reference_photon_lat ../geolocation/reference_photon_lon")

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_ATL03_tide_write(IS2_atl03_tide,
                          IS2_atl03_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(INPUT_FILE),
                          FILL_VALUE=IS2_atl03_fill,
                          DIMENSIONS=IS2_atl03_dims,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #2
0
def compute_LPET_ICESat2(INPUT_FILE, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd',level=loglevel)

    #-- read data from input file
    logger.info('{0} -->'.format(INPUT_FILE))
    IS2_atl11_mds,IS2_atl11_attrs,IS2_atl11_pairs = read_HDF5_ATL11(INPUT_FILE,
        ATTRIBUTES=True, CROSSOVERS=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})_(\d{2})(\d{2})_'
        r'(\d{3})_(\d{2})(.*?).h5$')
    try:
        SUB,PRD,TRK,GRAN,SCYC,ECYC,RL,VERS,AUX = rx.findall(INPUT_FILE).pop()
    except:
        #-- output long-period equilibrium tide HDF5 file (generic)
        fileBasename,fileExtension = os.path.splitext(INPUT_FILE)
        OUTPUT_FILE = '{0}_{1}{2}'.format(fileBasename,'LPET',fileExtension)
    else:
        #-- output long-period equilibrium tide HDF5 file for ASAS/NSIDC granules
        args = (PRD,TRK,GRAN,SCYC,ECYC,RL,VERS,AUX)
        file_format = '{0}_LPET_{1}{2}_{3}{4}_{5}_{6}{7}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl11_mds['ancillary_data']['atlas_sdp_gps_epoch']
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])

    #-- copy variables for outputting to HDF5 file
    IS2_atl11_tide = {}
    IS2_atl11_fill = {}
    IS2_atl11_dims = {}
    IS2_atl11_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl11_tide['ancillary_data'] = {}
    IS2_atl11_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl11_tide['ancillary_data'][key] = IS2_atl11_mds['ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl11_tide_attrs['ancillary_data'][key] = {}
        for att_name,att_val in IS2_atl11_attrs['ancillary_data'][key].items():
            IS2_atl11_tide_attrs['ancillary_data'][key][att_name] = att_val
    #-- HDF5 group name for across-track data
    XT = 'crossing_track_data'

    #-- for each input beam pair within the file
    for ptx in sorted(IS2_atl11_pairs):
        #-- output data dictionaries for beam
        IS2_atl11_tide[ptx] = dict(cycle_stats=collections.OrderedDict(),
            crossing_track_data=collections.OrderedDict())
        IS2_atl11_fill[ptx] = dict(cycle_stats={},crossing_track_data={})
        IS2_atl11_dims[ptx] = dict(cycle_stats={},crossing_track_data={})
        IS2_atl11_tide_attrs[ptx] = dict(cycle_stats={},crossing_track_data={})

        #-- extract along-track and across-track variables
        ref_pt = {}
        latitude = {}
        longitude = {}
        delta_time = {}
        #-- along-track (AT) reference point, latitude, longitude and time
        ref_pt['AT'] = IS2_atl11_mds[ptx]['ref_pt'].copy()
        latitude['AT'] = np.ma.array(IS2_atl11_mds[ptx]['latitude'],
            fill_value=IS2_atl11_attrs[ptx]['latitude']['_FillValue'])
        longitude['AT'] = np.ma.array(IS2_atl11_mds[ptx]['longitude'],
            fill_value=IS2_atl11_attrs[ptx]['longitude']['_FillValue'])
        delta_time['AT'] = np.ma.array(IS2_atl11_mds[ptx]['delta_time'],
            fill_value=IS2_atl11_attrs[ptx]['delta_time']['_FillValue'])
        #-- across-track (XT) reference point, latitude, longitude and time
        ref_pt['XT'] = IS2_atl11_mds[ptx][XT]['ref_pt'].copy()
        latitude['XT'] = np.ma.array(IS2_atl11_mds[ptx][XT]['latitude'],
            fill_value=IS2_atl11_attrs[ptx][XT]['latitude']['_FillValue'])
        longitude['XT'] = np.ma.array(IS2_atl11_mds[ptx][XT]['longitude'],
            fill_value=IS2_atl11_attrs[ptx][XT]['longitude']['_FillValue'])
        delta_time['XT'] = np.ma.array(IS2_atl11_mds[ptx][XT]['delta_time'],
            fill_value=IS2_atl11_attrs[ptx][XT]['delta_time']['_FillValue'])

        #-- number of average segments and number of included cycles
        #-- fill_value for invalid heights and corrections
        fv = IS2_atl11_attrs[ptx]['h_corr']['_FillValue']
        #-- shape of along-track and across-track data
        n_points,n_cycles = delta_time['AT'].shape
        n_cross, = delta_time['XT'].shape
        #-- allocate for output long-period equilibrium tide variables
        tide_lpe = {}
        #-- along-track (AT) tides
        tide_lpe['AT'] = np.ma.empty((n_points,n_cycles),fill_value=fv)
        tide_lpe['AT'].mask = (delta_time['AT'] == delta_time['AT'].fill_value)
        #-- across-track (XT) tides
        tide_lpe['XT'] = np.ma.empty((n_cross),fill_value=fv)
        tide_lpe['XT'].mask = (delta_time['XT'] == delta_time['XT'].fill_value)

        #-- calculate tides for along-track and across-track data
        for track in ['AT','XT']:
            #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
            gps_seconds = atlas_sdp_gps_epoch + delta_time[track]
            leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
            tide_time = pyTMD.time.convert_delta_time(gps_seconds-leap_seconds,
                epoch1=(1980,1,6,0,0,0), epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
            #-- interpolate delta times from calendar dates to tide time
            delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])
            deltat = calc_delta_time(delta_file, tide_time)

            #-- calculate  long-period equilibrium tides for track type
            if (track == 'AT'):
                #-- calculate LPET for each cycle if along-track
                for cycle in range(n_cycles):
                    #-- find valid time and spatial points for cycle
                    valid, = np.nonzero(~tide_lpe[track].mask[:,cycle])
                    #-- predict long-period equilibrium tides at latitudes and time
                    t = tide_time[valid,cycle] + deltat[valid,cycle]
                    tide_lpe[track].data[valid,cycle] = compute_equilibrium_tide(t,
                        latitude[track][valid])
            elif (track == 'XT'):
                #-- find valid time and spatial points for cycle
                valid, = np.nonzero(~tide_lpe[track].mask[:])
                #-- predict long-period equilibrium tides at latitudes and time
                t = tide_time[valid] + deltat[valid]
                tide_lpe[track].data[valid] = compute_equilibrium_tide(t,
                    latitude[track][valid])

            #-- replace masked and nan values with fill value
            invalid = np.nonzero(np.isnan(tide_lpe[track].data) | tide_lpe[track].mask)
            tide_lpe[track].data[invalid] = tide_lpe[track].fill_value
            tide_lpe[track].mask[invalid] = True

        #-- group attributes for beam
        IS2_atl11_tide_attrs[ptx]['description'] = ('Contains the primary science parameters '
            'for this data set')
        IS2_atl11_tide_attrs[ptx]['beam_pair'] = IS2_atl11_attrs[ptx]['beam_pair']
        IS2_atl11_tide_attrs[ptx]['ReferenceGroundTrack'] = IS2_atl11_attrs[ptx]['ReferenceGroundTrack']
        IS2_atl11_tide_attrs[ptx]['first_cycle'] = IS2_atl11_attrs[ptx]['first_cycle']
        IS2_atl11_tide_attrs[ptx]['last_cycle'] = IS2_atl11_attrs[ptx]['last_cycle']
        IS2_atl11_tide_attrs[ptx]['equatorial_radius'] = IS2_atl11_attrs[ptx]['equatorial_radius']
        IS2_atl11_tide_attrs[ptx]['polar_radius'] = IS2_atl11_attrs[ptx]['polar_radius']

        #-- geolocation, time and reference point
        #-- reference point
        IS2_atl11_tide[ptx]['ref_pt'] = ref_pt['AT'].copy()
        IS2_atl11_fill[ptx]['ref_pt'] = None
        IS2_atl11_dims[ptx]['ref_pt'] = None
        IS2_atl11_tide_attrs[ptx]['ref_pt'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['ref_pt']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['long_name'] = "Reference point number"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['description'] = ("The reference point is the "
            "7 digit segment_id number corresponding to the center of the ATL06 data used "
            "for each ATL11 point.  These are sequential, starting with 1 for the first "
            "segment after an ascending equatorial crossing node.")
        IS2_atl11_tide_attrs[ptx]['ref_pt']['coordinates'] = \
            "delta_time latitude longitude"
        #-- cycle_number
        IS2_atl11_tide[ptx]['cycle_number'] = IS2_atl11_mds[ptx]['cycle_number'].copy()
        IS2_atl11_fill[ptx]['cycle_number'] = None
        IS2_atl11_dims[ptx]['cycle_number'] = None
        IS2_atl11_tide_attrs[ptx]['cycle_number'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['cycle_number']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['long_name'] = "Orbital cycle number"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['description'] = ("Number of 91-day periods "
            "that have elapsed since ICESat-2 entered the science orbit. Each of the 1,387 "
            "reference ground track (RGTs) is targeted in the polar regions once "
            "every 91 days.")
        #-- delta time
        IS2_atl11_tide[ptx]['delta_time'] = delta_time['AT'].copy()
        IS2_atl11_fill[ptx]['delta_time'] = delta_time['AT'].fill_value
        IS2_atl11_dims[ptx]['delta_time'] = ['ref_pt','cycle_number']
        IS2_atl11_tide_attrs[ptx]['delta_time'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['delta_time']['units'] = "seconds since 2018-01-01"
        IS2_atl11_tide_attrs[ptx]['delta_time']['long_name'] = "Elapsed GPS seconds"
        IS2_atl11_tide_attrs[ptx]['delta_time']['standard_name'] = "time"
        IS2_atl11_tide_attrs[ptx]['delta_time']['calendar'] = "standard"
        IS2_atl11_tide_attrs[ptx]['delta_time']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['delta_time']['description'] = ("Number of GPS "
            "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
            "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
            "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
            "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
            "time in gps_seconds relative to the GPS epoch can be computed.")
        IS2_atl11_tide_attrs[ptx]['delta_time']['coordinates'] = \
            "ref_pt cycle_number latitude longitude"
        #-- latitude
        IS2_atl11_tide[ptx]['latitude'] = latitude['AT'].copy()
        IS2_atl11_fill[ptx]['latitude'] = latitude['AT'].fill_value
        IS2_atl11_dims[ptx]['latitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['latitude'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['latitude']['units'] = "degrees_north"
        IS2_atl11_tide_attrs[ptx]['latitude']['contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['latitude']['long_name'] = "Latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['standard_name'] = "latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['latitude']['description'] = ("Center latitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_min'] = -90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_max'] = 90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['coordinates'] = \
            "ref_pt delta_time longitude"
        #-- longitude
        IS2_atl11_tide[ptx]['longitude'] = longitude['AT'].copy()
        IS2_atl11_fill[ptx]['longitude'] = longitude['AT'].fill_value
        IS2_atl11_dims[ptx]['longitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['longitude'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['longitude']['units'] = "degrees_east"
        IS2_atl11_tide_attrs[ptx]['longitude']['contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['longitude']['long_name'] = "Longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['standard_name'] = "longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['longitude']['description'] = ("Center longitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_min'] = -180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_max'] = 180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['coordinates'] = \
            "ref_pt delta_time latitude"

        #-- cycle statistics variables
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['Description'] = ("The cycle_stats subgroup "
            "contains summary information about segments for each reference point, including "
            "the uncorrected mean heights for reference surfaces, blowing snow and cloud "
            "indicators, and geolocation and height misfit statistics.")
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['data_rate'] = ("Data within this group "
            "are stored at the average segment rate.")
        #-- computed long-period equilibrium tide
        IS2_atl11_tide[ptx]['cycle_stats']['tide_equilibrium'] = tide_lpe['AT'].copy()
        IS2_atl11_fill[ptx]['cycle_stats']['tide_equilibrium'] = tide_lpe['AT'].fill_value
        IS2_atl11_dims[ptx]['cycle_stats']['tide_equilibrium'] = ['ref_pt','cycle_number']
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['units'] = "meters"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['description'] = ("Long-period "
            "equilibrium tidal elevation from the summation of fifteen tidal spectral lines")
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['coordinates'] = \
            "../ref_pt ../cycle_number ../delta_time ../latitude ../longitude"

        #-- crossing track variables
        IS2_atl11_tide_attrs[ptx][XT]['Description'] = ("The crossing_track_data "
            "subgroup contains elevation data at crossover locations. These are "
            "locations where two ICESat-2 pair tracks cross, so data are available "
            "from both the datum track, for which the granule was generated, and "
            "from the crossing track.")
        IS2_atl11_tide_attrs[ptx][XT]['data_rate'] = ("Data within this group are "
            "stored at the average segment rate.")

        #-- reference point
        IS2_atl11_tide[ptx][XT]['ref_pt'] = ref_pt['XT'].copy()
        IS2_atl11_fill[ptx][XT]['ref_pt'] = None
        IS2_atl11_dims[ptx][XT]['ref_pt'] = None
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['units'] = "1"
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['long_name'] = ("fit center reference point number, "
            "segment_id")
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['source'] = "derived, ATL11 algorithm"
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['description'] = ("The reference-point number of the "
            "fit center for the datum track. The reference point is the 7 digit segment_id number "
            "corresponding to the center of the ATL06 data used for each ATL11 point.  These are "
            "sequential, starting with 1 for the first segment after an ascending equatorial "
            "crossing node.")
        IS2_atl11_tide_attrs[ptx][XT]['ref_pt']['coordinates'] = \
            "delta_time latitude longitude"

        #-- reference ground track of the crossing track
        IS2_atl11_tide[ptx][XT]['rgt'] = IS2_atl11_mds[ptx][XT]['rgt'].copy()
        IS2_atl11_fill[ptx][XT]['rgt'] = IS2_atl11_attrs[ptx][XT]['rgt']['_FillValue']
        IS2_atl11_dims[ptx][XT]['rgt'] = None
        IS2_atl11_tide_attrs[ptx][XT]['rgt'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['units'] = "1"
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['long_name'] = "crossover reference ground track"
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['description'] = "The RGT number for the crossing data."
        IS2_atl11_tide_attrs[ptx][XT]['rgt']['coordinates'] = \
            "ref_pt delta_time latitude longitude"
        #-- cycle_number of the crossing track
        IS2_atl11_tide[ptx][XT]['cycle_number'] = IS2_atl11_mds[ptx][XT]['cycle_number'].copy()
        IS2_atl11_fill[ptx][XT]['cycle_number'] = IS2_atl11_attrs[ptx][XT]['cycle_number']['_FillValue']
        IS2_atl11_dims[ptx][XT]['cycle_number'] = None
        IS2_atl11_tide_attrs[ptx][XT]['cycle_number'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['cycle_number']['units'] = "1"
        IS2_atl11_tide_attrs[ptx][XT]['cycle_number']['long_name'] = "crossover cycle number"
        IS2_atl11_tide_attrs[ptx][XT]['cycle_number']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx][XT]['cycle_number']['description'] = ("Cycle number for the "
            "crossing data. Number of 91-day periods that have elapsed since ICESat-2 entered "
            "the science orbit. Each of the 1,387 reference ground track (RGTs) is targeted "
            "in the polar regions once every 91 days.")
        #-- delta time of the crossing track
        IS2_atl11_tide[ptx][XT]['delta_time'] = delta_time['XT'].copy()
        IS2_atl11_fill[ptx][XT]['delta_time'] = delta_time['XT'].fill_value
        IS2_atl11_dims[ptx][XT]['delta_time'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx][XT]['delta_time'] = {}
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['units'] = "seconds since 2018-01-01"
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['long_name'] = "Elapsed GPS seconds"
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['standard_name'] = "time"
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['calendar'] = "standard"
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx][XT]['delta_time']['description'] = ("Number of GPS "
            "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
            "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
            "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
            "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
            "time in gps_seconds relative to the GPS epoch can be computed.")
        IS2_atl11_tide_attrs[ptx]['delta_time']['coordinates'] = \
            "ref_pt latitude longitude"
        #-- latitude of the crossover measurement
        IS2_atl11_tide[ptx][XT]['latitude'] = latitude['XT'].copy()
        IS2_atl11_fill[ptx][XT]['latitude'] = latitude['XT'].fill_value
        IS2_atl11_dims[ptx][XT]['latitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx][XT]['latitude'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['units'] = "degrees_north"
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['long_name'] = "crossover latitude"
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['standard_name'] = "latitude"
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['description'] = ("Center latitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['valid_min'] = -90.0
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['valid_max'] = 90.0
        IS2_atl11_tide_attrs[ptx][XT]['latitude']['coordinates'] = \
            "ref_pt delta_time longitude"
        #-- longitude of the crossover measurement
        IS2_atl11_tide[ptx][XT]['longitude'] = longitude['XT'].copy()
        IS2_atl11_fill[ptx][XT]['longitude'] = longitude['XT'].fill_value
        IS2_atl11_dims[ptx][XT]['longitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx][XT]['longitude'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['units'] = "degrees_east"
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['long_name'] = "crossover longitude"
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['standard_name'] = "longitude"
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['description'] = ("Center longitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['valid_min'] = -180.0
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['valid_max'] = 180.0
        IS2_atl11_tide_attrs[ptx][XT]['longitude']['coordinates'] = \
            "ref_pt delta_time latitude"
        #-- computed long-period equilibrium tide for the crossover measurement
        IS2_atl11_tide[ptx][XT]['tide_equilibrium'] = tide_lpe['XT'].copy()
        IS2_atl11_fill[ptx][XT]['tide_equilibrium'] = tide_lpe['XT'].fill_value
        IS2_atl11_dims[ptx][XT]['tide_equilibrium'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium'] = collections.OrderedDict()
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['units'] = "meters"
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['description'] = ("Long-period "
            "equilibrium tidal elevation from the summation of fifteen tidal spectral lines")
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl11_tide_attrs[ptx][XT]['tide_equilibrium']['coordinates'] = \
            "ref_pt delta_time latitude longitude"

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_ATL11_tide_write(IS2_atl11_tide, IS2_atl11_tide_attrs,
        CLOBBER=True, INPUT=os.path.basename(INPUT_FILE),
        FILL_VALUE=IS2_atl11_fill, DIMENSIONS=IS2_atl11_dims,
        FILENAME=os.path.join(DIRECTORY,OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY,OUTPUT_FILE), MODE)
예제 #3
0
def compute_tide_corrections(x,
                             y,
                             delta_time,
                             DIRECTORY=None,
                             MODEL=None,
                             ATLAS_FORMAT='netcdf',
                             GZIP=False,
                             DEFINITION_FILE=None,
                             EPSG=3031,
                             EPOCH=(2000, 1, 1, 0, 0, 0),
                             TYPE='drift',
                             TIME='UTC',
                             METHOD='spline',
                             EXTRAPOLATE=False,
                             CUTOFF=10.0,
                             FILL_VALUE=np.nan):
    """
    Compute tides at points and times using tidal harmonics

    Parameters
    ----------
    x: float
        x-coordinates in projection EPSG
    y: float
        y-coordinates in projection EPSG
    delta_time: float
        seconds since EPOCH or datetime array
    DIRECTORY: str or NoneType, default None
        working data directory for tide models
    MODEL: str or NoneType, default None
        Tide model to use in correction
    ATLAS_FORMAT: str, default 'netcdf'
        ATLAS tide model format (OTIS, netcdf)
        ATLAS tide model format

            - ``'OTIS'``
            - ``'netcdf'``
    GZIP: bool, default False
        Tide model files are gzip compressed
    DEFINITION_FILE: str or NoneType, default None
        Tide model definition file for use
    EPSG: int, default: 3031 (Polar Stereographic South, WGS84)
        Input coordinate system
    EPOCH: tuple, default (2000,1,1,0,0,0)
        Time period for calculating delta times
    TYPE: str or NoneType, default 'drift'
        Input data type

            - ``None``: determined from input variable dimensions
            - ``'drift'``: drift buoys or satellite/airborne altimetry
            - ``'grid'``: spatial grids or images
            - ``'time series'``: time series at a single point
    TIME: str, default 'UTC'
        Time type if need to compute leap seconds to convert to UTC

            - ``'GPS'``: leap seconds needed
            - ``'LORAN'``: leap seconds needed (LORAN = GPS + 9 seconds)
            - ``'TAI'``: leap seconds needed (TAI = GPS + 19 seconds)
            - ``'UTC'``: no leap seconds needed
            - ``'datetime'``: numpy datatime array in UTC
    METHOD: str
        Interpolation method

            - ```bilinear```: quick bilinear interpolation
            - ```spline```: scipy bivariate spline interpolation
            - ```linear```, ```nearest```: scipy regular grid interpolations

    EXTRAPOLATE: bool, default False
        Extrapolate with nearest-neighbors
    CUTOFF: float, default 10.0
        Extrapolation cutoff in kilometers

        Set to np.inf to extrapolate for all points
    FILL_VALUE: float, default np.nan
        Output invalid value

    Returns
    -------
    tide: float
        tidal elevation at coordinates and time in meters
    """

    #-- check that tide directory is accessible
    try:
        os.access(DIRECTORY, os.F_OK)
    except:
        raise FileNotFoundError("Invalid tide directory")

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(DIRECTORY).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(DIRECTORY, format=ATLAS_FORMAT,
                            compressed=GZIP).elevation(MODEL)

    #-- determine input data type based on variable dimensions
    if not TYPE:
        TYPE = pyTMD.spatial.data_type(x, y, delta_time)
    #-- reform coordinate dimensions for input grids
    #-- or verify coordinate dimension shapes
    if (TYPE.lower() == 'grid') and (np.size(x) != np.size(y)):
        x, y = np.meshgrid(np.copy(x), np.copy(y))
    elif (TYPE.lower() == 'grid'):
        x = np.atleast_2d(x)
        y = np.atleast_2d(y)
    elif TYPE.lower() in ('time series', 'drift'):
        x = np.atleast_1d(x)
        y = np.atleast_1d(y)

    #-- converting x,y from EPSG to latitude/longitude
    try:
        #-- EPSG projection code string or int
        crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(EPSG)))
    except (ValueError, pyproj.exceptions.CRSError):
        #-- Projection SRS string
        crs1 = pyproj.CRS.from_string(EPSG)
    crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326))
    transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)
    lon, lat = transformer.transform(x.flatten(), y.flatten())

    #-- assert delta time is an array
    delta_time = np.atleast_1d(delta_time)
    #-- calculate leap seconds if specified
    if (TIME.upper() == 'GPS'):
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(0,
                                                       epoch1=EPOCH,
                                                       epoch2=(1980, 1, 6, 0,
                                                               0, 0),
                                                       scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time,
                                                 epoch1=EPOCH,
                                                 epoch2=(1980, 1, 6, 0, 0, 0),
                                                 scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    elif (TIME.upper() == 'LORAN'):
        #-- LORAN time is ahead of GPS time by 9 seconds
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(-9.0,
                                                       epoch1=EPOCH,
                                                       epoch2=(1980, 1, 6, 0,
                                                               0, 0),
                                                       scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time - 9.0,
                                                 epoch1=EPOCH,
                                                 epoch2=(1980, 1, 6, 0, 0, 0),
                                                 scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    elif (TIME.upper() == 'TAI'):
        #-- TAI time is ahead of GPS time by 19 seconds
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(-19.0,
                                                       epoch1=EPOCH,
                                                       epoch2=(1980, 1, 6, 0,
                                                               0, 0),
                                                       scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time - 19.0,
                                                 epoch1=EPOCH,
                                                 epoch2=(1980, 1, 6, 0, 0, 0),
                                                 scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    else:
        leap_seconds = 0.0

    #-- convert delta times or datetimes objects
    if (TIME.lower() == 'datetime'):
        #-- convert delta time array from datetime object
        #-- to days relative to 1992-01-01T00:00:00
        t = pyTMD.time.convert_datetime(delta_time,
                                        epoch=(1992, 1, 1, 0, 0, 0)) / 86400.0
    else:
        #-- convert time to days relative to Jan 1, 1992 (48622mjd)
        t = pyTMD.time.convert_delta_time(delta_time - leap_seconds,
                                          epoch1=EPOCH,
                                          epoch2=(1992, 1, 1, 0, 0, 0),
                                          scale=(1.0 / 86400.0))
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data', 'merged_deltat.data'])

    #-- read tidal constants and interpolate to grid points
    if model.format in ('OTIS', 'ATLAS'):
        amp, ph, D, c = extract_tidal_constants(lon,
                                                lat,
                                                model.grid_file,
                                                model.model_file,
                                                model.projection,
                                                TYPE=model.type,
                                                METHOD=METHOD,
                                                EXTRAPOLATE=EXTRAPOLATE,
                                                CUTOFF=CUTOFF,
                                                GRID=model.format)
        deltat = np.zeros_like(t)
    elif (model.format == 'netcdf'):
        amp, ph, D, c = extract_netcdf_constants(lon,
                                                 lat,
                                                 model.grid_file,
                                                 model.model_file,
                                                 TYPE=model.type,
                                                 METHOD=METHOD,
                                                 EXTRAPOLATE=EXTRAPOLATE,
                                                 CUTOFF=CUTOFF,
                                                 SCALE=model.scale,
                                                 GZIP=model.compressed)
        deltat = np.zeros_like(t)
    elif (model.format == 'GOT'):
        amp, ph, c = extract_GOT_constants(lon,
                                           lat,
                                           model.model_file,
                                           METHOD=METHOD,
                                           EXTRAPOLATE=EXTRAPOLATE,
                                           CUTOFF=CUTOFF,
                                           SCALE=model.scale,
                                           GZIP=model.compressed)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)
    elif (model.format == 'FES'):
        amp, ph = extract_FES_constants(lon,
                                        lat,
                                        model.model_file,
                                        TYPE=model.type,
                                        VERSION=model.version,
                                        METHOD=METHOD,
                                        EXTRAPOLATE=EXTRAPOLATE,
                                        CUTOFF=CUTOFF,
                                        SCALE=model.scale,
                                        GZIP=model.compressed)
        #-- available model constituents
        c = model.constituents
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)

    #-- calculate complex phase in radians for Euler's
    cph = -1j * ph * np.pi / 180.0
    #-- calculate constituent oscillation
    hc = amp * np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    if (TYPE.lower() == 'grid'):
        ny, nx = np.shape(x)
        nt = len(t)
        tide = np.ma.zeros((ny, nx, nt), fill_value=FILL_VALUE)
        tide.mask = np.zeros((ny, nx, nt), dtype=bool)
        for i in range(nt):
            TIDE = predict_tide(t[i],
                                hc,
                                c,
                                DELTAT=deltat[i],
                                CORRECTIONS=model.format)
            MINOR = infer_minor_corrections(t[i],
                                            hc,
                                            c,
                                            DELTAT=deltat[i],
                                            CORRECTIONS=model.format)
            #-- add major and minor components and reform grid
            tide[:, :, i] = np.reshape((TIDE + MINOR), (ny, nx))
            tide.mask[:, :, i] = np.reshape((TIDE.mask | MINOR.mask), (ny, nx))
    elif (TYPE.lower() == 'drift'):
        npts = len(t)
        tide = np.ma.zeros((npts), fill_value=FILL_VALUE)
        tide.mask = np.any(hc.mask, axis=1)
        tide.data[:] = predict_tide_drift(t,
                                          hc,
                                          c,
                                          DELTAT=deltat,
                                          CORRECTIONS=model.format)
        minor = infer_minor_corrections(t,
                                        hc,
                                        c,
                                        DELTAT=deltat,
                                        CORRECTIONS=model.format)
        tide.data[:] += minor.data[:]
    elif (TYPE.lower() == 'time series'):
        npts = len(t)
        tide = np.ma.zeros((npts), fill_value=FILL_VALUE)
        tide.mask = np.any(hc.mask, axis=1)
        tide.data[:] = predict_tidal_ts(t,
                                        hc,
                                        c,
                                        DELTAT=deltat,
                                        CORRECTIONS=model.format)
        minor = infer_minor_corrections(t,
                                        hc,
                                        c,
                                        DELTAT=deltat,
                                        CORRECTIONS=model.format)
        tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.fill_value

    #-- return the tide correction
    return tide
def compute_LPET_ICESat2(INPUT_FILE, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd', level=loglevel)

    #-- read data from input file
    logger.info('{0} -->'.format(INPUT_FILE))
    IS2_atl10_mds, IS2_atl10_attrs, IS2_atl10_beams = read_HDF5_ATL10(
        INPUT_FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 sea ice file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})-(\d{2})_(\d{4})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$'
    )
    try:
        SUB, PRD, HEM, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN, RL, VERS, AUX = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output long-period equilibrium tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        OUTPUT_FILE = '{0}_{1}{2}'.format(fileBasename, 'LPET', fileExtension)
    else:
        #-- output long-period equilibrium tide HDF5 file for ASAS/NSIDC granules
        args = (PRD, HEM, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN, RL, VERS, AUX)
        file_format = '{0}-{1}_LPET_{2}{3}{4}{5}{6}{7}_{8}{9}{10}_{11}_{12}{13}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl10_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl10_tide = {}
    IS2_atl10_fill = {}
    IS2_atl10_dims = {}
    IS2_atl10_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl10_tide['ancillary_data'] = {}
    IS2_atl10_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl10_tide['ancillary_data'][key] = IS2_atl10_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl10_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl10_attrs['ancillary_data'][key].items(
        ):
            IS2_atl10_tide_attrs['ancillary_data'][key][att_name] = att_val

    for gtx in sorted(IS2_atl10_beams):
        #-- output data dictionaries for beam
        IS2_atl10_tide[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_fill[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_dims[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_tide_attrs[gtx] = dict(freeboard_beam_segment={}, leads={})

        #-- group attributes for beam
        IS2_atl10_tide_attrs[gtx]['Description'] = IS2_atl10_attrs[gtx][
            'Description']
        IS2_atl10_tide_attrs[gtx]['atlas_pce'] = IS2_atl10_attrs[gtx][
            'atlas_pce']
        IS2_atl10_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl10_attrs[gtx][
            'atlas_beam_type']
        IS2_atl10_tide_attrs[gtx]['groundtrack_id'] = IS2_atl10_attrs[gtx][
            'groundtrack_id']
        IS2_atl10_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl10_attrs[gtx][
            'atmosphere_profile']
        IS2_atl10_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl10_attrs[gtx][
            'atlas_spot_number']
        IS2_atl10_tide_attrs[gtx]['sc_orientation'] = IS2_atl10_attrs[gtx][
            'sc_orientation']

        #-- group attributes for freeboard_beam_segment
        IS2_atl10_tide_attrs[gtx]['freeboard_beam_segment']['Description'] = (
            "Contains freeboard "
            "estimate and associated height segment parameters for only the sea ice segments by beam."
        )
        IS2_atl10_tide_attrs[gtx]['freeboard_beam_segment']['data_rate'] = (
            "Data within this "
            "group are stored at the freeboard swath segment rate.")
        #-- group attributes for leads
        IS2_atl10_tide_attrs[gtx]['leads']['Description'] = (
            "Contains parameters relating "
            "to the freeboard values.")
        IS2_atl10_tide_attrs[gtx]['leads']['data_rate'] = (
            "Data within this "
            "group are stored at the lead index rate.")

        #-- for each ATL10 group
        for group in ['freeboard_beam_segment', 'leads']:
            #-- number of segments
            val = IS2_atl10_mds[gtx][group]
            n_seg = len(val['delta_time'])

            #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
            gps_seconds = atlas_sdp_gps_epoch + val['delta_time']
            leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
            tide_time = pyTMD.time.convert_delta_time(
                gps_seconds - leap_seconds,
                epoch1=(1980, 1, 6, 0, 0, 0),
                epoch2=(1992, 1, 1, 0, 0, 0),
                scale=1.0 / 86400.0)
            #-- interpolate delta times from calendar dates to tide time
            delta_file = pyTMD.utilities.get_data_path(
                ['data', 'merged_deltat.data'])
            deltat = calc_delta_time(delta_file, tide_time)

            #-- predict long-period equilibrium tides at latitudes and time
            tide_lpe = compute_equilibrium_tide(tide_time + deltat,
                                                val['latitude'])

            #-- delta time
            IS2_atl10_tide[gtx][group]['delta_time'] = val['delta_time'].copy()
            IS2_atl10_fill[gtx][group]['delta_time'] = None
            IS2_atl10_dims[gtx][group]['delta_time'] = None
            IS2_atl10_tide_attrs[gtx][group]['delta_time'] = {}
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'units'] = "seconds since 2018-01-01"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'long_name'] = "Elapsed GPS seconds"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'standard_name'] = "time"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'source'] = "telemetry"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'calendar'] = "standard"
            IS2_atl10_tide_attrs[gtx][group]['delta_time']['description'] = (
                "Number of "
                "GPS seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch "
                "offset is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS "
                "seconds between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP "
                "epoch. By adding the offset contained within atlas_sdp_gps_epoch to delta time "
                "parameters, the time in gps_seconds relative to the GPS epoch can be computed."
            )
            IS2_atl10_tide_attrs[gtx][group]['delta_time']['coordinates'] = \
                "latitude longitude"
            #-- latitude
            IS2_atl10_tide[gtx][group]['latitude'] = val['latitude'].copy()
            IS2_atl10_fill[gtx][group]['latitude'] = None
            IS2_atl10_dims[gtx][group]['latitude'] = ['delta_time']
            IS2_atl10_tide_attrs[gtx][group]['latitude'] = {}
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'units'] = "degrees_north"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'contentType'] = "physicalMeasurement"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'long_name'] = "Latitude"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'standard_name'] = "latitude"
            IS2_atl10_tide_attrs[gtx][group]['latitude']['description'] = (
                "Latitude of "
                "segment center")
            IS2_atl10_tide_attrs[gtx][group]['latitude']['valid_min'] = -90.0
            IS2_atl10_tide_attrs[gtx][group]['latitude']['valid_max'] = 90.0
            IS2_atl10_tide_attrs[gtx][group]['latitude']['coordinates'] = \
                "delta_time longitude"
            #-- longitude
            IS2_atl10_tide[gtx][group]['longitude'] = val['longitude'].copy()
            IS2_atl10_fill[gtx][group]['longitude'] = None
            IS2_atl10_dims[gtx][group]['longitude'] = ['delta_time']
            IS2_atl10_tide_attrs[gtx][group]['longitude'] = {}
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'units'] = "degrees_east"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'contentType'] = "physicalMeasurement"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'long_name'] = "Longitude"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'standard_name'] = "longitude"
            IS2_atl10_tide_attrs[gtx][group]['longitude']['description'] = (
                "Longitude of "
                "segment center")
            IS2_atl10_tide_attrs[gtx][group]['longitude']['valid_min'] = -180.0
            IS2_atl10_tide_attrs[gtx][group]['longitude']['valid_max'] = 180.0
            IS2_atl10_tide_attrs[gtx][group]['longitude']['coordinates'] = \
                "delta_time latitude"

            #-- geophysical variables
            IS2_atl10_tide[gtx][group]['geophysical'] = {}
            IS2_atl10_fill[gtx][group]['geophysical'] = {}
            IS2_atl10_dims[gtx][group]['geophysical'] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical'] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['Description'] = (
                "Contains geophysical "
                "parameters and corrections used to correct photon heights for geophysical "
                "effects, such as tides.")
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['data_rate'] = (
                "Data within this group "
                "are stored at the variable segment rate.")

            #-- computed long-period equilibrium tide
            IS2_atl10_tide[gtx][group]['geophysical'][
                'height_segment_lpe'] = tide_lpe
            IS2_atl10_fill[gtx][group]['geophysical'][
                'height_segment_lpe'] = None
            IS2_atl10_dims[gtx][group]['geophysical']['height_segment_lpe'] = [
                'delta_time'
            ]
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                'height_segment_lpe'] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                'height_segment_lpe']['units'] = "meters"
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['height_segment_lpe']['contentType'] = \
                "referenceInformation"
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['height_segment_lpe']['long_name'] = \
                "Long Period Equilibrium Tide"
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                'height_segment_lpe']['description'] = (
                    "Long-period "
                    "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
                )
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['height_segment_lpe']['reference'] = \
                "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['height_segment_lpe']['coordinates'] = \
                "../delta_time ../latitude ../longitude"

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_ATL10_tide_write(IS2_atl10_tide,
                          IS2_atl10_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(INPUT_FILE),
                          FILL_VALUE=IS2_atl10_fill,
                          DIMENSIONS=IS2_atl10_dims,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #5
0
def compute_LPET_elevations(input_file, output_file,
    FORMAT='csv', VARIABLES=['time','lat','lon','data'], HEADER=0, TYPE='drift',
    TIME_UNITS='days since 1858-11-17T00:00:00', TIME=None, PROJECTION='4326',
    VERBOSE=False, MODE=0o775):

    #-- 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'
    #-- long-period equilibrium tides
    attrib['tide_lpe'] = {}
    attrib['tide_lpe']['long_name'] = 'Equilibrium_Tide'
    attrib['tide_lpe']['description'] = ('Long-period_equilibrium_tidal_'
        'elevation_from_the_summation_of_fifteen_tidal_spectral_lines')
    attrib['tide_lpe']['reference'] = ('https://doi.org/10.1111/'
        'j.1365-246X.1973.tb03420.x')
    attrib['tide_lpe']['units'] = 'meters'
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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=HEADER, 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)
    elif (FORMAT == 'geotiff'):
        dinput = pyTMD.spatial.from_geotiff(input_file, verbose=VERBOSE)
        #-- copy global geotiff attributes for projection and grid parameters
        for att_name in ['projection','wkt','spacing','extent']:
            attrib[att_name] = dinput['attributes'][att_name]
    #-- update time variable if entered as argument
    if TIME is not None:
        dinput['time'] = np.copy(TIME)

    #-- 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)
    if (TYPE == 'grid'):
        ny,nx = (len(dinput['y']),len(dinput['x']))
        gridx,gridy = np.meshgrid(dinput['x'],dinput['y'])
        lon,lat = transformer.transform(gridx.flatten(),gridy.flatten())
    elif (TYPE == 'drift'):
        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 time from units to days since 1992-01-01T00:00:00
    tide_time = pyTMD.time.convert_delta_time(to_secs*dinput['time'].flatten(),
        epoch1=epoch1, epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    #-- interpolate delta times from calendar dates to tide time
    delta_file = get_data_path(['data','merged_deltat.data'])
    deltat = calc_delta_time(delta_file, tide_time)
    #-- number of time points
    nt = len(tide_time)

    #-- predict long-period equilibrium tides at time
    if (TYPE == 'grid'):
        tide_lpe = np.zeros((ny,nx,nt))
        for i in range(nt):
            lpet = compute_equilibrium_tide(tide_time[i] + deltat[i], lat)
            tide_lpe[:,:,i] = np.reshape(lpet,(ny,nx))
    elif (TYPE == 'drift'):
        tide_lpe = compute_equilibrium_tide(tide_time + deltat, lat)

    #-- output to file
    output = dict(time=tide_time,lon=lon,lat=lat,tide_lpe=tide_lpe)
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output, attrib, output_file, delimiter=',',
            columns=['time','lat','lon','tide_lpe'], 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)
    elif (FORMAT == 'geotiff'):
        pyTMD.spatial.to_geotiff(output, attrib, output_file, verbose=VERBOSE,
            varname='tide_lpe')
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
예제 #6
0
def compute_tidal_currents(tide_dir, input_file, output_file,
    TIDE_MODEL=None, FORMAT='csv', VARIABLES=['time','lat','lon','data'],
    HEADER=0, TYPE='drift', TIME_UNITS='days since 1858-11-17T00:00:00',
    TIME=None, PROJECTION='4326', METHOD='spline', EXTRAPOLATE=False,
    VERBOSE=False, MODE=0o775):

    #-- select between tide models
    if (TIDE_MODEL == 'CATS0201'):
        grid_file = os.path.join(tide_dir,'cats0201_tmd','grid_CATS')
        model_file = os.path.join(tide_dir,'cats0201_tmd','UV0_CATS02_01')
        reference = 'https://mail.esr.org/polar_tide_models/Model_CATS0201.html'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir,'CATS2008','grid_CATS2008')
        model_file = os.path.join(tide_dir,'CATS2008','uv.CATS2008.out')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/cats2008/')
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas')
        grid_file = 'grid_tpxo9_atlas.nc.gz'
        model_files = {}
        model_files['u'] = ['u_q1_tpxo9_atlas_30.nc.gz','u_o1_tpxo9_atlas_30.nc.gz',
            'u_p1_tpxo9_atlas_30.nc.gz','u_k1_tpxo9_atlas_30.nc.gz',
            'u_n2_tpxo9_atlas_30.nc.gz','u_m2_tpxo9_atlas_30.nc.gz',
            'u_s2_tpxo9_atlas_30.nc.gz','u_k2_tpxo9_atlas_30.nc.gz',
            'u_m4_tpxo9_atlas_30.nc.gz','u_ms4_tpxo9_atlas_30.nc.gz',
            'u_mn4_tpxo9_atlas_30.nc.gz','u_2n2_tpxo9_atlas_30.nc.gz']
        model_files['v'] = ['v_q1_tpxo9_atlas_30.nc.gz','v_o1_tpxo9_atlas_30.nc.gz',
            'v_p1_tpxo9_atlas_30.nc.gz','v_k1_tpxo9_atlas_30.nc.gz',
            'v_n2_tpxo9_atlas_30.nc.gz','v_m2_tpxo9_atlas_30.nc.gz',
            'v_s2_tpxo9_atlas_30.nc.gz','v_k2_tpxo9_atlas_30.nc.gz',
            'v_m4_tpxo9_atlas_30.nc.gz','v_ms4_tpxo9_atlas_30.nc.gz',
            'v_mn4_tpxo9_atlas_30.nc.gz','v_2n2_tpxo9_atlas_30.nc.gz']
        reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
        model_format = 'netcdf'
        TYPES = ['u','v']
        model_scale = 1.0/100.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v2')
        grid_file = 'grid_tpxo9_atlas_30_v2.nc.gz'
        model_files = {}
        model_files['u'] = ['u_q1_tpxo9_atlas_30_v2.nc.gz','u_o1_tpxo9_atlas_30_v2.nc.gz',
            'u_p1_tpxo9_atlas_30_v2.nc.gz','u_k1_tpxo9_atlas_30_v2.nc.gz',
            'u_n2_tpxo9_atlas_30_v2.nc.gz','u_m2_tpxo9_atlas_30_v2.nc.gz',
            'u_s2_tpxo9_atlas_30_v2.nc.gz','u_k2_tpxo9_atlas_30_v2.nc.gz',
            'u_m4_tpxo9_atlas_30_v2.nc.gz','u_ms4_tpxo9_atlas_30_v2.nc.gz',
            'u_mn4_tpxo9_atlas_30_v2.nc.gz','u_2n2_tpxo9_atlas_30_v2.nc.gz']
        model_files['v'] = ['v_q1_tpxo9_atlas_30_v2.nc.gz','v_o1_tpxo9_atlas_30_v2.nc.gz',
            'v_p1_tpxo9_atlas_30_v2.nc.gz','v_k1_tpxo9_atlas_30_v2.nc.gz',
            'v_n2_tpxo9_atlas_30_v2.nc.gz','v_m2_tpxo9_atlas_30_v2.nc.gz',
            'v_s2_tpxo9_atlas_30_v2.nc.gz','v_k2_tpxo9_atlas_30_v2.nc.gz',
            'v_m4_tpxo9_atlas_30_v2.nc.gz','v_ms4_tpxo9_atlas_30_v2.nc.gz',
            'v_mn4_tpxo9_atlas_30_v2.nc.gz','v_2n2_tpxo9_atlas_30_v2.nc.gz']
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        model_format = 'netcdf'
        TYPES = ['u','v']
        model_scale = 1.0/100.0
        GZIP = True
    elif (TIDE_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','u_tpxo9.v1')
        reference = 'http://volkov.oce.orst.edu/tides/global.html'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPES = ['u','v']
    elif (TIDE_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','uv.tpxo8_atlas_30_v1')
        reference = 'http://volkov.oce.orst.edu/tides/tpxo8_atlas.html'
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPES = ['u','v']
    elif (TIDE_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','u_tpxo7.2')
        reference = 'http://volkov.oce.orst.edu/tides/global.html'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'AODTM-5'):
        grid_file = os.path.join(tide_dir,'aodtm5_tmd','grid_Arc5km')
        model_file = os.path.join(tide_dir,'aodtm5_tmd','UV0_Arc5km')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aodtm-5/')
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'AOTIM-5'):
        grid_file = os.path.join(tide_dir,'aotim5_tmd','grid_Arc5km')
        model_file = os.path.join(tide_dir,'aotim5_tmd','UV_Arc5km')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aotim-5/')
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir,'Arc5km2018','grid_Arc5km2018')
        model_file = os.path.join(tide_dir,'Arc5km2018','UV_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aotim-5/')
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPES = ['u','v']
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = {}
        model_directory['u'] = os.path.join(tide_dir,'fes2014','eastward_velocity')
        model_directory['v'] = os.path.join(tide_dir,'fes2014','northward_velocity')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
            'auxiliary-products/global-tide-fes.html')
        model_format = 'FES'
        TYPES = ['u','v']
        model_scale = 1.0

    #-- 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'
    #-- zonal tidal currents
    attrib['u'] = {}
    attrib['u']['description'] = ('depth_averaged_tidal_zonal_current_'
        'from_harmonic_constants')
    attrib['u']['model'] = TIDE_MODEL
    attrib['u']['units'] = 'cm/s'
    attrib['u']['long_name'] = 'zonal_tidal_current'
    attrib['u']['_FillValue'] = fill_value
    #-- meridional tidal currents
    attrib['v'] = {}
    attrib['v']['description'] = ('depth_averaged_tidal_meridional_current_'
        'from_harmonic_constants')
    attrib['v']['model'] = TIDE_MODEL
    attrib['v']['units'] = 'cm/s'
    attrib['v']['long_name'] = 'meridional_tidal_current'
    attrib['v']['_FillValue'] = fill_value
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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=HEADER, 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)
    elif (FORMAT == 'geotiff'):
        dinput = pyTMD.spatial.from_geotiff(input_file, verbose=VERBOSE)
        #-- copy global geotiff attributes for projection and grid parameters
        for att_name in ['projection','wkt','spacing','extent']:
            attrib[att_name] = dinput['attributes'][att_name]
    #-- update time variable if entered as argument
    if TIME is not None:
        dinput['time'] = np.copy(TIME)

    #-- 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)
    if (TYPE == 'grid'):
        ny,nx = (len(dinput['y']),len(dinput['x']))
        gridx,gridy = np.meshgrid(dinput['x'],dinput['y'])
        lon,lat = transformer.transform(gridx,gridy)
    elif (TYPE == 'drift'):
        lon,lat = transformer.transform(dinput['x'],dinput['y'])

    #-- 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 time from units to days since 1992-01-01T00:00:00
    tide_time = pyTMD.time.convert_delta_time(to_secs*dinput['time'].flatten(),
        epoch1=epoch1, epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    #-- number of time points
    nt = len(tide_time)

    #-- python dictionary with output data
    output = {'time':tide_time,'lon':lon,'lat':lat}
    #-- iterate over u and v currents
    for t in TYPES:
        #-- read tidal constants and interpolate to grid points
        if model_format in ('OTIS','ATLAS'):
            amp,ph,D,c = extract_tidal_constants(lon.flatten(), lat.flatten(),
                grid_file, model_file, EPSG, TYPE=t, METHOD=METHOD,
                EXTRAPOLATE=EXTRAPOLATE, GRID=model_format)
            deltat = np.zeros((nt))
        elif (model_format == 'netcdf'):
            amp,ph,D,c = extract_netcdf_constants(lon.flatten(), lat.flatten(),
                model_directory, grid_file, model_files[t], TYPE=t,
                METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, SCALE=model_scale,
                GZIP=GZIP)
            deltat = np.zeros((nt))
        elif (model_format == 'FES'):
            amp,ph = extract_FES_constants(lon.flatten(), lat.flatten(),
                model_directory[t], model_files, TYPE=t, VERSION=TIDE_MODEL,
                METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, SCALE=model_scale)
            #-- interpolate delta times from calendar dates to tide time
            delta_file = get_data_path(['data','merged_deltat.data'])
            deltat = calc_delta_time(delta_file, tide_time)

        #-- calculate complex phase in radians for Euler's
        cph = -1j*ph*np.pi/180.0
        #-- calculate constituent oscillation
        hc = amp*np.exp(cph)

        #-- predict tidal currents at time and infer minor corrections
        if (TYPE == 'grid'):
            output[t] = np.ma.zeros((ny,nx,nt),fill_value=fill_value)
            output[t].mask = np.zeros((ny,nx,nt),dtype=np.bool)
            for i in range(nt):
                TIDE = predict_tide(tide_time[i], hc, c,
                    DELTAT=deltat[i], CORRECTIONS=model_format)
                MINOR = infer_minor_corrections(tide_time[i], hc, c,
                    DELTAT=deltat[i], CORRECTIONS=model_format)
                #-- add major and minor components and reform grid
                output[t][:,:,i] = np.reshape((TIDE+MINOR), (ny,nx))
                output[t].mask[:,:,i] = np.reshape((TIDE.mask | MINOR.mask),
                    (ny,nx))
        elif (TYPE == 'drift'):
            output[t] = np.ma.zeros((nt), fill_value=fill_value)
            output[t].mask = np.any(hc.mask,axis=1)
            output[t].data[:] = predict_tide_drift(tide_time, hc, c,
                DELTAT=deltat, CORRECTIONS=model_format)
            minor = infer_minor_corrections(tide_time, hc, c,
                DELTAT=deltat, CORRECTIONS=model_format)
            output[t].data[:] += minor.data[:]
        #-- replace invalid values with fill value
        output[t].data[output[t].mask] = output[t].fill_value

    #-- output to file
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output, attrib, output_file, delimiter=',',
            columns=['time','lat','lon','u','v'], 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)
    elif (FORMAT == 'geotiff'):
        #-- merge current variables into a single variable
        output['data'] = np.concatenate((output['u'],output['v']),axis=-1)
        attrib['data'] = {'_FillValue':fill_value}
        pyTMD.spatial.to_geotiff(output, attrib, output_file, verbose=VERBOSE,
            varname='data')
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
def compute_tides_ICESat2(tide_dir,
                          INPUT_FILE,
                          TIDE_MODEL=None,
                          ATLAS_FORMAT=None,
                          GZIP=True,
                          DEFINITION_FILE=None,
                          METHOD='spline',
                          EXTRAPOLATE=False,
                          CUTOFF=None,
                          VERBOSE=False,
                          MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd', level=loglevel)

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(tide_dir).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(tide_dir, format=ATLAS_FORMAT,
                            compressed=GZIP).elevation(TIDE_MODEL)

    #-- read data from input file
    logger.info('{0} -->'.format(INPUT_FILE))
    IS2_atl03_mds, IS2_atl03_attrs, IS2_atl03_beams = read_HDF5_ATL03_main(
        INPUT_FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$')
    try:
        SUB, PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        args = (fileBasename, model.name, fileExtension)
        OUTPUT_FILE = '{0}_{1}_TIDES{2}'.format(*args)
    else:
        #-- output tide HDF5 file for ASAS/NSIDC granules
        args = (PRD, model.name, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL,
                VERS, AUX)
        file_format = '{0}_{1}_TIDES_{2}{3}{4}{5}{6}{7}_{8}{9}{10}_{11}_{12}{13}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl03_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data', 'merged_deltat.data'])

    #-- copy variables for outputting to HDF5 file
    IS2_atl03_tide = {}
    IS2_atl03_fill = {}
    IS2_atl03_dims = {}
    IS2_atl03_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl03_tide['ancillary_data'] = {}
    IS2_atl03_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl03_tide['ancillary_data'][key] = IS2_atl03_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl03_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl03_attrs['ancillary_data'][key].items(
        ):
            IS2_atl03_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl03_beams):
        #-- output data dictionaries for beam
        IS2_atl03_tide[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_fill[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_dims[gtx] = dict(geolocation={}, geophys_corr={})
        IS2_atl03_tide_attrs[gtx] = dict(geolocation={}, geophys_corr={})

        #-- read data and attributes for beam
        val, attrs = read_HDF5_ATL03_beam(INPUT_FILE, gtx, ATTRIBUTES=True)
        #-- number of segments
        n_seg = len(val['geolocation']['segment_id'])
        #-- extract variables for computing tides
        segment_id = val['geolocation']['segment_id'].copy()
        delta_time = val['geolocation']['delta_time'].copy()
        lon = val['geolocation']['reference_photon_lon'].copy()
        lat = val['geolocation']['reference_photon_lat'].copy()
        #-- invalid value
        fv = attrs['geolocation']['sigma_h']['_FillValue']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + delta_time
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- read tidal constants and interpolate to grid points
        if model.format in ('OTIS', 'ATLAS'):
            amp, ph, D, c = extract_tidal_constants(lon,
                                                    lat,
                                                    model.grid_file,
                                                    model.model_file,
                                                    model.projection,
                                                    TYPE=model.type,
                                                    METHOD=METHOD,
                                                    EXTRAPOLATE=EXTRAPOLATE,
                                                    CUTOFF=CUTOFF,
                                                    GRID=model.format)
            deltat = np.zeros_like(tide_time)
        elif (model.format == 'netcdf'):
            amp, ph, D, c = extract_netcdf_constants(lon,
                                                     lat,
                                                     model.grid_file,
                                                     model.model_file,
                                                     TYPE=model.type,
                                                     METHOD=METHOD,
                                                     EXTRAPOLATE=EXTRAPOLATE,
                                                     CUTOFF=CUTOFF,
                                                     SCALE=model.scale,
                                                     GZIP=model.compressed)
            deltat = np.zeros_like(tide_time)
        elif (model.format == 'GOT'):
            amp, ph, c = extract_GOT_constants(lon,
                                               lat,
                                               model.model_file,
                                               METHOD=METHOD,
                                               EXTRAPOLATE=EXTRAPOLATE,
                                               CUTOFF=CUTOFF,
                                               SCALE=model.scale,
                                               GZIP=model.compressed)
            #-- interpolate delta times from calendar dates to tide time
            deltat = calc_delta_time(delta_file, tide_time)
        elif (model.format == 'FES'):
            amp, ph = extract_FES_constants(lon,
                                            lat,
                                            model.model_file,
                                            TYPE=model.type,
                                            VERSION=model.version,
                                            METHOD=METHOD,
                                            EXTRAPOLATE=EXTRAPOLATE,
                                            CUTOFF=CUTOFF,
                                            SCALE=model.scale,
                                            GZIP=model.compressed)
            #-- available model constituents
            c = model.constituents
            #-- interpolate delta times from calendar dates to tide time
            deltat = calc_delta_time(delta_file, tide_time)

        #-- calculate complex phase in radians for Euler's
        cph = -1j * ph * np.pi / 180.0
        #-- calculate constituent oscillation
        hc = amp * np.exp(cph)

        #-- predict tidal elevations at time and infer minor corrections
        tide = np.ma.empty((n_seg), fill_value=fv)
        tide.mask = np.any(hc.mask, axis=1)
        tide.data[:] = predict_tide_drift(tide_time,
                                          hc,
                                          c,
                                          DELTAT=deltat,
                                          CORRECTIONS=model.format)
        minor = infer_minor_corrections(tide_time,
                                        hc,
                                        c,
                                        DELTAT=deltat,
                                        CORRECTIONS=model.format)
        tide.data[:] += minor.data[:]
        #-- replace masked and nan values with fill value
        invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
        tide.data[invalid] = tide.fill_value
        tide.mask[invalid] = True

        #-- group attributes for beam
        IS2_atl03_tide_attrs[gtx]['Description'] = attrs['Description']
        IS2_atl03_tide_attrs[gtx]['atlas_pce'] = attrs['atlas_pce']
        IS2_atl03_tide_attrs[gtx]['atlas_beam_type'] = attrs['atlas_beam_type']
        IS2_atl03_tide_attrs[gtx]['groundtrack_id'] = attrs['groundtrack_id']
        IS2_atl03_tide_attrs[gtx]['atmosphere_profile'] = attrs[
            'atmosphere_profile']
        IS2_atl03_tide_attrs[gtx]['atlas_spot_number'] = attrs[
            'atlas_spot_number']
        IS2_atl03_tide_attrs[gtx]['sc_orientation'] = attrs['sc_orientation']

        #-- group attributes for geolocation
        IS2_atl03_tide_attrs[gtx]['geolocation']['Description'] = (
            "Contains parameters related to "
            "geolocation.  The rate of all of these parameters is at the rate corresponding to the "
            "ICESat-2 Geolocation Along Track Segment interval (nominally 20 m along-track)."
        )
        IS2_atl03_tide_attrs[gtx]['geolocation']['data_rate'] = (
            "Data within this group are "
            "stored at the ICESat-2 20m segment rate.")
        #-- group attributes for geophys_corr
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['Description'] = (
            "Contains parameters used to "
            "correct photon heights for geophysical effects, such as tides.  These parameters are "
            "posted at the same interval as the ICESat-2 Geolocation Along-Track Segment interval "
            "(nominally 20m along-track).")
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['data_rate'] = (
            "These parameters are stored at "
            "the ICESat-2 Geolocation Along Track Segment rate (nominally every 20 m along-track)."
        )

        #-- geolocation, time and segment ID
        #-- delta time in geolocation group
        IS2_atl03_tide[gtx]['geolocation']['delta_time'] = delta_time
        IS2_atl03_fill[gtx]['geolocation']['delta_time'] = None
        IS2_atl03_dims[gtx]['geolocation']['delta_time'] = None
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'standard_name'] = "time"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time'][
            'calendar'] = "standard"
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time']['description'] = (
            "Elapsed seconds "
            "from the ATLAS SDP GPS Epoch, corresponding to the transmit time of the reference "
            "photon. The ATLAS Standard Data Products (SDP) epoch offset is defined within "
            "/ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds between the GPS epoch "
            "(1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By adding the offset "
            "contained within atlas_sdp_gps_epoch to delta time parameters, the time in gps_seconds "
            "relative to the GPS epoch can be computed.")
        IS2_atl03_tide_attrs[gtx]['geolocation']['delta_time']['coordinates'] = \
            "segment_id reference_photon_lat reference_photon_lon"
        #-- delta time in geophys_corr group
        IS2_atl03_tide[gtx]['geophys_corr']['delta_time'] = delta_time
        IS2_atl03_fill[gtx]['geophys_corr']['delta_time'] = None
        IS2_atl03_dims[gtx]['geophys_corr']['delta_time'] = None
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'] = {}
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'standard_name'] = "time"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time'][
            'calendar'] = "standard"
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time']['description'] = (
            "Elapsed seconds "
            "from the ATLAS SDP GPS Epoch, corresponding to the transmit time of the reference "
            "photon. The ATLAS Standard Data Products (SDP) epoch offset is defined within "
            "/ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds between the GPS epoch "
            "(1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By adding the offset "
            "contained within atlas_sdp_gps_epoch to delta time parameters, the time in gps_seconds "
            "relative to the GPS epoch can be computed.")
        IS2_atl03_tide_attrs[gtx]['geophys_corr']['delta_time']['coordinates'] = (
            "../geolocation/segment_id "
            "../geolocation/reference_photon_lat ../geolocation/reference_photon_lon"
        )

        #-- latitude
        IS2_atl03_tide[gtx]['geolocation']['reference_photon_lat'] = lat
        IS2_atl03_fill[gtx]['geolocation']['reference_photon_lat'] = None
        IS2_atl03_dims[gtx]['geolocation']['reference_photon_lat'] = [
            'delta_time'
        ]
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'units'] = "degrees_north"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'contentType'] = "physicalMeasurement"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'long_name'] = "Latitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'standard_name'] = "latitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'description'] = (
                "Latitude of each "
                "reference photon. Computed from the ECF Cartesian coordinates of the bounce point."
            )
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'valid_min'] = -90.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat'][
            'valid_max'] = 90.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lat']['coordinates'] = \
            "segment_id delta_time reference_photon_lon"
        #-- longitude
        IS2_atl03_tide[gtx]['geolocation']['reference_photon_lon'] = lon
        IS2_atl03_fill[gtx]['geolocation']['reference_photon_lon'] = None
        IS2_atl03_dims[gtx]['geolocation']['reference_photon_lon'] = [
            'delta_time'
        ]
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'units'] = "degrees_east"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'contentType'] = "physicalMeasurement"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'long_name'] = "Longitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'standard_name'] = "longitude"
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'description'] = (
                "Longitude of each "
                "reference photon. Computed from the ECF Cartesian coordinates of the bounce point."
            )
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'valid_min'] = -180.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon'][
            'valid_max'] = 180.0
        IS2_atl03_tide_attrs[gtx]['geolocation']['reference_photon_lon']['coordinates'] = \
            "segment_id delta_time reference_photon_lat"
        #-- segment ID
        IS2_atl03_tide[gtx]['geolocation']['segment_id'] = segment_id
        IS2_atl03_fill[gtx]['geolocation']['segment_id'] = None
        IS2_atl03_dims[gtx]['geolocation']['segment_id'] = ['delta_time']
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'] = {}
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['units'] = "1"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'][
            'contentType'] = "referenceInformation"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id'][
            'long_name'] = "Along-track segment ID number"
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['description'] = (
            "A 7 digit number "
            "identifying the along-track geolocation segment number.  These are sequential, starting with "
            "1 for the first segment after an ascending equatorial crossing node. Equal to the segment_id for "
            "the second of the two 20m ATL03 segments included in the 40m ATL03 segment"
        )
        IS2_atl03_tide_attrs[gtx]['geolocation']['segment_id']['coordinates'] = \
            "delta_time reference_photon_lat reference_photon_lon"

        #-- computed tide
        IS2_atl03_tide[gtx]['geophys_corr'][model.atl03] = tide
        IS2_atl03_fill[gtx]['geophys_corr'][model.atl03] = tide.fill_value
        IS2_atl03_dims[gtx]['geophys_corr'][model.atl03] = ['delta_time']
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][model.atl03] = {}
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['units'] = "meters"
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['contentType'] = "referenceInformation"
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['long_name'] = model.long_name
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['description'] = model.description
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['source'] = model.name
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][
            model.atl03]['reference'] = model.reference
        IS2_atl03_tide_attrs[gtx]['geophys_corr'][model.atl03]['coordinates'] = \
            ("../geolocation/segment_id ../geolocation/delta_time "
            "../geolocation/reference_photon_lat ../geolocation/reference_photon_lon")

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_ATL03_tide_write(IS2_atl03_tide,
                          IS2_atl03_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(INPUT_FILE),
                          FILL_VALUE=IS2_atl03_fill,
                          DIMENSIONS=IS2_atl03_dims,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #8
0
def compute_tides_icebridge_data(tide_dir, arg, TIDE_MODEL,
    METHOD='spline', EXTRAPOLATE=False, 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

    #-- select between tide models
    if (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir,'CATS2008','grid_CATS2008')
        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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas')
        grid_file = os.path.join(model_directory,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v2')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v2.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v2.nc.gz','h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz','h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz','h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz','h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz','h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz','h_2n2_tpxo9_atlas_30_v2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v3')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v3.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v3.nc.gz','h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz','h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz','h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz','h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz','h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz','h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz','h_mm_tpxo9_atlas_30_v3.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        output_variable = 'tide_ocean'
        variable_long_name = "Ocean Tide"
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v4'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v4')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v4')
        model_files = ['h_q1_tpxo9_atlas_30_v4','h_o1_tpxo9_atlas_30_v4',
            'h_p1_tpxo9_atlas_30_v4','h_k1_tpxo9_atlas_30_v4',
            'h_n2_tpxo9_atlas_30_v4','h_m2_tpxo9_atlas_30_v4',
            'h_s2_tpxo9_atlas_30_v4','h_k2_tpxo9_atlas_30_v4',
            'h_m4_tpxo9_atlas_30_v4','h_ms4_tpxo9_atlas_30_v4',
            'h_mn4_tpxo9_atlas_30_v4','h_2n2_tpxo9_atlas_30_v4',
            'h_mf_tpxo9_atlas_30_v4','h_mm_tpxo9_atlas_30_v4']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir,'Arc5km2018','grid_Arc5km2018')
        model_file = os.path.join(tide_dir,'Arc5km2018','h_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aotim-5/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = os.path.join(tide_dir,'fes2014','ocean_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
            'auxiliary-products/global-tide-fes.html')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014_load'):
        model_directory = os.path.join(tide_dir,'fes2014','load_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
            'auxiliary-products/global-tide-fes.html')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
        GZIP = True

    #-- 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'
    #-- tides
    attrib[output_variable] = {}
    attrib[output_variable]['description'] = ('Tidal_elevation_from_harmonic_'
        'constants_at_the_measurement_position_at_the_acquisition_time')
    attrib[output_variable]['reference'] = reference
    attrib[output_variable]['model'] = TIDE_MODEL
    attrib[output_variable]['units'] = 'meters'
    attrib[output_variable]['long_name'] = variable_long_name
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['description'] = ('Time_corresponding_to_the_measurement_'
        'position')
    attrib['time']['units'] = 'Days since 1992-01-01T00:00:00'
    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.float64(ypre) >= 90):
                YY1 = '{0:4.0f}'.format(np.float64(ypre) + 1900.0)
            else:
                YY1 = '{0:4.0f}'.format(np.float64(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)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    t = pyTMD.time.convert_delta_time(dinput['time'],
        epoch1=(2000,1,1,12,0,0), epoch2=(1992,1,1,0,0,0),
        scale=1.0/86400.0)
    #-- delta time (TT - UT1) file
    delta_file = get_data_path(['data','merged_deltat.data'])

    #-- read tidal constants and interpolate to grid points
    if model_format in ('OTIS','ATLAS'):
        amp,ph,D,c = extract_tidal_constants(dinput['lon'], dinput['lat'],
            grid_file, model_file, EPSG, TYPE=TYPE, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, GRID=model_format)
        deltat = np.zeros_like(t)
    elif model_format in ('netcdf'):
        amp,ph,D,c = extract_netcdf_constants(dinput['lon'], dinput['lat'],
            grid_file, model_file, TYPE=TYPE, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE, GZIP=GZIP)
        deltat = np.zeros_like(t)
    elif (model_format == 'GOT'):
        amp,ph,c = extract_GOT_constants(dinput['lon'], dinput['lat'],
            model_file, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            SCALE=SCALE, GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)
    elif (model_format == 'FES'):
        amp,ph = extract_FES_constants(dinput['lon'], dinput['lat'],
            model_file, TYPE=TYPE, VERSION=TIDE_MODEL, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE, GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    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 TIDE_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],TIDE_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
    fill_value = -9999.0
    tide = np.ma.empty((file_lines),fill_value=fill_value)
    tide.mask = np.any(hc.mask,axis=1)
    tide.data[:] = predict_tide_drift(t, hc, c,
        DELTAT=deltat, CORRECTIONS=model_format)
    minor = infer_minor_corrections(t, hc, c,
        DELTAT=deltat, CORRECTIONS=model_format)
    tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.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(output_variable, (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[output_variable].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'] = ('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 file
    fid.attrs['elevation_file'] = os.path.basename(input_file)
    fid.attrs['tide_model'] = TIDE_MODEL
    #-- 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 days since 1992-01-01 into Julian days
    time_range = np.array([np.min(t),np.max(t)])
    time_julian = 2400000.5 + pyTMD.time.convert_delta_time(time_range,
        epoch1=(1992,1,1,0,0,0), epoch2=(1858,11,17,0,0,0), scale=1.0)
    #-- convert to calendar date
    cal = pyTMD.time.convert_julian(time_julian,ASTYPE=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(time_julian[-1]*86400.0 - time_julian[0]*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)
예제 #9
0
def compute_LPET_ICESat(INPUT_FILE, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd', level=loglevel)

    #-- get directory from INPUT_FILE
    logger.info('{0} -->'.format(INPUT_FILE))
    DIRECTORY = os.path.dirname(INPUT_FILE)

    #-- compile regular expression operator for extracting information from file
    rx = re.compile((r'GLAH(\d{2})_(\d{3})_(\d{1})(\d{1})(\d{2})_(\d{3})_'
                     r'(\d{4})_(\d{1})_(\d{2})_(\d{4})\.H5'), re.VERBOSE)
    #-- extract parameters from ICESat/GLAS HDF5 file name
    #-- PRD:  Product number (01, 05, 06, 12, 13, 14, or 15)
    #-- RL:  Release number for process that created the product = 634
    #-- RGTP:  Repeat ground-track phase (1=8-day, 2=91-day, 3=transfer orbit)
    #-- ORB:   Reference orbit number (starts at 1 and increments each time a
    #--           new reference orbit ground track file is obtained.)
    #-- INST:  Instance number (increments every time the satellite enters a
    #--           different reference orbit)
    #-- CYCL:   Cycle of reference orbit for this phase
    #-- TRK: Track within reference orbit
    #-- SEG:   Segment of orbit
    #-- GRAN:  Granule version number
    #-- TYPE:  File type
    try:
        PRD, RL, RGTP, ORB, INST, CYCL, TRK, SEG, GRAN, TYPE = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output long-period equilibrium tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        OUTPUT_FILE = '{0}_{1}{2}'.format(fileBasename, 'LPET', fileExtension)
    else:
        #-- output long-period equilibrium tide HDF5 file for NSIDC granules
        args = (PRD, RL, RGTP, ORB, INST, CYCL, TRK, SEG, GRAN, TYPE)
        file_format = 'GLAH{0}_{1}_LPET_{2}{3}{4}_{5}_{6}_{7}_{8}_{9}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- read GLAH12 HDF5 file
    fileID = h5py.File(INPUT_FILE, 'r')
    n_40HZ, = fileID['Data_40HZ']['Time']['i_rec_ndx'].shape
    #-- get variables and attributes
    rec_ndx_40HZ = fileID['Data_40HZ']['Time']['i_rec_ndx'][:].copy()
    #-- seconds since 2000-01-01 12:00:00 UTC (J2000)
    DS_UTCTime_40HZ = fileID['Data_40HZ']['DS_UTCTime_40'][:].copy()
    #-- Latitude (degrees North)
    lat_TPX = fileID['Data_40HZ']['Geolocation']['d_lat'][:].copy()
    #-- Longitude (degrees East)
    lon_40HZ = fileID['Data_40HZ']['Geolocation']['d_lon'][:].copy()
    #-- Elevation (height above TOPEX/Poseidon ellipsoid in meters)
    elev_TPX = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'][:].copy()
    fv = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'].attrs[
        '_FillValue']

    #-- semimajor axis (a) and flattening (f) for TP and WGS84 ellipsoids
    atop, ftop = (6378136.3, 1.0 / 298.257)
    awgs, fwgs = (6378137.0, 1.0 / 298.257223563)
    #-- convert from Topex/Poseidon to WGS84 Ellipsoids
    lat_40HZ, elev_40HZ = pyTMD.spatial.convert_ellipsoid(lat_TPX,
                                                          elev_TPX,
                                                          atop,
                                                          ftop,
                                                          awgs,
                                                          fwgs,
                                                          eps=1e-12,
                                                          itmax=10)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    tide_time = pyTMD.time.convert_delta_time(DS_UTCTime_40HZ,
                                              epoch1=(2000, 1, 1, 12, 0, 0),
                                              epoch2=(1992, 1, 1, 0, 0, 0),
                                              scale=1.0 / 86400.0)
    #-- interpolate delta times from calendar dates to tide time
    delta_file = pyTMD.utilities.get_data_path(['data', 'merged_deltat.data'])
    deltat = calc_delta_time(delta_file, tide_time)

    #-- predict long-period equilibrium tides at latitudes and time
    tide_lpe = compute_equilibrium_tide(tide_time + deltat, lat_40HZ)

    #-- copy variables for outputting to HDF5 file
    IS_gla12_tide = dict(Data_40HZ={})
    IS_gla12_fill = dict(Data_40HZ={})
    IS_gla12_tide_attrs = dict(Data_40HZ={})

    #-- copy global file attributes
    global_attribute_list = [
        'featureType', 'title', 'comment', 'summary', 'license', 'references',
        'AccessConstraints', 'CitationforExternalPublication',
        'contributor_role', 'contributor_name', 'creator_name',
        'creator_email', 'publisher_name', 'publisher_email', 'publisher_url',
        'platform', 'instrument', 'processing_level', 'date_created',
        'spatial_coverage_type', 'history', 'keywords', 'keywords_vocabulary',
        'naming_authority', 'project', 'time_type', 'date_type',
        'time_coverage_start', 'time_coverage_end', 'time_coverage_duration',
        'source', 'HDFVersion', 'identifier_product_type',
        'identifier_product_format_version', 'Conventions', 'institution',
        'ReprocessingPlanned', 'ReprocessingActual', 'LocalGranuleID',
        'ProductionDateTime', 'LocalVersionID', 'PGEVersion', 'OrbitNumber',
        'StartOrbitNumber', 'StopOrbitNumber', 'EquatorCrossingLongitude',
        'EquatorCrossingTime', 'EquatorCrossingDate', 'ShortName', 'VersionID',
        'InputPointer', 'RangeBeginningTime', 'RangeEndingTime',
        'RangeBeginningDate', 'RangeEndingDate', 'PercentGroundHit',
        'OrbitQuality', 'Cycle', 'Track', 'Instrument_State', 'Timing_Bias',
        'ReferenceOrbit', 'SP_ICE_PATH_NO', 'SP_ICE_GLAS_StartBlock',
        'SP_ICE_GLAS_EndBlock', 'Instance', 'Range_Bias',
        'Instrument_State_Date', 'Instrument_State_Time', 'Range_Bias_Date',
        'Range_Bias_Time', 'Timing_Bias_Date', 'Timing_Bias_Time',
        'identifier_product_doi', 'identifier_file_uuid',
        'identifier_product_doi_authority'
    ]
    for att in global_attribute_list:
        IS_gla12_tide_attrs[att] = fileID.attrs[att]
    #-- copy ICESat campaign name from ancillary data
    IS_gla12_tide_attrs['Campaign'] = fileID['ANCILLARY_DATA'].attrs[
        'Campaign']

    #-- add attributes for input GLA12 file
    IS_gla12_tide_attrs['input_files'] = os.path.basename(INPUT_FILE)
    #-- update geospatial ranges for ellipsoid
    IS_gla12_tide_attrs['geospatial_lat_min'] = np.min(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_max'] = np.max(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_min'] = np.min(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_max'] = np.max(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_units'] = "degrees_north"
    IS_gla12_tide_attrs['geospatial_lon_units'] = "degrees_east"
    IS_gla12_tide_attrs['geospatial_ellipsoid'] = "WGS84"

    #-- copy 40Hz group attributes
    for att_name, att_val in fileID['Data_40HZ'].attrs.items():
        IS_gla12_tide_attrs['Data_40HZ'][att_name] = att_val
    #-- copy attributes for time, geolocation and geophysical groups
    for var in ['Time', 'Geolocation', 'Geophysical']:
        IS_gla12_tide['Data_40HZ'][var] = {}
        IS_gla12_fill['Data_40HZ'][var] = {}
        IS_gla12_tide_attrs['Data_40HZ'][var] = {}
        for att_name, att_val in fileID['Data_40HZ'][var].attrs.items():
            IS_gla12_tide_attrs['Data_40HZ'][var][att_name] = att_val

    #-- J2000 time
    IS_gla12_tide['Data_40HZ']['DS_UTCTime_40'] = DS_UTCTime_40HZ
    IS_gla12_fill['Data_40HZ']['DS_UTCTime_40'] = None
    IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'] = {}
    for att_name, att_val in fileID['Data_40HZ']['DS_UTCTime_40'].attrs.items(
    ):
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'][
                att_name] = att_val
    #-- record
    IS_gla12_tide['Data_40HZ']['Time']['i_rec_ndx'] = rec_ndx_40HZ
    IS_gla12_fill['Data_40HZ']['Time']['i_rec_ndx'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'] = {}
    for att_name, att_val in fileID['Data_40HZ']['Time'][
            'i_rec_ndx'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'][
                att_name] = att_val
    #-- latitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lat'] = lat_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lat'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'] = {}
    for att_name, att_val in fileID['Data_40HZ']['Geolocation'][
            'd_lat'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'][
                att_name] = att_val
    #-- longitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lon'] = lon_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lon'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'] = {}
    for att_name, att_val in fileID['Data_40HZ']['Geolocation'][
            'd_lon'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'][
                att_name] = att_val

    #-- geophysical variables
    #-- computed long-period equilibrium tide
    IS_gla12_tide['Data_40HZ']['Geophysical']['d_eqElv'] = tide_lpe
    IS_gla12_fill['Data_40HZ']['Geophysical']['d_eqElv'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv'][
        'units'] = "meters"
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv']['long_name'] = \
        "Long Period Equilibrium Tide"
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv']['description'] = (
        "Long-period "
        "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
    )
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv']['reference'] = \
        "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical']['d_eqElv']['coordinates'] = \
        "../DS_UTCTime_40"

    #-- close the input HDF5 file
    fileID.close()

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_GLA12_tide_write(IS_gla12_tide,
                          IS_gla12_tide_attrs,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE),
                          FILL_VALUE=IS_gla12_fill,
                          CLOBBER=True)
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #10
0
def compute_tidal_elevations(tide_dir,
                             input_file,
                             output_file,
                             TIDE_MODEL='',
                             MODE=0775):

    #-- read input *.csv file to extract MJD, latitude, longitude and elevation
    dtype = dict(names=('MJD', 'lat', 'lon', 'h'),
                 formats=('f8', 'f8', 'f8', 'f8'))
    dinput = np.loadtxt(input_file, delimiter=',', dtype=dtype)

    #-- select between tide models
    if (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        type = 'z'
    elif (TIDE_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/')
        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'
        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'
        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'
        model_format = 'ATLAS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0

    #-- read tidal constants and interpolate to grid points
    if model_format in ('OTIS', 'ATLAS'):
        amp, ph, D, c = extract_tidal_constants(dinput['lon'],
                                                dinput['lat'],
                                                grid_file,
                                                model_file,
                                                EPSG,
                                                type,
                                                METHOD='spline')
        deltat = np.zeros_like(dinput['MJD'])
    elif (model_format == 'netcdf'):
        amp, ph, D, c = extract_netcdf_constants(dinput['lon'],
                                                 dinput['lat'],
                                                 model_directory,
                                                 grid_file,
                                                 model_files,
                                                 type,
                                                 METHOD='spline',
                                                 SCALE=SCALE)
        deltat = np.zeros_like(dinput['MJD'])
    elif (model_format == 'GOT'):
        amp, ph = extract_GOT_constants(dinput['lon'],
                                        dinput['lat'],
                                        model_directory,
                                        model_files,
                                        METHOD='spline',
                                        SCALE=SCALE)
        delta_file = os.path.join(tide_dir, 'deltat.data')
        deltat = calc_delta_time(delta_file, dinput['MJD'])

    #-- convert phase to radians
    cph = -1j * ph * np.pi / 180.0
    hc = amp * np.exp(cph)

    #-- convert time from MJD to days relative to Jan 1, 1992 (48622 MJD)
    #-- predict tidal elevations at time 1 and infer minor corrections
    tide = predict_tide_drift(dinput['MJD'] - 48622.0,
                              hc,
                              c,
                              DELTAT=deltat,
                              CORRECTIONS=model_format)
    tide += infer_minor_corrections(dinput['MJD'] - 48622.0,
                                    hc,
                                    c,
                                    DELTAT=deltat,
                                    CORRECTIONS=model_format)
    #-- replace invalid values with fill value
    fill_value = -9999.0
    tide.data[tide.mask] = fill_value

    #-- output to file
    with open(output_file, 'w') as f:
        for d, lt, ln, td in zip(dinput['MJD'], dinput['lat'], dinput['lon'],
                                 tide):
            f.write('{0:0.6f},{1:0.2f},{2:0.2f},{3:0.2f}\n'.format(
                d, lt, ln, td))
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
예제 #11
0
def compute_LPET_icebridge_data(arg, 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

    #-- HDF5 file attributes
    attrib = dict(lon={}, lat={}, tide_lpe={}, day={})
    #-- 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'
    #-- long-period equilibrium tides
    attrib['tide_lpe']['long_name'] = 'Equilibrium_Tide'
    attrib['tide_lpe']['description'] = (
        'Long-period_equilibrium_tidal_elevation_'
        'from_the_summation_of_fifteen_tidal_spectral_lines_at_the_measurement_'
        'position_at_the_acquisition_time')
    attrib['tide_lpe']['reference'] = ('https://doi.org/10.1111/'
                                       'j.1365-246X.1973.tb03420.x')
    attrib['tide_lpe']['units'] = 'meters'
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    tide_time = pyTMD.time.convert_delta_time(dinput['time'],
                                              epoch1=(2000, 1, 1, 12, 0, 0),
                                              epoch2=(1992, 1, 1, 0, 0, 0),
                                              scale=1.0 / 86400.0)
    #-- interpolate delta times from calendar dates to tide time
    delta_file = get_data_path(['data', 'merged_deltat.data'])
    deltat = calc_delta_time(delta_file, tide_time)

    #-- output tidal HDF5 file
    #-- form: rg_NASA_model_EQUILIBRIUM_TIDES_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
    file_format = '{0}_NASA_EQUILIBRIUM_TIDES_WGS84_{1}{2}{3}{4}{5:05.0f}.H5'
    FILENAME = file_format.format(hem_flag[HEM], OIB, YY1, MM1, DD1, JJ1)
    #-- 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 long-period equilibrium tides at time
    tide_lpe = compute_equilibrium_tide(tide_time + deltat, dinput['lat'])

    #-- 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_lpe', (file_lines, ),
                            data=tide_lpe,
                            dtype=tide_lpe.dtype,
                            compression='gzip')
    #-- add HDF5 variable attributes
    for att_name, att_val in attrib['tide_lpe'].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=tide_time,
                            dtype=tide_time.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'] = ('Long-Period_Equilibrium_tidal_correction_for_'
                          'elevation_measurements')
    fid.attrs['summary'] = ('Tidal_correction_computed_at_elevation_'
                            'measurements_using_fifteen_spectral_lines.')
    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 days since 1992-01-01 into Julian days
    time_range = np.array([np.min(tide_time), np.max(tide_time)])
    time_julian = 2400000.5 + pyTMD.time.convert_delta_time(
        time_range,
        epoch1=(1992, 1, 1, 0, 0, 0),
        epoch2=(1858, 11, 17, 0, 0, 0),
        scale=1.0)
    #-- convert to calendar date
    cal = pyTMD.time.convert_julian(time_julian, 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(time_julian[-1] * 86400.0 - time_julian[0] * 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)
예제 #12
0
def compute_tides_icebridge_data(tide_dir, arg, TIDE_MODEL,
    ATLAS_FORMAT=None, GZIP=True, DEFINITION_FILE=None, METHOD='spline',
    EXTRAPOLATE=False, CUTOFF=None, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd',level=loglevel)

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(tide_dir).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(tide_dir, format=ATLAS_FORMAT,
            compressed=GZIP).elevation(TIDE_MODEL)

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

    #-- HDF5 file attributes
    attrib = collections.OrderedDict()
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['description'] = ('Time_corresponding_to_the_measurement_'
        'position')
    attrib['time']['units'] = 'Days since 1992-01-01T00:00:00'
    attrib['time']['standard_name'] = 'time'
    attrib['time']['calendar'] = 'standard'
    #-- 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'
    #-- tides
    attrib[model.variable] = {}
    attrib[model.variable]['description'] = model.description
    attrib[model.variable]['reference'] = model.reference
    attrib[model.variable]['model'] = model.name
    attrib[model.variable]['units'] = 'meters'
    attrib[model.variable]['long_name'] = model.long_name

    #-- 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.float64(ypre) >= 90):
                YY1 = '{0:4.0f}'.format(np.float64(ypre) + 1900.0)
            else:
                YY1 = '{0:4.0f}'.format(np.float64(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
    logger.info('{0} -->'.format(input_file))
    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)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    t = pyTMD.time.convert_delta_time(dinput['time'],
        epoch1=(2000,1,1,12,0,0), epoch2=(1992,1,1,0,0,0),
        scale=1.0/86400.0)
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])

    #-- read tidal constants and interpolate to grid points
    if model.format in ('OTIS','ATLAS'):
        amp,ph,D,c = extract_tidal_constants(dinput['lon'], dinput['lat'],
            model.grid_file, model.model_file, model.projection,
            TYPE=model.type, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, GRID=model.format)
        deltat = np.zeros_like(t)
    elif model.format in ('netcdf'):
        amp,ph,D,c = extract_netcdf_constants(dinput['lon'], dinput['lat'],
            model.grid_file, model.model_file, TYPE=model.type, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF, SCALE=model.scale,
            GZIP=model.compressed)
        deltat = np.zeros_like(t)
    elif (model.format == 'GOT'):
        amp,ph,c = extract_GOT_constants(dinput['lon'], dinput['lat'],
            model.model_file, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, SCALE=model.scale, GZIP=model.compressed)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)
    elif (model.format == 'FES'):
        amp,ph = extract_FES_constants(dinput['lon'], dinput['lat'],
            model.model_file, TYPE=model.type, VERSION=model.version,
            METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF,
            SCALE=model.scale, GZIP=model.compressed)
        #-- available model constituents
        c = model.constituents
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    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 name 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.name,OIB,YY1,MM1,DD1,JJ1)
    FILENAME = '{0}_NASA_{1}_TIDES_WGS84_{2}{3}{4}{5}{6:05.0f}.H5'.format(*args)
    #-- print file information
    logger.info('\t{0}'.format(FILENAME))

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

    #-- predict tidal elevations at time and infer minor corrections
    fill_value = -9999.0
    tide = np.ma.empty((file_lines),fill_value=fill_value)
    tide.mask = np.any(hc.mask,axis=1)
    tide.data[:] = predict_tide_drift(t, hc, c,
        DELTAT=deltat, CORRECTIONS=model.format)
    minor = infer_minor_corrections(t, hc, c,
        DELTAT=deltat, CORRECTIONS=model.format)
    tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.fill_value
    #-- copy tide to output variable
    dinput[model.variable] = tide.copy()

    #-- output dictionary with HDF5 variables
    h5 = {}
    #-- add variables to output file
    for key,attributes in attrib.items():
        #-- Defining the HDF5 dataset variables for lat/lon
        h5[key] = 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 attributes.items():
            h5[key].attrs[att_name] = att_val
        #-- attach dimensions
        if key not in ('time',):
            for i,dim in enumerate(['time']):
                h5[key].dims[i].label = 'RECORD_SIZE'
                h5[key].dims[i].attach_scale(h5[dim])

    #-- 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 file
    fid.attrs['elevation_file'] = os.path.basename(input_file)
    fid.attrs['tide_model'] = model.name
    #-- 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 days since 1992-01-01 into Julian days
    time_range = np.array([np.min(t),np.max(t)])
    time_julian = 2400000.5 + pyTMD.time.convert_delta_time(time_range,
        epoch1=(1992,1,1,0,0,0), epoch2=(1858,11,17,0,0,0), scale=1.0)
    #-- convert to calendar date
    cal = pyTMD.time.convert_julian(time_julian,ASTYPE=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(time_julian[-1]*86400.0 - time_julian[0]*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)
예제 #13
0
def compute_LPET_elevations(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):

    #-- 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'
    #-- long-period equilibrium tides
    attrib['tide_lpe'] = {}
    attrib['tide_lpe']['long_name'] = 'Equilibrium_Tide'
    attrib['tide_lpe']['description'] = ('Long-period_equilibrium_tidal_'
        'elevation_from_the_summation_of_fifteen_tidal_spectral_lines')
    attrib['tide_lpe']['reference'] = ('https://doi.org/10.1111/'
        'j.1365-246X.1973.tb03420.x')
    attrib['tide_lpe']['units'] = 'meters'
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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 time from units to days since 1992-01-01T00:00:00
    tide_time = pyTMD.time.convert_delta_time(to_secs*dinput['time'].flatten(),
        epoch1=epoch1, epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    #-- interpolate delta times from calendar dates to tide time
    delta_file = get_data_path(['data','merged_deltat.data'])
    deltat = calc_delta_time(delta_file, tide_time)

    #-- predict long-period equilibrium tides at time
    tide_lpe = compute_equilibrium_tide(tide_time + deltat, lat)

    #-- output to file
    output = dict(time=tide_time,lon=lon,lat=lat,tide_lpe=tide_lpe)
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output, attrib, output_file, delimiter=',',
            columns=['time','lat','lon','tide_lpe'], 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)
예제 #14
0
def compute_tides_ICESat(tide_dir, INPUT_FILE, TIDE_MODEL=None,
    ATLAS_FORMAT=None, GZIP=True, DEFINITION_FILE=None, METHOD='spline',
    EXTRAPOLATE=False, CUTOFF=None, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd',level=loglevel)

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(tide_dir).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(tide_dir, format=ATLAS_FORMAT,
            compressed=GZIP).elevation(TIDE_MODEL)

    #-- get directory from INPUT_FILE
    logger.info('{0} -->'.format(INPUT_FILE))
    DIRECTORY = os.path.dirname(INPUT_FILE)

    #-- compile regular expression operator for extracting information from file
    rx = re.compile((r'GLAH(\d{2})_(\d{3})_(\d{1})(\d{1})(\d{2})_(\d{3})_'
        r'(\d{4})_(\d{1})_(\d{2})_(\d{4})\.H5'), re.VERBOSE)
    #-- extract parameters from ICESat/GLAS HDF5 file name
    #-- PRD:  Product number (01, 05, 06, 12, 13, 14, or 15)
    #-- RL:  Release number for process that created the product = 634
    #-- RGTP:  Repeat ground-track phase (1=8-day, 2=91-day, 3=transfer orbit)
    #-- ORB:   Reference orbit number (starts at 1 and increments each time a
    #--           new reference orbit ground track file is obtained.)
    #-- INST:  Instance number (increments every time the satellite enters a
    #--           different reference orbit)
    #-- CYCL:   Cycle of reference orbit for this phase
    #-- TRK: Track within reference orbit
    #-- SEG:   Segment of orbit
    #-- GRAN:  Granule version number
    #-- TYPE:  File type
    try:
        PRD,RL,RGTP,ORB,INST,CYCL,TRK,SEG,GRAN,TYPE = rx.findall(INPUT_FILE).pop()
    except:
        #-- output tide HDF5 file (generic)
        fileBasename,fileExtension = os.path.splitext(INPUT_FILE)
        args = (fileBasename,model.name,fileExtension)
        OUTPUT_FILE = '{0}_{1}_TIDES{2}'.format(*args)
    else:
        #-- output tide HDF5 file for NSIDC granules
        args = (PRD,RL,model.name,RGTP,ORB,INST,CYCL,TRK,SEG,GRAN,TYPE)
        file_format = 'GLAH{0}_{1}_{2}_TIDES_{3}{4}{5}_{6}_{7}_{8}_{9}_{10}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- read GLAH12 HDF5 file
    fileID = h5py.File(INPUT_FILE,'r')
    n_40HZ, = fileID['Data_40HZ']['Time']['i_rec_ndx'].shape
    #-- get variables and attributes
    rec_ndx_40HZ = fileID['Data_40HZ']['Time']['i_rec_ndx'][:].copy()
    #-- seconds since 2000-01-01 12:00:00 UTC (J2000)
    DS_UTCTime_40HZ = fileID['Data_40HZ']['DS_UTCTime_40'][:].copy()
    #-- Latitude (degrees North)
    lat_TPX = fileID['Data_40HZ']['Geolocation']['d_lat'][:].copy()
    #-- Longitude (degrees East)
    lon_40HZ = fileID['Data_40HZ']['Geolocation']['d_lon'][:].copy()
    #-- Elevation (height above TOPEX/Poseidon ellipsoid in meters)
    elev_TPX = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'][:].copy()
    fv = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'].attrs['_FillValue']

    #-- semimajor axis (a) and flattening (f) for TP and WGS84 ellipsoids
    atop,ftop = (6378136.3,1.0/298.257)
    awgs,fwgs = (6378137.0,1.0/298.257223563)
    #-- convert from Topex/Poseidon to WGS84 Ellipsoids
    lat_40HZ,elev_40HZ = pyTMD.spatial.convert_ellipsoid(lat_TPX, elev_TPX,
        atop, ftop, awgs, fwgs, eps=1e-12, itmax=10)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    tide_time = pyTMD.time.convert_delta_time(DS_UTCTime_40HZ,
        epoch1=(2000,1,1,12,0,0), epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])
    #-- read tidal constants and interpolate to grid points
    if model.format in ('OTIS','ATLAS'):
        amp,ph,D,c = extract_tidal_constants(lon_40HZ, lat_40HZ,
            model.grid_file, model.model_file, model.projection, TYPE=TYPE,
            METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, GRID=model.format)
        deltat = np.zeros_like(tide_time)
    elif (model.format == 'netcdf'):
        amp,ph,D,c = extract_netcdf_constants(lon_40HZ, lat_40HZ,
            model.grid_file, model.model_file, TYPE=TYPE, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF, SCALE=model.scale,
            GZIP=model.compressed)
        deltat = np.zeros_like(tide_time)
    elif (model.format == 'GOT'):
        amp,ph,c = extract_GOT_constants(lon_40HZ, lat_40HZ,
            model.model_file, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, SCALE=model.scale, GZIP=model.compressed)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, tide_time)
    elif (model.format == 'FES'):
        amp,ph = extract_FES_constants(lon_40HZ, lat_40HZ,
            model.model_file, TYPE=TYPE, VERSION=model.version,
            METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF,
            SCALE=model.scale, GZIP=model.compressed)
        #-- available model constituents
        c = model.constituents
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, tide_time)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    hc = amp*np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    tide = np.ma.empty((n_40HZ),fill_value=fv)
    tide.mask = np.any(hc.mask,axis=1)
    tide.data[:] = predict_tide_drift(tide_time, hc, c,
        DELTAT=deltat, CORRECTIONS=model.format)
    minor = infer_minor_corrections(tide_time, hc, c,
        DELTAT=deltat, CORRECTIONS=model.format)
    tide.data[:] += minor.data[:]
    #-- replace masked and nan values with fill value
    invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
    tide.data[invalid] = tide.fill_value
    tide.mask[invalid] = True

    #-- copy variables for outputting to HDF5 file
    IS_gla12_tide = dict(Data_40HZ={})
    IS_gla12_fill = dict(Data_40HZ={})
    IS_gla12_tide_attrs = dict(Data_40HZ={})

    #-- copy global file attributes of interest
    global_attribute_list = ['featureType','title','comment','summary','license',
        'references','AccessConstraints','CitationforExternalPublication',
        'contributor_role','contributor_name','creator_name','creator_email',
        'publisher_name','publisher_email','publisher_url','platform','instrument',
        'processing_level','date_created','spatial_coverage_type','history',
        'keywords','keywords_vocabulary','naming_authority','project','time_type',
        'date_type','time_coverage_start','time_coverage_end',
        'time_coverage_duration','source','HDFVersion','identifier_product_type',
        'identifier_product_format_version','Conventions','institution',
        'ReprocessingPlanned','ReprocessingActual','LocalGranuleID',
        'ProductionDateTime','LocalVersionID','PGEVersion','OrbitNumber',
        'StartOrbitNumber','StopOrbitNumber','EquatorCrossingLongitude',
        'EquatorCrossingTime','EquatorCrossingDate','ShortName','VersionID',
        'InputPointer','RangeBeginningTime','RangeEndingTime','RangeBeginningDate',
        'RangeEndingDate','PercentGroundHit','OrbitQuality','Cycle','Track',
        'Instrument_State','Timing_Bias','ReferenceOrbit','SP_ICE_PATH_NO',
        'SP_ICE_GLAS_StartBlock','SP_ICE_GLAS_EndBlock','Instance','Range_Bias',
        'Instrument_State_Date','Instrument_State_Time','Range_Bias_Date',
        'Range_Bias_Time','Timing_Bias_Date','Timing_Bias_Time',
        'identifier_product_doi','identifier_file_uuid',
        'identifier_product_doi_authority']
    for att in global_attribute_list:
        IS_gla12_tide_attrs[att] = fileID.attrs[att]
    #-- copy ICESat campaign name from ancillary data
    IS_gla12_tide_attrs['Campaign'] = fileID['ANCILLARY_DATA'].attrs['Campaign']

    #-- add attributes for input GLA12 file
    IS_gla12_tide_attrs['input_files'] = os.path.basename(INPUT_FILE)
    #-- update geospatial ranges for ellipsoid
    IS_gla12_tide_attrs['geospatial_lat_min'] = np.min(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_max'] = np.max(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_min'] = np.min(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_max'] = np.max(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_units'] = "degrees_north"
    IS_gla12_tide_attrs['geospatial_lon_units'] = "degrees_east"
    IS_gla12_tide_attrs['geospatial_ellipsoid'] = "WGS84"

    #-- copy 40Hz group attributes
    for att_name,att_val in fileID['Data_40HZ'].attrs.items():
        IS_gla12_tide_attrs['Data_40HZ'][att_name] = att_val
    #-- copy attributes for time, geolocation and geophysical groups
    for var in ['Time','Geolocation','Geophysical']:
        IS_gla12_tide['Data_40HZ'][var] = {}
        IS_gla12_fill['Data_40HZ'][var] = {}
        IS_gla12_tide_attrs['Data_40HZ'][var] = {}
        for att_name,att_val in fileID['Data_40HZ'][var].attrs.items():
            IS_gla12_tide_attrs['Data_40HZ'][var][att_name] = att_val

    #-- J2000 time
    IS_gla12_tide['Data_40HZ']['DS_UTCTime_40'] = DS_UTCTime_40HZ
    IS_gla12_fill['Data_40HZ']['DS_UTCTime_40'] = None
    IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'] = {}
    for att_name,att_val in fileID['Data_40HZ']['DS_UTCTime_40'].attrs.items():
        if att_name not in ('DIMENSION_LIST','CLASS','NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'][att_name] = att_val
    #-- record
    IS_gla12_tide['Data_40HZ']['Time']['i_rec_ndx'] = rec_ndx_40HZ
    IS_gla12_fill['Data_40HZ']['Time']['i_rec_ndx'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name,att_val in fileID['Data_40HZ']['Time']['i_rec_ndx'].attrs.items():
        if att_name not in ('DIMENSION_LIST','CLASS','NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'][att_name] = att_val
    #-- latitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lat'] = lat_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lat'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name,att_val in fileID['Data_40HZ']['Geolocation']['d_lat'].attrs.items():
        if att_name not in ('DIMENSION_LIST','CLASS','NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'][att_name] = att_val
    #-- longitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lon'] = lon_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lon'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name,att_val in fileID['Data_40HZ']['Geolocation']['d_lon'].attrs.items():
        if att_name not in ('DIMENSION_LIST','CLASS','NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'][att_name] = att_val

    #-- geophysical variables
    #-- computed tide
    IS_gla12_tide['Data_40HZ']['Geophysical'][model.gla12] = tide
    IS_gla12_fill['Data_40HZ']['Geophysical'][model.gla12] = tide.fill_value
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['units'] = "meters"
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['long_name'] = model.long_name
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['description'] = model.description
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['source'] = model.name
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['reference'] = model.reference
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][model.gla12]['coordinates'] = \
        "../DS_UTCTime_40"

    #-- close the input HDF5 file
    fileID.close()

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_GLA12_tide_write(IS_gla12_tide, IS_gla12_tide_attrs,
        FILENAME=os.path.join(DIRECTORY,OUTPUT_FILE),
        FILL_VALUE=IS_gla12_fill, CLOBBER=True)
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY,OUTPUT_FILE), MODE)
예제 #15
0
def compute_tides_ICESat2(tide_dir,
                          FILE,
                          TIDE_MODEL=None,
                          METHOD='spline',
                          EXTRAPOLATE=False,
                          VERBOSE=False,
                          MODE=0o775):
    #-- select between tide models
    if (TIDE_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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir, 'CATS2008', 'grid_CATS2008')
        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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas_v2')
        grid_file = 'grid_tpxo9_atlas_30_v2.nc.gz'
        model_files = [
            'h_q1_tpxo9_atlas_30_v2.nc.gz', 'h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz', 'h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz', 'h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz', 'h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz', 'h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz', 'h_2n2_tpxo9_atlas_30_v2.nc.gz'
        ]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
    elif (TIDE_MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas_v3')
        grid_file = 'grid_tpxo9_atlas_30_v3.nc.gz'
        model_files = [
            'h_q1_tpxo9_atlas_30_v3.nc.gz', 'h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz', 'h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz', 'h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz', 'h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz', 'h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz', 'h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz', 'h_mm_tpxo9_atlas_30_v3.nc.gz'
        ]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir, 'Arc5km2018', 'grid_Arc5km2018')
        model_file = os.path.join(tide_dir, 'Arc5km2018', 'h_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/aotim-5/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = os.path.join(tide_dir, 'fes2014', 'ocean_tide')
        model_files = [
            '2n2.nc.gz', 'eps2.nc.gz', 'j1.nc.gz', 'k1.nc.gz', 'k2.nc.gz',
            'l2.nc.gz', 'la2.nc.gz', 'm2.nc.gz', 'm3.nc.gz', 'm4.nc.gz',
            'm6.nc.gz', 'm8.nc.gz', 'mf.nc.gz', 'mks2.nc.gz', 'mm.nc.gz',
            'mn4.nc.gz', 'ms4.nc.gz', 'msf.nc.gz', 'msqm.nc.gz', 'mtm.nc.gz',
            'mu2.nc.gz', 'n2.nc.gz', 'n4.nc.gz', 'nu2.nc.gz', 'o1.nc.gz',
            'p1.nc.gz', 'q1.nc.gz', 'r2.nc.gz', 's1.nc.gz', 's2.nc.gz',
            's4.nc.gz', 'sa.nc.gz', 'ssa.nc.gz', 't2.nc.gz'
        ]
        c = [
            '2n2', 'eps2', 'j1', 'k1', 'k2', 'l2', 'lambda2', 'm2', 'm3', 'm4',
            'm6', 'm8', 'mf', 'mks2', 'mm', 'mn4', 'ms4', 'msf', 'msqm', 'mtm',
            'mu2', 'n2', 'n4', 'nu2', 'o1', 'p1', 'q1', 'r2', 's1', 's2', 's4',
            'sa', 'ssa', 't2'
        ]
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
                     'auxiliary-products/global-tide-fes.html')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0 / 100.0
    elif (TIDE_MODEL == 'FES2014_load'):
        model_directory = os.path.join(tide_dir, 'fes2014', 'load_tide')
        model_files = [
            '2n2.nc.gz', 'eps2.nc.gz', 'j1.nc.gz', 'k1.nc.gz', 'k2.nc.gz',
            'l2.nc.gz', 'la2.nc.gz', 'm2.nc.gz', 'm3.nc.gz', 'm4.nc.gz',
            'm6.nc.gz', 'm8.nc.gz', 'mf.nc.gz', 'mks2.nc.gz', 'mm.nc.gz',
            'mn4.nc.gz', 'ms4.nc.gz', 'msf.nc.gz', 'msqm.nc.gz', 'mtm.nc.gz',
            'mu2.nc.gz', 'n2.nc.gz', 'n4.nc.gz', 'nu2.nc.gz', 'o1.nc.gz',
            'p1.nc.gz', 'q1.nc.gz', 'r2.nc.gz', 's1.nc.gz', 's2.nc.gz',
            's4.nc.gz', 'sa.nc.gz', 'ssa.nc.gz', 't2.nc.gz'
        ]
        c = [
            '2n2', 'eps2', 'j1', 'k1', 'k2', 'l2', 'lambda2', 'm2', 'm3', 'm4',
            'm6', 'm8', 'mf', 'mks2', 'mm', 'mn4', 'ms4', 'msf', 'msqm', 'mtm',
            'mu2', 'n2', 'n4', 'nu2', 'o1', 'p1', 'q1', 'r2', 's1', 's2', 's4',
            'sa', 'ssa', 't2'
        ]
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
                     'auxiliary-products/global-tide-fes.html')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0 / 100.0

    #-- read data from FILE
    print('{0} -->'.format(os.path.basename(FILE))) if VERBOSE else None
    IS2_atl11_mds, IS2_atl11_attrs, IS2_atl11_pairs = read_HDF5_ATL11(
        FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})_(\d{2})(\d{2})_'
                    r'(\d{3})_(\d{2})(.*?).h5$')
    SUB, PRD, TRK, GRAN, SCYC, ECYC, RL, VERS, AUX = rx.findall(FILE).pop()

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl11_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl11_tide = {}
    IS2_atl11_fill = {}
    IS2_atl11_dims = {}
    IS2_atl11_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl11_tide['ancillary_data'] = {}
    IS2_atl11_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl11_tide['ancillary_data'][key] = IS2_atl11_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl11_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl11_attrs['ancillary_data'][key].items(
        ):
            IS2_atl11_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam pair within the file
    for ptx in sorted(IS2_atl11_pairs):
        #-- output data dictionaries for beam
        IS2_atl11_tide[ptx] = dict(cycle_stats={})
        IS2_atl11_fill[ptx] = dict(cycle_stats={})
        IS2_atl11_dims[ptx] = dict(cycle_stats={})
        IS2_atl11_tide_attrs[ptx] = dict(cycle_stats={})

        #-- number of average segments and number of included cycles
        invalid_time = IS2_atl11_attrs[ptx]['delta_time']['_FillValue']
        n_points, n_cycles = IS2_atl11_mds[ptx]['delta_time'].shape
        #-- find valid average segments for beam pair
        fv = IS2_atl11_attrs[ptx]['h_corr']['_FillValue']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + IS2_atl11_mds[ptx]['delta_time']
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- read tidal constants and interpolate to grid points
        if model_format in ('OTIS', 'ATLAS'):
            amp, ph, D, c = extract_tidal_constants(
                IS2_atl11_mds[ptx]['longitude'],
                IS2_atl11_mds[ptx]['latitude'],
                grid_file,
                model_file,
                EPSG,
                TYPE=TYPE,
                METHOD=METHOD,
                EXTRAPOLATE=EXTRAPOLATE,
                GRID=model_format)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'netcdf'):
            amp, ph, D, c = extract_netcdf_constants(
                IS2_atl11_mds[ptx]['longitude'],
                IS2_atl11_mds[ptx]['latitude'],
                model_directory,
                grid_file,
                model_files,
                TYPE=TYPE,
                METHOD=METHOD,
                EXTRAPOLATE=EXTRAPOLATE,
                SCALE=SCALE)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'GOT'):
            amp, ph = extract_GOT_constants(IS2_atl11_mds[ptx]['longitude'],
                                            IS2_atl11_mds[ptx]['latitude'],
                                            model_directory,
                                            model_files,
                                            METHOD=METHOD,
                                            EXTRAPOLATE=EXTRAPOLATE,
                                            SCALE=SCALE)
            #-- interpolate delta times from calendar dates to tide time
            delta_file = pyTMD.utilities.get_data_path(
                ['data', 'merged_deltat.data'])
            deltat = calc_delta_time(delta_file, tide_time)
        elif (model_format == 'FES'):
            amp, ph = extract_FES_constants(IS2_atl11_mds[ptx]['longitude'],
                                            IS2_atl11_mds[ptx]['latitude'],
                                            model_directory,
                                            model_files,
                                            TYPE=TYPE,
                                            VERSION=TIDE_MODEL,
                                            METHOD=METHOD,
                                            EXTRAPOLATE=EXTRAPOLATE,
                                            SCALE=SCALE)
            #-- interpolate delta times from calendar dates to tide time
            delta_file = pyTMD.utilities.get_data_path(
                ['data', 'merged_deltat.data'])
            deltat = calc_delta_time(delta_file, tide_time)

        #-- calculate complex phase in radians for Euler's
        cph = -1j * ph * np.pi / 180.0
        #-- calculate constituent oscillation
        hc = amp * np.exp(cph)

        #-- allocate for each cycle
        tide = np.ma.empty((n_points, n_cycles), fill_value=fv)
        tide.mask = (IS2_atl11_mds[ptx]['delta_time'] == invalid_time)
        for cycle in range(n_cycles):
            #-- find valid time and spatial points for cycle
            tide.mask[:, cycle] |= np.any(hc.mask, axis=1)
            valid, = np.nonzero(~tide.mask[:, cycle])
            #-- predict tidal elevations and infer minor corrections
            tide.data[valid,
                      cycle] = predict_tide_drift(tide_time[valid, cycle],
                                                  hc[valid, :],
                                                  c,
                                                  DELTAT=deltat[valid, cycle],
                                                  CORRECTIONS=model_format)
            minor = infer_minor_corrections(tide_time[valid, cycle],
                                            hc[valid, :],
                                            c,
                                            DELTAT=deltat[valid, cycle],
                                            CORRECTIONS=model_format)
            tide.data[valid, cycle] += minor.data[:]
        #-- replace masked and nan values with fill value
        invalid = np.nonzero(np.isnan(tide.data) | tide.mask)
        tide.data[invalid] = tide.fill_value
        tide.mask[invalid] = True

        #-- group attributes for beam
        IS2_atl11_tide_attrs[ptx]['description'] = (
            'Contains the primary science parameters for this '
            'data set')
        IS2_atl11_tide_attrs[ptx]['beam_pair'] = IS2_atl11_attrs[ptx][
            'beam_pair']
        IS2_atl11_tide_attrs[ptx]['ReferenceGroundTrack'] = IS2_atl11_attrs[
            ptx]['ReferenceGroundTrack']
        IS2_atl11_tide_attrs[ptx]['first_cycle'] = IS2_atl11_attrs[ptx][
            'first_cycle']
        IS2_atl11_tide_attrs[ptx]['last_cycle'] = IS2_atl11_attrs[ptx][
            'last_cycle']
        IS2_atl11_tide_attrs[ptx]['equatorial_radius'] = IS2_atl11_attrs[ptx][
            'equatorial_radius']
        IS2_atl11_tide_attrs[ptx]['polar_radius'] = IS2_atl11_attrs[ptx][
            'polar_radius']

        #-- geolocation, time and reference point
        #-- cycle_number
        IS2_atl11_tide[ptx]['cycle_number'] = IS2_atl11_mds[ptx][
            'cycle_number'].copy()
        IS2_atl11_fill[ptx]['cycle_number'] = None
        IS2_atl11_dims[ptx]['cycle_number'] = None
        IS2_atl11_tide_attrs[ptx]['cycle_number'] = {}
        IS2_atl11_tide_attrs[ptx]['cycle_number']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['cycle_number'][
            'long_name'] = "Orbital cycle number"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['description'] = (
            "Number of 91-day periods "
            "that have elapsed since ICESat-2 entered the science orbit. Each of the 1,387 "
            "reference ground track (RGTs) is targeted in the polar regions once "
            "every 91 days.")
        #-- delta time
        IS2_atl11_tide[ptx]['delta_time'] = IS2_atl11_mds[ptx][
            'delta_time'].copy()
        IS2_atl11_fill[ptx]['delta_time'] = IS2_atl11_attrs[ptx]['delta_time'][
            '_FillValue']
        IS2_atl11_dims[ptx]['delta_time'] = ['ref_pt', 'cycle_number']
        IS2_atl11_tide_attrs[ptx]['delta_time'] = {}
        IS2_atl11_tide_attrs[ptx]['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl11_tide_attrs[ptx]['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl11_tide_attrs[ptx]['delta_time']['standard_name'] = "time"
        IS2_atl11_tide_attrs[ptx]['delta_time']['calendar'] = "standard"
        IS2_atl11_tide_attrs[ptx]['delta_time']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['delta_time']['description'] = (
            "Number of GPS "
            "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
            "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
            "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
            "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
            "time in gps_seconds relative to the GPS epoch can be computed.")
        IS2_atl11_tide_attrs[ptx]['delta_time']['coordinates'] = \
            "ref_pt cycle_number latitude longitude"
        #-- latitude
        IS2_atl11_tide[ptx]['latitude'] = IS2_atl11_mds[ptx]['latitude'].copy()
        IS2_atl11_fill[ptx]['latitude'] = IS2_atl11_attrs[ptx]['latitude'][
            '_FillValue']
        IS2_atl11_dims[ptx]['latitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['latitude'] = {}
        IS2_atl11_tide_attrs[ptx]['latitude']['units'] = "degrees_north"
        IS2_atl11_tide_attrs[ptx]['latitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['latitude']['long_name'] = "Latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['standard_name'] = "latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['latitude']['description'] = (
            "Center latitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_min'] = -90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_max'] = 90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['coordinates'] = \
            "ref_pt delta_time longitude"
        #-- longitude
        IS2_atl11_tide[ptx]['longitude'] = IS2_atl11_mds[ptx][
            'longitude'].copy()
        IS2_atl11_fill[ptx]['longitude'] = IS2_atl11_attrs[ptx]['longitude'][
            '_FillValue']
        IS2_atl11_dims[ptx]['longitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['longitude'] = {}
        IS2_atl11_tide_attrs[ptx]['longitude']['units'] = "degrees_east"
        IS2_atl11_tide_attrs[ptx]['longitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['longitude']['long_name'] = "Longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['standard_name'] = "longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['longitude']['description'] = (
            "Center longitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_min'] = -180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_max'] = 180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['coordinates'] = \
            "ref_pt delta_time latitude"
        #-- reference point
        IS2_atl11_tide[ptx]['ref_pt'] = IS2_atl11_mds[ptx]['ref_pt'].copy()
        IS2_atl11_fill[ptx]['ref_pt'] = None
        IS2_atl11_dims[ptx]['ref_pt'] = None
        IS2_atl11_tide_attrs[ptx]['ref_pt'] = {}
        IS2_atl11_tide_attrs[ptx]['ref_pt']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['ref_pt'][
            'contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['ref_pt'][
            'long_name'] = "Reference point number"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['description'] = (
            "The reference point is the 7 digit segment_id "
            "number corresponding to the center of the ATL06 data used for each ATL11 point.  These are "
            "sequential, starting with 1 for the first segment after an ascending equatorial crossing node."
        )
        IS2_atl11_tide_attrs[ptx]['ref_pt']['coordinates'] = \
            "delta_time latitude longitude"

        #-- cycle statistics variables
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['Description'] = (
            "The cycle_stats subgroup "
            "contains summary information about segments for each reference point, including "
            "the uncorrected mean heights for reference surfaces, blowing snow and cloud "
            "indicators, and geolocation and height misfit statistics.")
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['data_rate'] = (
            "Data within this group "
            "are stored at the average segment rate.")
        #-- computed tide
        IS2_atl11_tide[ptx]['cycle_stats'][variable] = tide
        IS2_atl11_fill[ptx]['cycle_stats'][variable] = tide.fill_value
        IS2_atl11_dims[ptx]['cycle_stats'][variable] = [
            'ref_pt', 'cycle_number'
        ]
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable] = {}
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable]['units'] = "meters"
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable][
            'contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable][
            'long_name'] = long_name
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable][
            'description'] = description
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable][
            'source'] = TIDE_MODEL
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable][
            'reference'] = reference
        IS2_atl11_tide_attrs[ptx]['cycle_stats'][variable]['coordinates'] = \
            "../ref_pt ../cycle_number ../delta_time ../latitude ../longitude"

    #-- output tidal HDF5 file
    args = (PRD, TIDE_MODEL, TRK, GRAN, SCYC, ECYC, RL, VERS, AUX)
    file_format = '{0}_{1}_TIDES_{2}{3}_{4}{5}_{6}_{7}{8}.h5'
    #-- print file information
    print('\t{0}'.format(file_format.format(*args))) if VERBOSE else None
    HDF5_ATL11_tide_write(IS2_atl11_tide,
                          IS2_atl11_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(FILE),
                          FILL_VALUE=IS2_atl11_fill,
                          DIMENSIONS=IS2_atl11_dims,
                          FILENAME=os.path.join(DIRECTORY,
                                                file_format.format(*args)))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, file_format.format(*args)), MODE)
def compute_LPET_ICESat2(FILE, VERBOSE=False, MODE=0o775):

    #-- read data from FILE
    print('{0} -->'.format(os.path.basename(FILE))) if VERBOSE else None
    IS2_atl07_mds, IS2_atl07_attrs, IS2_atl07_beams = read_HDF5_ATL07(
        FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 sea ice file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})-(\d{2})_(\d{4})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$'
    )
    SUB, PRD, HEM, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN, RL, VERS, AUX = rx.findall(
        FILE).pop()

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl07_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl07_tide = {}
    IS2_atl07_fill = {}
    IS2_atl07_dims = {}
    IS2_atl07_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl07_tide['ancillary_data'] = {}
    IS2_atl07_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl07_tide['ancillary_data'][key] = IS2_atl07_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl07_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl07_attrs['ancillary_data'][key].items(
        ):
            IS2_atl07_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl07_beams):
        #-- output data dictionaries for beam
        IS2_atl07_tide[gtx] = dict(sea_ice_segments={})
        IS2_atl07_fill[gtx] = dict(sea_ice_segments={})
        IS2_atl07_dims[gtx] = dict(sea_ice_segments={})
        IS2_atl07_tide_attrs[gtx] = dict(sea_ice_segments={})

        #-- number of segments
        val = IS2_atl07_mds[gtx]['sea_ice_segments']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + val['delta_time']
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- interpolate delta times from calendar dates to tide time
        delta_file = get_data_path(['data', 'merged_deltat.data'])
        deltat = calc_delta_time(delta_file, tide_time)

        #-- predict long-period equilibrium tides at latitudes and time
        tide_lpe = compute_equilibrium_tide(tide_time + deltat,
                                            val['latitude'])

        #-- group attributes for beam
        IS2_atl07_tide_attrs[gtx]['Description'] = IS2_atl07_attrs[gtx][
            'Description']
        IS2_atl07_tide_attrs[gtx]['atlas_pce'] = IS2_atl07_attrs[gtx][
            'atlas_pce']
        IS2_atl07_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl07_attrs[gtx][
            'atlas_beam_type']
        IS2_atl07_tide_attrs[gtx]['groundtrack_id'] = IS2_atl07_attrs[gtx][
            'groundtrack_id']
        IS2_atl07_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl07_attrs[gtx][
            'atmosphere_profile']
        IS2_atl07_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl07_attrs[gtx][
            'atlas_spot_number']
        IS2_atl07_tide_attrs[gtx]['sc_orientation'] = IS2_atl07_attrs[gtx][
            'sc_orientation']
        #-- group attributes for sea_ice_segments
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['Description'] = (
            "Top group for sea "
            "ice segments as computed by the ATBD algorithm.")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['data_rate'] = (
            "Data within this "
            "group are stored at the variable segment rate.")

        #-- geolocation, time and segment ID
        #-- delta time
        IS2_atl07_tide[gtx]['sea_ice_segments']['delta_time'] = val[
            'delta_time'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['delta_time'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['delta_time'] = None
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'][
            'standard_name'] = "time"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'][
            'source'] = "telemetry"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'][
            'calendar'] = "standard"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['description'] = (
            "Number of "
            "GPS seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch "
            "offset is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS "
            "seconds between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP "
            "epoch. By adding the offset contained within atlas_sdp_gps_epoch to delta time "
            "parameters, the time in gps_seconds relative to the GPS epoch can be computed."
        )
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['coordinates'] = \
            "height_segment_id latitude longitude"
        #-- latitude
        IS2_atl07_tide[gtx]['sea_ice_segments']['latitude'] = val[
            'latitude'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['latitude'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['latitude'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'units'] = "degrees_north"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'long_name'] = "Latitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'standard_name'] = "latitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'description'] = ("Latitude of "
                              "segment center")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'valid_min'] = -90.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'][
            'valid_max'] = 90.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['coordinates'] = \
            "height_segment_id delta_time longitude"
        #-- longitude
        IS2_atl07_tide[gtx]['sea_ice_segments']['longitude'] = val[
            'longitude'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['longitude'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['longitude'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'units'] = "degrees_east"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'long_name'] = "Longitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'standard_name'] = "longitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'description'] = ("Longitude of "
                              "segment center")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'valid_min'] = -180.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'][
            'valid_max'] = 180.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['coordinates'] = \
            "height_segment_id delta_time latitude"
        #-- segment ID
        IS2_atl07_tide[gtx]['sea_ice_segments']['height_segment_id'] = val[
            'height_segment_id']
        IS2_atl07_fill[gtx]['sea_ice_segments']['height_segment_id'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['height_segment_id'] = [
            'delta_time'
        ]
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id'][
            'units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id'][
            'contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['long_name'] = \
            "Identifier of each height segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['description'] = \
            "Identifier of each height segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['coordinates'] = \
            "delta_time latitude longitude"
        #-- geolocation segment beginning
        IS2_atl07_tide[gtx]['sea_ice_segments']['geoseg_beg'] = val[
            'geoseg_beg'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['geoseg_beg'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['geoseg_beg'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg'][
            'units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg'][
            'contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg'][
            'long_name'] = "Beginning GEOSEG"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['description'] = \
            "Geolocation segment (geoseg) ID associated with the first photon used in this sea ice segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"
        #-- geolocation segment ending
        IS2_atl07_tide[gtx]['sea_ice_segments']['geoseg_end'] = val[
            'geoseg_end'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['geoseg_end'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['geoseg_end'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end'][
            'units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end'][
            'contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end'][
            'long_name'] = "Ending GEOSEG"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['description'] = \
            "Geolocation segment (geoseg) ID associated with the last photon used in this sea ice segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"
        #-- along track distance
        IS2_atl07_tide[gtx]['sea_ice_segments']['seg_dist_x'] = val[
            'seg_dist_x'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['seg_dist_x'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['seg_dist_x'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x'][
            'units'] = "meters"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x'][
            'contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x'][
            'long_name'] = "Along track distance"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['description'] = \
            "Along-track distance from the equator crossing to the segment center."
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"

        #-- geophysical variables
        IS2_atl07_tide[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_fill[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_dims[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'Description'] = (
                "Contains geophysical "
                "parameters and corrections used to correct photon heights for geophysical effects, such as tides."
            )
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'data_rate'] = ("Data within this group "
                            "are stored at the sea_ice_height segment rate.")

        #-- computed long-period equilibrium tide
        IS2_atl07_tide[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe'] = tide_lpe
        IS2_atl07_fill[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe']['units'] = "meters"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe']['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical']['height_segment_lpe']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][
            'height_segment_lpe']['description'] = (
                "Long-period "
                "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
            )
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical']['height_segment_lpe']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical']['height_segment_lpe']['coordinates'] = \
            "../height_segment_id ../delta_time ../latitude ../longitude"

    #-- output equilibrium tide HDF5 file
    args = (PRD, HEM, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN, RL, VERS, AUX)
    ff = '{0}-{1}_LPET_{2}{3}{4}{5}{6}{7}_{8}{9}{10}_{11}_{12}{13}.h5'
    #-- print file information
    print('\t{0}'.format(ff.format(*args))) if VERBOSE else None
    HDF5_ATL07_tide_write(IS2_atl07_tide,
                          IS2_atl07_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(FILE),
                          FILL_VALUE=IS2_atl07_fill,
                          DIMENSIONS=IS2_atl07_dims,
                          FILENAME=os.path.join(DIRECTORY, ff.format(*args)))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, ff.format(*args)), MODE)
예제 #17
0
def compute_LPET_ICESat2(INPUT_FILE, VERBOSE=False, MODE=0o775):

    #-- read data from input file
    print('{0} -->'.format(os.path.basename(INPUT_FILE))) if VERBOSE else None
    IS2_atl06_mds, IS2_atl06_attrs, IS2_atl06_beams = read_HDF5_ATL06(
        INPUT_FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$')
    try:
        SUB, PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output long-period equilibrium tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        OUTPUT_FILE = '{0}_{1}{2}'.format(fileBasename, 'LPET', fileExtension)
    else:
        #-- output long-period equilibrium tide HDF5 file for ASAS/NSIDC granules
        args = (PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX)
        file_format = '{0}_LPET_{1}{2}{3}{4}{5}{6}_{7}{8}{9}_{10}_{11}{12}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl06_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl06_tide = {}
    IS2_atl06_fill = {}
    IS2_atl06_dims = {}
    IS2_atl06_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl06_tide['ancillary_data'] = {}
    IS2_atl06_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl06_tide['ancillary_data'][key] = IS2_atl06_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl06_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl06_attrs['ancillary_data'][key].items(
        ):
            IS2_atl06_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl06_beams):
        #-- output data dictionaries for beam
        IS2_atl06_tide[gtx] = dict(land_ice_segments={})
        IS2_atl06_fill[gtx] = dict(land_ice_segments={})
        IS2_atl06_dims[gtx] = dict(land_ice_segments={})
        IS2_atl06_tide_attrs[gtx] = dict(land_ice_segments={})

        #-- number of segments
        val = IS2_atl06_mds[gtx]['land_ice_segments']
        n_seg = len(val['segment_id'])
        #-- find valid segments for beam
        fv = IS2_atl06_attrs[gtx]['land_ice_segments']['h_li']['_FillValue']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + val['delta_time']
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- interpolate delta times from calendar dates to tide time
        delta_file = get_data_path(['data', 'merged_deltat.data'])
        deltat = calc_delta_time(delta_file, tide_time)

        #-- predict long-period equilibrium tides at latitudes and time
        tide_lpe = np.ma.zeros((n_seg), fill_value=fv)
        tide_lpe.data[:] = compute_equilibrium_tide(tide_time + deltat,
                                                    val['latitude'])
        tide_lpe.mask = (val['latitude'] == fv) | (val['delta_time'] == fv)

        #-- group attributes for beam
        IS2_atl06_tide_attrs[gtx]['Description'] = IS2_atl06_attrs[gtx][
            'Description']
        IS2_atl06_tide_attrs[gtx]['atlas_pce'] = IS2_atl06_attrs[gtx][
            'atlas_pce']
        IS2_atl06_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl06_attrs[gtx][
            'atlas_beam_type']
        IS2_atl06_tide_attrs[gtx]['groundtrack_id'] = IS2_atl06_attrs[gtx][
            'groundtrack_id']
        IS2_atl06_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl06_attrs[gtx][
            'atmosphere_profile']
        IS2_atl06_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl06_attrs[gtx][
            'atlas_spot_number']
        IS2_atl06_tide_attrs[gtx]['sc_orientation'] = IS2_atl06_attrs[gtx][
            'sc_orientation']
        #-- group attributes for land_ice_segments
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['Description'] = (
            "The land_ice_segments group "
            "contains the primary set of derived products. This includes geolocation, height, and "
            "standard error and quality measures for each segment. This group is sparse, meaning "
            "that parameters are provided only for pairs of segments for which at least one beam "
            "has a valid surface-height measurement.")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['data_rate'] = (
            "Data within this group are "
            "sparse.  Data values are provided only for those ICESat-2 20m segments where at "
            "least one beam has a valid land ice height measurement.")

        #-- geolocation, time and segment ID
        #-- delta time
        delta_time = np.ma.array(val['delta_time'],
                                 fill_value=fv,
                                 mask=(val['delta_time'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['delta_time'] = delta_time
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'delta_time'] = delta_time.fill_value
        IS2_atl06_dims[gtx]['land_ice_segments']['delta_time'] = None
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'standard_name'] = "time"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'calendar'] = "standard"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'description'] = (
                "Number of GPS "
                "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
                "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
                "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
                "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
                "time in gps_seconds relative to the GPS epoch can be computed."
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time']['coordinates'] = \
            "segment_id latitude longitude"
        #-- latitude
        latitude = np.ma.array(val['latitude'],
                               fill_value=fv,
                               mask=(val['latitude'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['latitude'] = latitude
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'latitude'] = latitude.fill_value
        IS2_atl06_dims[gtx]['land_ice_segments']['latitude'] = ['delta_time']
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'units'] = "degrees_north"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'long_name'] = "Latitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'standard_name'] = "latitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'description'] = ("Latitude of "
                              "segment center")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'valid_min'] = -90.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'valid_max'] = 90.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude']['coordinates'] = \
            "segment_id delta_time longitude"
        #-- longitude
        longitude = np.ma.array(val['longitude'],
                                fill_value=fv,
                                mask=(val['longitude'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['longitude'] = longitude
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'longitude'] = longitude.fill_value
        IS2_atl06_dims[gtx]['land_ice_segments']['longitude'] = ['delta_time']
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'units'] = "degrees_east"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'long_name'] = "Longitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'standard_name'] = "longitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'description'] = ("Longitude of "
                              "segment center")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'valid_min'] = -180.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'valid_max'] = 180.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude']['coordinates'] = \
            "segment_id delta_time latitude"
        #-- segment ID
        IS2_atl06_tide[gtx]['land_ice_segments']['segment_id'] = val[
            'segment_id']
        IS2_atl06_fill[gtx]['land_ice_segments']['segment_id'] = None
        IS2_atl06_dims[gtx]['land_ice_segments']['segment_id'] = ['delta_time']
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'units'] = "1"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'contentType'] = "referenceInformation"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'long_name'] = "Along-track segment ID number"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'description'] = (
                "A 7 digit number "
                "identifying the along-track geolocation segment number.  These are sequential, starting with "
                "1 for the first segment after an ascending equatorial crossing node. Equal to the segment_id for "
                "the second of the two 20m ATL03 segments included in the 40m ATL06 segment"
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id']['coordinates'] = \
            "delta_time latitude longitude"

        #-- geophysical variables
        IS2_atl06_tide[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_fill[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_dims[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'Description'] = (
                "The geophysical group "
                "contains parameters used to correct segment heights for geophysical effects, parameters "
                "related to solar background and parameters indicative of the presence or absence of clouds."
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'data_rate'] = (
                "Data within this group "
                "are stored at the land_ice_segments segment rate.")
        #-- computed long-period equilibrium tide
        IS2_atl06_tide[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium'] = tide_lpe
        IS2_atl06_fill[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium'] = tide_lpe.fill_value
        IS2_atl06_dims[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium'] = ['delta_time']
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium']['units'] = "meters"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium']['contentType'] = "referenceInformation"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical']['tide_equilibrium']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'tide_equilibrium']['description'] = (
                "Long-period "
                "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical']['tide_equilibrium']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical']['tide_equilibrium']['coordinates'] = \
            "../segment_id ../delta_time ../latitude ../longitude"

    #-- print file information
    print('\t{0}'.format(OUTPUT_FILE)) if VERBOSE else None
    HDF5_ATL06_tide_write(IS2_atl06_tide,
                          IS2_atl06_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(INPUT_FILE),
                          FILL_VALUE=IS2_atl06_fill,
                          DIMENSIONS=IS2_atl06_dims,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #18
0
def compute_tidal_elevations(tide_dir, input_file, output_file,
    TIDE_MODEL=None, ATLAS_FORMAT='netcdf', GZIP=True,
    DEFINITION_FILE=None, FORMAT='csv', VARIABLES=[], HEADER=0,
    TYPE='drift', TIME_UNITS='days since 1858-11-17T00:00:00',
    TIME_STANDARD='UTC', TIME=None, PROJECTION='4326', METHOD='spline',
    EXTRAPOLATE=False, CUTOFF=None, VERBOSE=False, MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logging.basicConfig(level=loglevel)

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(tide_dir).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(tide_dir, format=ATLAS_FORMAT,
            compressed=GZIP).elevation(TIDE_MODEL)
    output_variable = model.variable

    #-- 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'
    #-- tides
    attrib[output_variable] = {}
    attrib[output_variable]['description'] = model.description
    attrib[output_variable]['reference'] = model.reference
    attrib[output_variable]['model'] = model.name
    attrib[output_variable]['units'] = 'meters'
    attrib[output_variable]['long_name'] = model.long_name
    attrib[output_variable]['_FillValue'] = fill_value
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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=HEADER)
    elif (FORMAT == 'netCDF4'):
        dinput = pyTMD.spatial.from_netCDF4(input_file, timename=VARIABLES[0],
            xname=VARIABLES[2], yname=VARIABLES[1], varname=VARIABLES[3])
    elif (FORMAT == 'HDF5'):
        dinput = pyTMD.spatial.from_HDF5(input_file, timename=VARIABLES[0],
            xname=VARIABLES[2], yname=VARIABLES[1], varname=VARIABLES[3])
    elif (FORMAT == 'geotiff'):
        dinput = pyTMD.spatial.from_geotiff(input_file)
        #-- copy global geotiff attributes for projection and grid parameters
        for att_name in ['projection','wkt','spacing','extent']:
            attrib[att_name] = dinput['attributes'][att_name]
    #-- update time variable if entered as argument
    if TIME is not None:
        dinput['time'] = np.copy(TIME)

    #-- converting x,y from projection to latitude/longitude
    crs1 = get_projection(dinput['attributes'], PROJECTION)
    crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326))
    transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)
    if (TYPE == 'grid'):
        ny,nx = (len(dinput['y']),len(dinput['x']))
        gridx,gridy = np.meshgrid(dinput['x'],dinput['y'])
        lon,lat = transformer.transform(gridx,gridy)
    elif (TYPE == 'drift'):
        lon,lat = transformer.transform(dinput['x'],dinput['y'])

    #-- extract time units from netCDF4 and HDF5 attributes or from TIME_UNITS
    try:
        time_string = dinput['attributes']['time']['units']
        epoch1,to_secs = pyTMD.time.parse_date_string(time_string)
    except (TypeError, KeyError, ValueError):
        epoch1,to_secs = pyTMD.time.parse_date_string(TIME_UNITS)
    #-- convert time to seconds
    delta_time = to_secs*dinput['time'].flatten()

    #-- calculate leap seconds if specified
    if (TIME_STANDARD.upper() == 'GPS'):
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(0, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    elif (TIME_STANDARD.upper() == 'LORAN'):
        #-- LORAN time is ahead of GPS time by 9 seconds
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(-9.0, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time-9.0, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    elif (TIME_STANDARD.upper() == 'TAI'):
        #-- TAI time is ahead of GPS time by 19 seconds
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(-19.0, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time-19.0, epoch1=epoch1,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    else:
        leap_seconds = 0.0

    #-- convert time from units to days since 1992-01-01T00:00:00
    tide_time = pyTMD.time.convert_delta_time(delta_time-leap_seconds,
        epoch1=epoch1, epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    #-- number of time points
    nt = len(tide_time)
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])

    #-- read tidal constants and interpolate to grid points
    if model.format in ('OTIS','ATLAS'):
        amp,ph,D,c = extract_tidal_constants(lon.flatten(), lat.flatten(),
            model.grid_file, model.model_file, model.projection,
            TYPE=model.type, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, GRID=model.format)
        deltat = np.zeros((nt))
    elif (model.format == 'netcdf'):
        amp,ph,D,c = extract_netcdf_constants(lon.flatten(), lat.flatten(),
            model.grid_file, model.model_file, TYPE=model.type,
            METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF,
            SCALE=model.scale, GZIP=model.compressed)
        deltat = np.zeros((nt))
    elif (model.format == 'GOT'):
        amp,ph,c = extract_GOT_constants(lon.flatten(), lat.flatten(),
            model.model_file, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            CUTOFF=CUTOFF, SCALE=model.scale, GZIP=model.compressed)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file,tide_time)
    elif (model.format == 'FES'):
        amp,ph = extract_FES_constants(lon.flatten(), lat.flatten(),
            model.model_file, TYPE=model.type, VERSION=model.version,
            METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF,
            SCALE=model.scale, GZIP=model.compressed)
        #-- available model constituents
        c = model.constituents
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file,tide_time)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    hc = amp*np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    if (TYPE == 'grid'):
        tide = np.ma.zeros((ny,nx,nt),fill_value=fill_value)
        tide.mask = np.zeros((ny,nx,nt),dtype=bool)
        for i in range(nt):
            TIDE = predict_tide(tide_time[i], hc, c,
                DELTAT=deltat[i], CORRECTIONS=model.format)
            MINOR = infer_minor_corrections(tide_time[i], hc, c,
                DELTAT=deltat[i], CORRECTIONS=model.format)
            #-- add major and minor components and reform grid
            tide[:,:,i] = np.reshape((TIDE+MINOR), (ny,nx))
            tide.mask[:,:,i] = np.reshape((TIDE.mask | MINOR.mask), (ny,nx))
    elif (TYPE == 'drift'):
        tide = np.ma.zeros((nt), fill_value=fill_value)
        tide.mask = np.any(hc.mask,axis=1)
        tide.data[:] = predict_tide_drift(tide_time, hc, c,
            DELTAT=deltat, CORRECTIONS=model.format)
        minor = infer_minor_corrections(tide_time, hc, c,
            DELTAT=deltat, CORRECTIONS=model.format)
        tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.fill_value

    #-- output to file
    output = {'time':tide_time,'lon':lon,'lat':lat,output_variable:tide}
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output, attrib, output_file, delimiter=',',
            columns=['time','lat','lon',output_variable])
    elif (FORMAT == 'netCDF4'):
        pyTMD.spatial.to_netCDF4(output, attrib, output_file)
    elif (FORMAT == 'HDF5'):
        pyTMD.spatial.to_HDF5(output, attrib, output_file)
    elif (FORMAT == 'geotiff'):
        pyTMD.spatial.to_geotiff(output, attrib, output_file,
            varname=output_variable)
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
예제 #19
0
def compute_LPET_ICESat2(FILE, VERBOSE=False, MODE=0o775):

    #-- read data from FILE
    print('{0} -->'.format(os.path.basename(FILE))) if VERBOSE else None
    IS2_atl11_mds, IS2_atl11_attrs, IS2_atl11_pairs = read_HDF5_ATL11(
        FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(r'(processed_)?(ATL\d{2})_(\d{4})(\d{2})_(\d{2})(\d{2})_'
                    r'(\d{3})_(\d{2})(.*?).h5$')
    SUB, PRD, TRK, GRAN, SCYC, ECYC, RL, VERS, AUX = rx.findall(FILE).pop()

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl11_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl11_tide = {}
    IS2_atl11_fill = {}
    IS2_atl11_dims = {}
    IS2_atl11_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl11_tide['ancillary_data'] = {}
    IS2_atl11_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl11_tide['ancillary_data'][key] = IS2_atl11_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl11_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl11_attrs['ancillary_data'][key].items(
        ):
            IS2_atl11_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam pair within the file
    for ptx in sorted(IS2_atl11_pairs):
        #-- output data dictionaries for beam
        IS2_atl11_tide[ptx] = dict(cycle_stats={})
        IS2_atl11_fill[ptx] = dict(cycle_stats={})
        IS2_atl11_dims[ptx] = dict(cycle_stats={})
        IS2_atl11_tide_attrs[ptx] = dict(cycle_stats={})

        #-- number of average segments and number of included cycles
        invalid_time = IS2_atl11_attrs[ptx]['delta_time']['_FillValue']
        n_points, n_cycles = IS2_atl11_mds[ptx]['delta_time'].shape
        #-- latitudinal values
        lat = IS2_atl11_mds[ptx]['latitude'].copy()
        #-- find valid average segments for beam pair
        fv = IS2_atl11_attrs[ptx]['h_corr']['_FillValue']

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + IS2_atl11_mds[ptx]['delta_time']
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds - leap_seconds,
                                                  epoch1=(1980, 1, 6, 0, 0, 0),
                                                  epoch2=(1992, 1, 1, 0, 0, 0),
                                                  scale=1.0 / 86400.0)
        #-- interpolate delta times from calendar dates to tide time
        delta_file = get_data_path(['data', 'merged_deltat.data'])
        deltat = calc_delta_time(delta_file, tide_time)

        #-- allocate for each cycle
        tide_lpe = np.ma.empty((n_points, n_cycles), fill_value=fv)
        tide_lpe.mask = (IS2_atl11_mds[ptx]['delta_time'] == invalid_time)
        for cycle in range(n_cycles):
            #-- find valid time and spatial points for cycle
            valid, = np.nonzero(~tide_lpe.mask[:, cycle])
            #-- predict long-period equilibrium tides at latitudes and time
            t = tide_time[valid, cycle] + deltat[valid, cycle]
            tide_lpe.data[valid,
                          cycle] = compute_equilibrium_tide(t, lat[valid])
        #-- replace masked and nan values with fill value
        invalid = np.nonzero(np.isnan(tide_lpe.data) | tide_lpe.mask)
        tide_lpe.data[invalid] = tide_lpe.fill_value
        tide_lpe.mask[invalid] = True

        #-- group attributes for beam
        IS2_atl11_tide_attrs[ptx]['description'] = (
            'Contains the primary science parameters for this '
            'data set')
        IS2_atl11_tide_attrs[ptx]['beam_pair'] = IS2_atl11_attrs[ptx][
            'beam_pair']
        IS2_atl11_tide_attrs[ptx]['ReferenceGroundTrack'] = IS2_atl11_attrs[
            ptx]['ReferenceGroundTrack']
        IS2_atl11_tide_attrs[ptx]['first_cycle'] = IS2_atl11_attrs[ptx][
            'first_cycle']
        IS2_atl11_tide_attrs[ptx]['last_cycle'] = IS2_atl11_attrs[ptx][
            'last_cycle']
        IS2_atl11_tide_attrs[ptx]['equatorial_radius'] = IS2_atl11_attrs[ptx][
            'equatorial_radius']
        IS2_atl11_tide_attrs[ptx]['polar_radius'] = IS2_atl11_attrs[ptx][
            'polar_radius']

        #-- geolocation, time and reference point
        #-- cycle_number
        IS2_atl11_tide[ptx]['cycle_number'] = IS2_atl11_mds[ptx][
            'cycle_number'].copy()
        IS2_atl11_fill[ptx]['cycle_number'] = None
        IS2_atl11_dims[ptx]['cycle_number'] = None
        IS2_atl11_tide_attrs[ptx]['cycle_number'] = {}
        IS2_atl11_tide_attrs[ptx]['cycle_number']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['cycle_number'][
            'long_name'] = "Orbital cycle number"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['cycle_number']['description'] = (
            "Number of 91-day periods "
            "that have elapsed since ICESat-2 entered the science orbit. Each of the 1,387 "
            "reference ground track (RGTs) is targeted in the polar regions once "
            "every 91 days.")
        #-- delta time
        IS2_atl11_tide[ptx]['delta_time'] = IS2_atl11_mds[ptx][
            'delta_time'].copy()
        IS2_atl11_fill[ptx]['delta_time'] = IS2_atl11_attrs[ptx]['delta_time'][
            '_FillValue']
        IS2_atl11_dims[ptx]['delta_time'] = ['ref_pt', 'cycle_number']
        IS2_atl11_tide_attrs[ptx]['delta_time'] = {}
        IS2_atl11_tide_attrs[ptx]['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl11_tide_attrs[ptx]['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl11_tide_attrs[ptx]['delta_time']['standard_name'] = "time"
        IS2_atl11_tide_attrs[ptx]['delta_time']['calendar'] = "standard"
        IS2_atl11_tide_attrs[ptx]['delta_time']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['delta_time']['description'] = (
            "Number of GPS "
            "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
            "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
            "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
            "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
            "time in gps_seconds relative to the GPS epoch can be computed.")
        IS2_atl11_tide_attrs[ptx]['delta_time']['coordinates'] = \
            "ref_pt cycle_number latitude longitude"
        #-- latitude
        IS2_atl11_tide[ptx]['latitude'] = IS2_atl11_mds[ptx]['latitude'].copy()
        IS2_atl11_fill[ptx]['latitude'] = IS2_atl11_attrs[ptx]['latitude'][
            '_FillValue']
        IS2_atl11_dims[ptx]['latitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['latitude'] = {}
        IS2_atl11_tide_attrs[ptx]['latitude']['units'] = "degrees_north"
        IS2_atl11_tide_attrs[ptx]['latitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['latitude']['long_name'] = "Latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['standard_name'] = "latitude"
        IS2_atl11_tide_attrs[ptx]['latitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['latitude']['description'] = (
            "Center latitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_min'] = -90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['valid_max'] = 90.0
        IS2_atl11_tide_attrs[ptx]['latitude']['coordinates'] = \
            "ref_pt delta_time longitude"
        #-- longitude
        IS2_atl11_tide[ptx]['longitude'] = IS2_atl11_mds[ptx][
            'longitude'].copy()
        IS2_atl11_fill[ptx]['longitude'] = IS2_atl11_attrs[ptx]['longitude'][
            '_FillValue']
        IS2_atl11_dims[ptx]['longitude'] = ['ref_pt']
        IS2_atl11_tide_attrs[ptx]['longitude'] = {}
        IS2_atl11_tide_attrs[ptx]['longitude']['units'] = "degrees_east"
        IS2_atl11_tide_attrs[ptx]['longitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl11_tide_attrs[ptx]['longitude']['long_name'] = "Longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['standard_name'] = "longitude"
        IS2_atl11_tide_attrs[ptx]['longitude']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['longitude']['description'] = (
            "Center longitude of "
            "selected segments")
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_min'] = -180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['valid_max'] = 180.0
        IS2_atl11_tide_attrs[ptx]['longitude']['coordinates'] = \
            "ref_pt delta_time latitude"
        #-- reference point
        IS2_atl11_tide[ptx]['ref_pt'] = IS2_atl11_mds[ptx]['ref_pt'].copy()
        IS2_atl11_fill[ptx]['ref_pt'] = None
        IS2_atl11_dims[ptx]['ref_pt'] = None
        IS2_atl11_tide_attrs[ptx]['ref_pt'] = {}
        IS2_atl11_tide_attrs[ptx]['ref_pt']['units'] = "1"
        IS2_atl11_tide_attrs[ptx]['ref_pt'][
            'contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['ref_pt'][
            'long_name'] = "Reference point number"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['source'] = "ATL06"
        IS2_atl11_tide_attrs[ptx]['ref_pt']['description'] = (
            "The reference point is the 7 digit segment_id "
            "number corresponding to the center of the ATL06 data used for each ATL11 point.  These are "
            "sequential, starting with 1 for the first segment after an ascending equatorial crossing node."
        )
        IS2_atl11_tide_attrs[ptx]['ref_pt']['coordinates'] = \
            "delta_time latitude longitude"

        #-- cycle statistics variables
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['Description'] = (
            "The cycle_stats subgroup "
            "contains summary information about segments for each reference point, including "
            "the uncorrected mean heights for reference surfaces, blowing snow and cloud "
            "indicators, and geolocation and height misfit statistics.")
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['data_rate'] = (
            "Data within this group "
            "are stored at the average segment rate.")
        #-- computed long-period equilibrium tide
        IS2_atl11_tide[ptx]['cycle_stats']['tide_equilibrium'] = tide_lpe
        IS2_atl11_fill[ptx]['cycle_stats'][
            'tide_equilibrium'] = tide_lpe.fill_value
        IS2_atl11_dims[ptx]['cycle_stats']['tide_equilibrium'] = [
            'ref_pt', 'cycle_number'
        ]
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium'] = {}
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium'][
            'units'] = "meters"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium'][
            'contentType'] = "referenceInformation"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['long_name'] = \
            "Long Period Equilibrium Tide"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium'][
            'description'] = (
                "Long-period "
                "equilibrium tidal elevation from the summation of fifteen tidal spectral lines"
            )
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['reference'] = \
            "https://doi.org/10.1111/j.1365-246X.1973.tb03420.x"
        IS2_atl11_tide_attrs[ptx]['cycle_stats']['tide_equilibrium']['coordinates'] = \
            "../ref_pt ../cycle_number ../delta_time ../latitude ../longitude"

    #-- output tidal HDF5 file
    args = (PRD, TRK, GRAN, SCYC, ECYC, RL, VERS, AUX)
    file_format = '{0}_LPET_{1}{2}_{3}{4}_{5}_{6}{7}.h5'
    #-- print file information
    print('\t{0}'.format(file_format.format(*args))) if VERBOSE else None
    HDF5_ATL11_tide_write(IS2_atl11_tide,
                          IS2_atl11_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(FILE),
                          FILL_VALUE=IS2_atl11_fill,
                          DIMENSIONS=IS2_atl11_dims,
                          FILENAME=os.path.join(DIRECTORY,
                                                file_format.format(*args)))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, file_format.format(*args)), MODE)
예제 #20
0
def compute_tide_corrections(x, y, delta_time, DIRECTORY=None, MODEL=None,
    EPSG=3031, EPOCH=(2000,1,1,0,0,0), TYPE='drift', TIME='UTC',
    METHOD='spline', EXTRAPOLATE=False, FILL_VALUE=np.nan):
    """
    Compute tides at points and times using tidal harmonics

    Arguments
    ---------
    x: x-coordinates in projection EPSG
    y: y-coordinates in projection EPSG
    delta_time: seconds since EPOCH

    Keyword arguments
    -----------------
    DIRECTORY: working data directory for tide models
    MODEL: Tide model to use in correction
    EPOCH: time period for calculating delta times
        default: J2000 (seconds since 2000-01-01T00:00:00)
    TYPE: input data type
        drift: drift buoys or satellite/airborne altimetry (time per data point)
        grid: spatial grids or images (single time per image)
    TIME: time type if need to compute leap seconds to convert to UTC
        GPS: leap seconds needed
        TAI: leap seconds needed (TAI = GPS + 19 seconds)
        UTC: no leap seconds needed
    EPSG: input coordinate system
        default: 3031 Polar Stereographic South, WGS84
    METHOD: interpolation method
        bilinear: quick bilinear interpolation
        spline: scipy bivariate spline interpolation
        linear, nearest: scipy regular grid interpolations
    FILL_VALUE: output invalid value (default NaN)

    Returns
    -------
    tide: tidal elevation at coordinates and time in meters
    """

    #-- select between tide models
    if (MODEL == 'CATS0201'):
        grid_file = os.path.join(DIRECTORY,'cats0201_tmd','grid_CATS')
        model_file = os.path.join(DIRECTORY,'cats0201_tmd','h0_CATS02_01')
        model_format = 'OTIS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'CATS2008'):
        grid_file = os.path.join(DIRECTORY,'CATS2008','grid_CATS2008')
        model_file = os.path.join(DIRECTORY,'CATS2008','hf.CATS2008.out')
        model_format = 'OTIS'
        model_EPSG = 'CATS2008'
        model_type = 'z'
    elif (MODEL == 'CATS2008_load'):
        grid_file = os.path.join(DIRECTORY,'CATS2008a_SPOTL_Load','grid_CATS2008a_opt')
        model_file = os.path.join(DIRECTORY,'CATS2008a_SPOTL_Load','h_CATS2008a_SPOTL_load')
        model_format = 'OTIS'
        model_EPSG = 'CATS2008'
        model_type = 'z'
    elif (MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(DIRECTORY,'TPXO9_atlas')
        grid_file = os.path.join(model_directory,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'netcdf'
        model_type = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(DIRECTORY,'TPXO9_atlas_v2')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v2.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v2.nc.gz','h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz','h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz','h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz','h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz','h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz','h_2n2_tpxo9_atlas_30_v2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'netcdf'
        model_type = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(DIRECTORY,'TPXO9_atlas_v3')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v3.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v3.nc.gz','h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz','h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz','h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz','h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz','h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz','h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz','h_mm_tpxo9_atlas_30_v3.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'netcdf'
        model_type = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'TPXO9-atlas-v4'):
        model_directory = os.path.join(DIRECTORY,'TPXO9_atlas_v4')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v4')
        model_files = ['h_q1_tpxo9_atlas_30_v4','h_o1_tpxo9_atlas_30_v4',
            'h_p1_tpxo9_atlas_30_v4','h_k1_tpxo9_atlas_30_v4',
            'h_n2_tpxo9_atlas_30_v4','h_m2_tpxo9_atlas_30_v4',
            'h_s2_tpxo9_atlas_30_v4','h_k2_tpxo9_atlas_30_v4',
            'h_m4_tpxo9_atlas_30_v4','h_ms4_tpxo9_atlas_30_v4',
            'h_mn4_tpxo9_atlas_30_v4','h_2n2_tpxo9_atlas_30_v4',
            'h_mf_tpxo9_atlas_30_v4','h_mm_tpxo9_atlas_30_v4']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'OTIS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'TPXO9.1'):
        grid_file = os.path.join(DIRECTORY,'TPXO9.1','DATA','grid_tpxo9')
        model_file = os.path.join(DIRECTORY,'TPXO9.1','DATA','h_tpxo9.v1')
        model_format = 'OTIS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'TPXO8-atlas'):
        grid_file = os.path.join(DIRECTORY,'tpxo8_atlas','grid_tpxo8atlas_30_v1')
        model_file = os.path.join(DIRECTORY,'tpxo8_atlas','hf.tpxo8_atlas_30_v1')
        model_format = 'ATLAS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'TPXO7.2'):
        grid_file = os.path.join(DIRECTORY,'TPXO7.2_tmd','grid_tpxo7.2')
        model_file = os.path.join(DIRECTORY,'TPXO7.2_tmd','h_tpxo7.2')
        model_format = 'OTIS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'TPXO7.2_load'):
        grid_file = os.path.join(DIRECTORY,'TPXO7.2_load','grid_tpxo6.2')
        model_file = os.path.join(DIRECTORY,'TPXO7.2_load','h_tpxo7.2_load')
        model_format = 'OTIS'
        model_EPSG = '4326'
        model_type = 'z'
    elif (MODEL == 'AODTM-5'):
        grid_file = os.path.join(DIRECTORY,'aodtm5_tmd','grid_Arc5km')
        model_file = os.path.join(DIRECTORY,'aodtm5_tmd','h0_Arc5km.oce')
        model_format = 'OTIS'
        model_EPSG = 'PSNorth'
        model_type = 'z'
    elif (MODEL == 'AOTIM-5'):
        grid_file = os.path.join(DIRECTORY,'aotim5_tmd','grid_Arc5km')
        model_file = os.path.join(DIRECTORY,'aotim5_tmd','h_Arc5km.oce')
        model_format = 'OTIS'
        model_EPSG = 'PSNorth'
        model_type = 'z'
    elif (MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(DIRECTORY,'Arc5km2018','grid_Arc5km2018')
        model_file = os.path.join(DIRECTORY,'Arc5km2018','h_Arc5km2018')
        model_format = 'OTIS'
        model_EPSG = 'PSNorth'
        model_type = 'z'
    elif (MODEL == 'GOT4.7'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (MODEL == 'GOT4.7_load'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'GOT4.8'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (MODEL == 'GOT4.8_load'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'GOT4.10'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (MODEL == 'GOT4.10_load'):
        model_directory = os.path.join(DIRECTORY,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (MODEL == 'FES2014'):
        model_directory = os.path.join(DIRECTORY,'fes2014','ocean_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6','m8',
            'mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2','n4',
            'nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
        GZIP = True
    elif (MODEL == 'FES2014_load'):
        model_directory = os.path.join(DIRECTORY,'fes2014','load_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        model_format = 'FES'
        model_type = 'z'
        SCALE = 1.0/100.0
        GZIP = True
    else:
        raise Exception("Unlisted tide model")

    #-- converting x,y from EPSG to latitude/longitude
    crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(EPSG))
    crs2 = pyproj.CRS.from_string("epsg:{0:d}".format(4326))
    transformer = pyproj.Transformer.from_crs(crs1, crs2, always_xy=True)
    lon,lat = transformer.transform(x.flatten(), y.flatten())

    #-- assert delta time is an array
    delta_time = np.atleast_1d(delta_time)
    #-- calculate leap seconds if specified
    if (TIME.upper() == 'GPS'):
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(0, epoch1=EPOCH,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time, epoch1=EPOCH,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    elif (TIME.upper() == 'TAI'):
        #-- TAI time is ahead of GPS time by 19 seconds
        GPS_Epoch_Time = pyTMD.time.convert_delta_time(-19.0, epoch1=EPOCH,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        GPS_Time = pyTMD.time.convert_delta_time(delta_time-19.0, epoch1=EPOCH,
            epoch2=(1980,1,6,0,0,0), scale=1.0)
        #-- calculate difference in leap seconds from start of epoch
        leap_seconds = pyTMD.time.count_leap_seconds(GPS_Time) - \
            pyTMD.time.count_leap_seconds(np.atleast_1d(GPS_Epoch_Time))
    else:
        leap_seconds = 0.0

    #-- convert time to days relative to Jan 1, 1992 (48622mjd)
    t = pyTMD.time.convert_delta_time(delta_time - leap_seconds, epoch1=EPOCH,
        epoch2=(1992,1,1,0,0,0), scale=(1.0/86400.0))
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.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,
            model_EPSG, TYPE=model_type, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            GRID=model_format)
        deltat = np.zeros_like(t)
    elif (model_format == 'netcdf'):
        amp,ph,D,c = extract_netcdf_constants(lon, lat, grid_file, model_file,
            TYPE=model_type, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            SCALE=SCALE, GZIP=GZIP)
        deltat = np.zeros_like(t)
    elif (model_format == 'GOT'):
        amp,ph,c = extract_GOT_constants(lon, lat, model_file, METHOD=METHOD,
            EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE, GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)
    elif (model_format == 'FES'):
        amp,ph = extract_FES_constants(lon, lat, model_file, TYPE=model_type,
            VERSION=MODEL, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE,
            SCALE=SCALE, GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, t)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    hc = amp*np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    if (TYPE.lower() == 'grid'):
        ny,nx = np.shape(x); nt = len(t)
        tide = np.ma.zeros((ny,nx,nt),fill_value=FILL_VALUE)
        tide.mask = np.zeros((ny,nx,nt),dtype=bool)
        for i in range(nt):
            TIDE = predict_tide(t[i], hc, c,
                DELTAT=deltat[i], CORRECTIONS=model_format)
            MINOR = infer_minor_corrections(t[i], hc, c,
                DELTAT=deltat[i], CORRECTIONS=model_format)
            #-- add major and minor components and reform grid
            tide[:,:,i] = np.reshape((TIDE+MINOR), (ny,nx))
            tide.mask[:,:,i] = np.reshape((TIDE.mask | MINOR.mask), (ny,nx))
    else:
        npts = len(t)
        tide = np.ma.zeros((npts), fill_value=FILL_VALUE)
        tide.mask = np.any(hc.mask,axis=1)
        tide.data[:] = predict_tide_drift(t, hc, c,
            DELTAT=deltat, CORRECTIONS=model_format)
        minor = infer_minor_corrections(t, hc, c,
            DELTAT=deltat, CORRECTIONS=model_format)
        tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.fill_value

    #-- return the tide correction
    return tide
예제 #21
0
def compute_tides_ICESat2(tide_dir, FILE, MODEL, VERBOSE=False, MODE=0o775):
    #-- 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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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/')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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'
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        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')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        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')
        variable = 'tide_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0

    #-- read data from FILE
    print('{0} -->'.format(os.path.basename(FILE))) if VERBOSE else None
    IS2_atl06_mds, IS2_atl06_attrs, IS2_atl06_beams = read_HDF5_ATL06(
        FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 file name
    rx = re.compile(
        '(processed_)?(ATL\d{2})_(\d{4})(\d{2})(\d{2})(\d{2})'
        '(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$')
    SUB, PRD, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX = rx.findall(
        FILE).pop()

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl06_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']

    #-- copy variables for outputting to HDF5 file
    IS2_atl06_tide = {}
    IS2_atl06_fill = {}
    IS2_atl06_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl06_tide['ancillary_data'] = {}
    IS2_atl06_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl06_tide['ancillary_data'][key] = IS2_atl06_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl06_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl06_attrs['ancillary_data'][key].items(
        ):
            IS2_atl06_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl06_beams):
        #-- output data dictionaries for beam
        IS2_atl06_tide[gtx] = dict(land_ice_segments={})
        IS2_atl06_fill[gtx] = dict(land_ice_segments={})
        IS2_atl06_tide_attrs[gtx] = dict(land_ice_segments={})

        #-- number of segments
        val = IS2_atl06_mds[gtx]['land_ice_segments']
        n_seg = len(val['segment_id'])
        #-- find valid segments for beam
        fv = IS2_atl06_attrs[gtx]['land_ice_segments']['h_li']['_FillValue']
        h_li = np.ma.array(val['h_li'],
                           fill_value=fv,
                           mask=(val['h_li'] == fv))
        ii, = np.nonzero(~h_li.mask)

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + val['delta_time'][ii]
        tide_time = (gps_seconds -
                     count_leap_seconds(gps_seconds)) / 86400.0 - 4378.0
        #-- read tidal constants and interpolate to grid points
        if model_format in ('OTIS', 'ATLAS'):
            amp, ph, D, c = extract_tidal_constants(val['longitude'][ii],
                                                    val['latitude'][ii],
                                                    grid_file,
                                                    model_file,
                                                    EPSG,
                                                    type,
                                                    METHOD='spline',
                                                    GRID=model_format)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'netcdf'):
            amp, ph, D, c = extract_netcdf_constants(val['longitude'][ii],
                                                     val['latitude'][ii],
                                                     model_directory,
                                                     grid_file,
                                                     model_files,
                                                     type,
                                                     METHOD='spline',
                                                     SCALE=SCALE)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'GOT'):
            amp, ph = extract_GOT_constants(val['longitude'][ii],
                                            val['latitude'][ii],
                                            model_directory,
                                            model_files,
                                            METHOD='spline',
                                            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, tide_time + 48622.0)

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

        #-- predict tidal elevations at time and infer minor corrections
        tide = np.ma.empty((n_seg), fill_value=fv)
        tide.mask = np.copy(h_li.mask)
        tide.data[ii] = predict_tide_drift(tide_time,
                                           hc,
                                           c,
                                           DELTAT=deltat,
                                           CORRECTIONS=model_format)
        tide.data[ii] += infer_minor_corrections(tide_time,
                                                 hc,
                                                 c,
                                                 DELTAT=deltat,
                                                 CORRECTIONS=model_format)
        #-- replace masked and nan values with fill value
        invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
        tide.data[invalid] = tide.fill_value
        tide.mask[invalid] = True

        #-- group attributes for beam
        IS2_atl06_tide_attrs[gtx]['Description'] = IS2_atl06_attrs[gtx][
            'Description']
        IS2_atl06_tide_attrs[gtx]['atlas_pce'] = IS2_atl06_attrs[gtx][
            'atlas_pce']
        IS2_atl06_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl06_attrs[gtx][
            'atlas_beam_type']
        IS2_atl06_tide_attrs[gtx]['groundtrack_id'] = IS2_atl06_attrs[gtx][
            'groundtrack_id']
        IS2_atl06_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl06_attrs[gtx][
            'atmosphere_profile']
        IS2_atl06_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl06_attrs[gtx][
            'atlas_spot_number']
        IS2_atl06_tide_attrs[gtx]['sc_orientation'] = IS2_atl06_attrs[gtx][
            'sc_orientation']
        #-- group attributes for land_ice_segments
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['Description'] = (
            "The land_ice_segments group "
            "contains the primary set of derived products. This includes geolocation, height, and "
            "standard error and quality measures for each segment. This group is sparse, meaning "
            "that parameters are provided only for pairs of segments for which at least one beam "
            "has a valid surface-height measurement.")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['data_rate'] = (
            "Data within this group are "
            "sparse.  Data values are provided only for those ICESat-2 20m segments where at "
            "least one beam has a valid land ice height measurement.")

        #-- geolocation, time and segment ID
        #-- delta time
        delta_time = np.ma.array(val['delta_time'],
                                 fill_value=fv,
                                 mask=(val['delta_time'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['delta_time'] = delta_time
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'delta_time'] = delta_time.fill_value
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'units'] = "seconds since 2018-01-01"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'long_name'] = "Elapsed GPS seconds"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'standard_name'] = "time"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'calendar'] = "standard"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time'][
            'description'] = (
                "Number of GPS "
                "seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch offset "
                "is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS seconds "
                "between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP epoch. By "
                "adding the offset contained within atlas_sdp_gps_epoch to delta time parameters, the "
                "time in gps_seconds relative to the GPS epoch can be computed."
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['delta_time']['coordinates'] = \
         "segment_id latitude longitude"
        #-- latitude
        latitude = np.ma.array(val['latitude'],
                               fill_value=fv,
                               mask=(val['latitude'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['latitude'] = latitude
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'latitude'] = latitude.fill_value
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'units'] = "degrees_north"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'long_name'] = "Latitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'standard_name'] = "latitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'description'] = ("Latitude of "
                              "segment center")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'valid_min'] = -90.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude'][
            'valid_max'] = 90.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['latitude']['coordinates'] = \
         "segment_id delta_time longitude"
        #-- longitude
        longitude = np.ma.array(val['longitude'],
                                fill_value=fv,
                                mask=(val['longitude'] == fv))
        IS2_atl06_tide[gtx]['land_ice_segments']['longitude'] = longitude
        IS2_atl06_fill[gtx]['land_ice_segments'][
            'longitude'] = longitude.fill_value
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'units'] = "degrees_east"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'contentType'] = "physicalMeasurement"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'long_name'] = "Longitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'standard_name'] = "longitude"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'description'] = ("Longitude of "
                              "segment center")
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'valid_min'] = -180.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude'][
            'valid_max'] = 180.0
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['longitude']['coordinates'] = \
         "segment_id delta_time latitude"
        #-- segment ID
        IS2_atl06_tide[gtx]['land_ice_segments']['segment_id'] = val[
            'segment_id']
        IS2_atl06_fill[gtx]['land_ice_segments']['segment_id'] = None
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'units'] = "1"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'contentType'] = "referenceInformation"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'long_name'] = "Along-track segment ID number"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id'][
            'description'] = (
                "A 7 digit number "
                "identifying the along-track geolocation segment number.  These are sequential, starting with "
                "1 for the first segment after an ascending equatorial crossing node. Equal to the segment_id for "
                "the second of the two 20m ATL03 segments included in the 40m ATL06 segment"
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['segment_id']['coordinates'] = \
         "delta_time latitude longitude"

        #-- geophysical variables
        IS2_atl06_tide[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_fill[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'Description'] = (
                "The geophysical group "
                "contains parameters used to correct segment heights for geophysical effects, parameters "
                "related to solar background and parameters indicative of the presence or absence of clouds."
            )
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            'data_rate'] = (
                "Data within this group "
                "are stored at the land_ice_segments segment rate.")
        #-- computed tide
        IS2_atl06_tide[gtx]['land_ice_segments']['geophysical'][
            variable] = tide
        IS2_atl06_fill[gtx]['land_ice_segments']['geophysical'][
            variable] = tide.fill_value
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable] = {}
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['units'] = "meters"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['contentType'] = "referenceInformation"
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['long_name'] = long_name
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['description'] = description
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['source'] = MODEL
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][
            variable]['reference'] = reference
        IS2_atl06_tide_attrs[gtx]['land_ice_segments']['geophysical'][variable]['coordinates'] = \
         "../segment_id ../delta_time ../latitude ../longitude"

    #-- output tidal HDF5 file
    args = (PRD, MODEL, YY, MM, DD, HH, MN, SS, TRK, CYCL, GRAN, RL, VERS, AUX)
    file_format = '{0}_{1}_TIDES_{2}{3}{4}{5}{6}{7}_{8}{9}{10}_{11}_{12}{13}.h5'
    #-- print file information
    print('\t{0}'.format(file_format.format(*args))) if VERBOSE else None
    HDF5_ATL06_tide_write(IS2_atl06_tide,
                          IS2_atl06_tide_attrs,
                          CLOBBER='Y',
                          INPUT=os.path.basename(FILE),
                          FILL_VALUE=IS2_atl06_fill,
                          FILENAME=os.path.join(DIRECTORY,
                                                file_format.format(*args)))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, file_format.format(*args)), MODE)
예제 #22
0
def compute_tidal_elevations(tide_dir, input_file, output_file,
    TIDE_MODEL=None, FORMAT='csv', VARIABLES=['time','lat','lon','data'],
    TIME_UNITS='days since 1858-11-17T00:00:00', PROJECTION='4326',
    METHOD='spline', VERBOSE=False, MODE=0o775):

    #-- select between tide models
    if (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir,'CATS2008','grid_CATS2008')
        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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v2')
        grid_file = 'grid_tpxo9_atlas_30_v2.nc.gz'
        model_files = ['h_q1_tpxo9_atlas_30_v2.nc.gz','h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz','h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz','h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz','h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz','h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz','h_2n2_tpxo9_atlas_30_v2.nc.gz']
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
    elif (TIDE_MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v3')
        grid_file = 'grid_tpxo9_atlas_30_v3.nc.gz'
        model_files = ['h_q1_tpxo9_atlas_30_v3.nc.gz','h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz','h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz','h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz','h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz','h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz','h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz','h_mm_tpxo9_atlas_30_v3.nc.gz']
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'tide_ocean'
        long_name = "Ocean_Tide"
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir,'Arc5km2018','grid_Arc5km2018')
        model_file = os.path.join(tide_dir,'Arc5km2018','h_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aotim-5/')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
    elif (TIDE_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')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
    elif (TIDE_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')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
    elif (TIDE_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')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
    elif (TIDE_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')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'GOT'
        SCALE = 1.0/100.0
    elif (TIDE_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')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'GOT'
        SCALE = 1.0/1000.0
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = os.path.join(tide_dir,'fes2014','ocean_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/data/products/'
            'auxiliary-products/global-tide-fes.html')
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
    elif (TIDE_MODEL == 'FES2014_load'):
        model_directory = os.path.join(tide_dir,'fes2014','load_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/data/products/'
            'auxiliary-products/global-tide-fes.html')
        output_variable = 'tide_load'
        variable_long_name = 'Load_Tide'
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0

    #-- 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'
    #-- tides
    attrib[output_variable] = {}
    attrib[output_variable]['description'] = ('tidal_elevation_from_harmonic_'
        'constants')
    attrib[output_variable]['model'] = TIDE_MODEL
    attrib[output_variable]['units'] = 'meters'
    attrib[output_variable]['long_name'] = variable_long_name
    attrib[output_variable]['_FillValue'] = fill_value
    #-- time
    attrib['time'] = {}
    attrib['time']['long_name'] = 'Time'
    attrib['time']['units'] = 'days since 1992-01-01T00:00:00'
    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 time from units to days since 1992-01-01T00:00:00
    tide_time = pyTMD.time.convert_delta_time(to_secs*dinput['time'].flatten(),
        epoch1=epoch1, epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
    n_time = len(tide_time)

    #-- 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=TYPE, METHOD=METHOD)
        deltat = np.zeros((n_time))
    elif (model_format == 'netcdf'):
        amp,ph,D,c = extract_netcdf_constants(lon, lat, model_directory,
            grid_file, model_files, TYPE=TYPE, METHOD=METHOD, SCALE=SCALE)
        deltat = np.zeros((n_time))
    elif (model_format == 'GOT'):
        amp,ph = extract_GOT_constants(lon, lat, model_directory, model_files,
            METHOD=METHOD, SCALE=SCALE)
        #-- convert times from modified julian days to days since 1992-01-01
        #-- interpolate delta times from calendar dates to tide time
        delta_file = get_data_path(['data','merged_deltat.data'])
        deltat = calc_delta_time(delta_file,tide_time)
    elif (model_format == 'FES'):
        amp,ph = extract_FES_constants(lon, lat, model_directory, model_files,
            TYPE=TYPE, VERSION=TIDE_MODEL, METHOD=METHOD, SCALE=SCALE)
        #-- convert times from modified julian days to days since 1992-01-01
        #-- interpolate delta times from calendar dates to tide time
        delta_file = get_data_path(['data','merged_deltat.data'])
        deltat = calc_delta_time(delta_file,tide_time)

    #-- calculate complex phase in radians for Euler's
    cph = -1j*ph*np.pi/180.0
    #-- calculate constituent oscillation
    hc = amp*np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    tide = np.ma.zeros((n_time), fill_value=fill_value)
    tide.mask = np.any(hc.mask,axis=1)
    tide.data[:] = predict_tide_drift(tide_time, hc, c,
        DELTAT=deltat, CORRECTIONS=model_format)
    minor = infer_minor_corrections(tide_time, hc, c,
        DELTAT=deltat, CORRECTIONS=model_format)
    tide.data[:] += minor.data[:]
    #-- replace invalid values with fill value
    tide.data[tide.mask] = tide.fill_value

    #-- output to file
    output = {'time':tide_time,'lon':lon,'lat':lat,output_variable:tide}
    if (FORMAT == 'csv'):
        pyTMD.spatial.to_ascii(output, attrib, output_file, delimiter=',',
            columns=['time','lat','lon',output_variable], 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)
예제 #23
0
def compute_tides_ICESat2(tide_dir,
                          INPUT_FILE,
                          TIDE_MODEL=None,
                          ATLAS_FORMAT=None,
                          GZIP=True,
                          DEFINITION_FILE=None,
                          METHOD='spline',
                          EXTRAPOLATE=False,
                          CUTOFF=None,
                          VERBOSE=False,
                          MODE=0o775):

    #-- create logger for verbosity level
    loglevel = logging.INFO if VERBOSE else logging.CRITICAL
    logger = pyTMD.utilities.build_logger('pytmd', level=loglevel)

    #-- get parameters for tide model
    if DEFINITION_FILE is not None:
        model = pyTMD.model(tide_dir).from_file(DEFINITION_FILE)
    else:
        model = pyTMD.model(tide_dir, format=ATLAS_FORMAT,
                            compressed=GZIP).elevation(TIDE_MODEL)

    #-- read data from input file
    logger.info('{0} -->'.format(INPUT_FILE))
    IS2_atl10_mds, IS2_atl10_attrs, IS2_atl10_beams = read_HDF5_ATL10(
        INPUT_FILE, ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(INPUT_FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 sea ice file name
    rx = re.compile(
        r'(processed_)?(ATL\d{2})-(\d{2})_(\d{4})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$'
    )
    try:
        SUB, PRD, HEM, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN, RL, VERS, AUX = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        args = (fileBasename, model.name, fileExtension)
        OUTPUT_FILE = '{0}_{1}_TIDES{2}'.format(*args)
    else:
        #-- output tide HDF5 file for ASAS/NSIDC granules
        args = (PRD, HEM, model.name, YY, MM, DD, HH, MN, SS, TRK, CYCL, SN,
                RL, VERS, AUX)
        ff = '{0}-{1}_{2}_TIDES_{3}{4}{5}{6}{7}{8}_{9}{10}{11}_{12}_{13}{14}.h5'
        OUTPUT_FILE = ff.format(*args)

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl10_mds['ancillary_data'][
        'atlas_sdp_gps_epoch']
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data', 'merged_deltat.data'])

    #-- copy variables for outputting to HDF5 file
    IS2_atl10_tide = {}
    IS2_atl10_fill = {}
    IS2_atl10_dims = {}
    IS2_atl10_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl10_tide['ancillary_data'] = {}
    IS2_atl10_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl10_tide['ancillary_data'][key] = IS2_atl10_mds[
            'ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl10_tide_attrs['ancillary_data'][key] = {}
        for att_name, att_val in IS2_atl10_attrs['ancillary_data'][key].items(
        ):
            IS2_atl10_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl10_beams):
        #-- output data dictionaries for beam
        IS2_atl10_tide[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_fill[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_dims[gtx] = dict(freeboard_beam_segment={}, leads={})
        IS2_atl10_tide_attrs[gtx] = dict(freeboard_beam_segment={}, leads={})

        #-- group attributes for beam
        IS2_atl10_tide_attrs[gtx]['Description'] = IS2_atl10_attrs[gtx][
            'Description']
        IS2_atl10_tide_attrs[gtx]['atlas_pce'] = IS2_atl10_attrs[gtx][
            'atlas_pce']
        IS2_atl10_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl10_attrs[gtx][
            'atlas_beam_type']
        IS2_atl10_tide_attrs[gtx]['groundtrack_id'] = IS2_atl10_attrs[gtx][
            'groundtrack_id']
        IS2_atl10_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl10_attrs[gtx][
            'atmosphere_profile']
        IS2_atl10_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl10_attrs[gtx][
            'atlas_spot_number']
        IS2_atl10_tide_attrs[gtx]['sc_orientation'] = IS2_atl10_attrs[gtx][
            'sc_orientation']

        #-- group attributes for freeboard_beam_segment
        IS2_atl10_tide_attrs[gtx]['freeboard_beam_segment']['Description'] = (
            "Contains freeboard "
            "estimate and associated height segment parameters for only the sea ice segments by beam."
        )
        IS2_atl10_tide_attrs[gtx]['freeboard_beam_segment']['data_rate'] = (
            "Data within this "
            "group are stored at the freeboard swath segment rate.")
        #-- group attributes for leads
        IS2_atl10_tide_attrs[gtx]['leads']['Description'] = (
            "Contains parameters relating "
            "to the freeboard values.")
        IS2_atl10_tide_attrs[gtx]['leads']['data_rate'] = (
            "Data within this "
            "group are stored at the lead index rate.")

        #-- for each ATL10 group
        for group in ['freeboard_beam_segment', 'leads']:
            #-- number of segments
            val = IS2_atl10_mds[gtx][group]
            n_seg = len(val['delta_time'])

            #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
            gps_seconds = atlas_sdp_gps_epoch + val['delta_time']
            leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
            tide_time = pyTMD.time.convert_delta_time(
                gps_seconds - leap_seconds,
                epoch1=(1980, 1, 6, 0, 0, 0),
                epoch2=(1992, 1, 1, 0, 0, 0),
                scale=1.0 / 86400.0)
            #-- read tidal constants and interpolate to grid points
            if model.format in ('OTIS', 'ATLAS'):
                amp, ph, D, c = extract_tidal_constants(
                    val['longitude'],
                    val['latitude'],
                    model.grid_file,
                    model.model_file,
                    model.projection,
                    TYPE=model.type,
                    METHOD=METHOD,
                    EXTRAPOLATE=EXTRAPOLATE,
                    CUTOFF=CUTOFF,
                    GRID=model.format)
                deltat = np.zeros_like(tide_time)
            elif (model.format == 'netcdf'):
                amp, ph, D, c = extract_netcdf_constants(
                    val['longitude'],
                    val['latitude'],
                    model.grid_file,
                    model.model_file,
                    TYPE=model.type,
                    METHOD=METHOD,
                    EXTRAPOLATE=EXTRAPOLATE,
                    SCALE=model.scale,
                    CUTOFF=CUTOFF,
                    GZIP=model.compressed)
                deltat = np.zeros_like(tide_time)
            elif (model.format == 'GOT'):
                amp, ph, c = extract_GOT_constants(val['longitude'],
                                                   val['latitude'],
                                                   model.model_file,
                                                   METHOD=METHOD,
                                                   EXTRAPOLATE=EXTRAPOLATE,
                                                   CUTOFF=CUTOFF,
                                                   SCALE=model.scale,
                                                   GZIP=model.compressed)
                #-- interpolate delta times from calendar dates to tide time
                deltat = calc_delta_time(delta_file, tide_time)
            elif (model.format == 'FES'):
                amp, ph = extract_FES_constants(val['longitude'],
                                                val['latitude'],
                                                model.model_file,
                                                TYPE=model.type,
                                                VERSION=model.version,
                                                METHOD=METHOD,
                                                EXTRAPOLATE=EXTRAPOLATE,
                                                CUTOFF=CUTOFF,
                                                SCALE=model.scale,
                                                GZIP=model.compressed)
                #-- available model constituents
                c = model.constituents
                #-- interpolate delta times from calendar dates to tide time
                deltat = calc_delta_time(delta_file, tide_time)

            #-- calculate complex phase in radians for Euler's
            cph = -1j * ph * np.pi / 180.0
            #-- calculate constituent oscillation
            hc = amp * np.exp(cph)

            #-- predict tidal elevations at time and infer minor corrections
            tide = np.ma.empty((n_seg))
            tide.mask = np.any(hc.mask, axis=1)
            tide.data[:] = predict_tide_drift(tide_time,
                                              hc,
                                              c,
                                              DELTAT=deltat,
                                              CORRECTIONS=model.format)
            minor = infer_minor_corrections(tide_time,
                                            hc,
                                            c,
                                            DELTAT=deltat,
                                            CORRECTIONS=model.format)
            tide.data[:] += minor.data[:]
            #-- replace masked and nan values with fill value
            invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
            tide.data[invalid] = tide.fill_value
            tide.mask[invalid] = True

            #-- geolocation, time and segment ID
            #-- delta time
            IS2_atl10_tide[gtx][group]['delta_time'] = val['delta_time'].copy()
            IS2_atl10_fill[gtx][group]['delta_time'] = None
            IS2_atl10_dims[gtx][group]['delta_time'] = None
            IS2_atl10_tide_attrs[gtx][group]['delta_time'] = {}
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'units'] = "seconds since 2018-01-01"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'long_name'] = "Elapsed GPS seconds"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'standard_name'] = "time"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'source'] = "telemetry"
            IS2_atl10_tide_attrs[gtx][group]['delta_time'][
                'calendar'] = "standard"
            IS2_atl10_tide_attrs[gtx][group]['delta_time']['description'] = (
                "Number of "
                "GPS seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch "
                "offset is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS "
                "seconds between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP "
                "epoch. By adding the offset contained within atlas_sdp_gps_epoch to delta time "
                "parameters, the time in gps_seconds relative to the GPS epoch can be computed."
            )
            IS2_atl10_tide_attrs[gtx][group]['delta_time']['coordinates'] = \
                "latitude longitude"
            #-- latitude
            IS2_atl10_tide[gtx][group]['latitude'] = val['latitude'].copy()
            IS2_atl10_fill[gtx][group]['latitude'] = None
            IS2_atl10_dims[gtx][group]['latitude'] = ['delta_time']
            IS2_atl10_tide_attrs[gtx][group]['latitude'] = {}
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'units'] = "degrees_north"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'contentType'] = "physicalMeasurement"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'long_name'] = "Latitude"
            IS2_atl10_tide_attrs[gtx][group]['latitude'][
                'standard_name'] = "latitude"
            IS2_atl10_tide_attrs[gtx][group]['latitude']['description'] = (
                "Latitude of "
                "segment center")
            IS2_atl10_tide_attrs[gtx][group]['latitude']['valid_min'] = -90.0
            IS2_atl10_tide_attrs[gtx][group]['latitude']['valid_max'] = 90.0
            IS2_atl10_tide_attrs[gtx][group]['latitude']['coordinates'] = \
                "delta_time longitude"
            #-- longitude
            IS2_atl10_tide[gtx][group]['longitude'] = val['longitude'].copy()
            IS2_atl10_fill[gtx][group]['longitude'] = None
            IS2_atl10_dims[gtx][group]['longitude'] = ['delta_time']
            IS2_atl10_tide_attrs[gtx][group]['longitude'] = {}
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'units'] = "degrees_east"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'contentType'] = "physicalMeasurement"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'long_name'] = "Longitude"
            IS2_atl10_tide_attrs[gtx][group]['longitude'][
                'standard_name'] = "longitude"
            IS2_atl10_tide_attrs[gtx][group]['longitude']['description'] = (
                "Longitude of "
                "segment center")
            IS2_atl10_tide_attrs[gtx][group]['longitude']['valid_min'] = -180.0
            IS2_atl10_tide_attrs[gtx][group]['longitude']['valid_max'] = 180.0
            IS2_atl10_tide_attrs[gtx][group]['longitude']['coordinates'] = \
                "delta_time latitude"

            #-- geophysical variables
            IS2_atl10_tide[gtx][group]['geophysical'] = {}
            IS2_atl10_fill[gtx][group]['geophysical'] = {}
            IS2_atl10_dims[gtx][group]['geophysical'] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical'] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['Description'] = (
                "Contains geophysical "
                "parameters and corrections used to correct photon heights for geophysical effects, "
                "such as tides.")
            IS2_atl10_tide_attrs[gtx][group]['geophysical']['data_rate'] = (
                "Data within this group "
                "are stored at the variable segment rate.")

            #-- computed tide
            IS2_atl10_tide[gtx][group]['geophysical'][
                model.atl10] = tide.copy()
            IS2_atl10_fill[gtx][group]['geophysical'][
                model.atl10] = tide.fill_value
            IS2_atl10_dims[gtx][group]['geophysical'][model.atl10] = [
                'delta_time'
            ]
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][model.atl10] = {}
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                model.atl10]['units'] = "meters"
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][model.atl10]['contentType'] = \
                "referenceInformation"
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                model.atl10]['long_name'] = model.long_name
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                model.atl10]['description'] = model.description
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                model.atl10]['source'] = model.name
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][
                model.atl10]['reference'] = model.reference
            IS2_atl10_tide_attrs[gtx][group]['geophysical'][model.atl10]['coordinates'] = \
                "../delta_time ../latitude ../longitude"

    #-- print file information
    logger.info('\t{0}'.format(OUTPUT_FILE))
    HDF5_ATL10_tide_write(IS2_atl10_tide,
                          IS2_atl10_tide_attrs,
                          CLOBBER=True,
                          INPUT=os.path.basename(INPUT_FILE),
                          FILL_VALUE=IS2_atl10_fill,
                          DIMENSIONS=IS2_atl10_dims,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
def compute_tides_ICESat2(tide_dir, FILE, TIDE_MODEL=None, METHOD='spline',
    EXTRAPOLATE=False, VERBOSE=False, MODE=0o775):
    #-- select between tide models
    if (TIDE_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'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir,'CATS2008','grid_CATS2008')
        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/')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas')
        grid_file = os.path.join(model_directory,'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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v2')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v2.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v2.nc.gz','h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz','h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz','h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz','h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz','h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz','h_2n2_tpxo9_atlas_30_v2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v3')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v3.nc.gz')
        model_files = ['h_q1_tpxo9_atlas_30_v3.nc.gz','h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz','h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz','h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz','h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz','h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz','h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz','h_mm_tpxo9_atlas_30_v3.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v4'):
        model_directory = os.path.join(tide_dir,'TPXO9_atlas_v4')
        grid_file = os.path.join(model_directory,'grid_tpxo9_atlas_30_v4')
        model_files = ['h_q1_tpxo9_atlas_30_v4','h_o1_tpxo9_atlas_30_v4',
            'h_p1_tpxo9_atlas_30_v4','h_k1_tpxo9_atlas_30_v4',
            'h_n2_tpxo9_atlas_30_v4','h_m2_tpxo9_atlas_30_v4',
            'h_s2_tpxo9_atlas_30_v4','h_k2_tpxo9_atlas_30_v4',
            'h_m4_tpxo9_atlas_30_v4','h_ms4_tpxo9_atlas_30_v4',
            'h_mn4_tpxo9_atlas_30_v4','h_2n2_tpxo9_atlas_30_v4',
            'h_mf_tpxo9_atlas_30_v4','h_mm_tpxo9_atlas_30_v4']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir,'Arc5km2018','grid_Arc5km2018')
        model_file = os.path.join(tide_dir,'Arc5km2018','h_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
            'list-of-polar-tide-models/aotim-5/')
        variable = 'tide_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_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']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
            'MiscPubs/19990089548_1999150788.pdf')
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0/1000.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = os.path.join(tide_dir,'fes2014','ocean_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
            'auxiliary-products/global-tide-fes.html')
        variable = 'height_segment_ocean'
        long_name = "Ocean Tide"
        description = ("Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014_load'):
        model_directory = os.path.join(tide_dir,'fes2014','load_tide')
        model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
            'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
            'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
            'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
            'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
            'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
            'ssa.nc.gz','t2.nc.gz']
        model_file = [os.path.join(model_directory,m) for m in model_files]
        c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
            'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
            'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
            'auxiliary-products/global-tide-fes.html')
        variable = 'height_segment_load'
        long_name = "Load Tide"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0/100.0
        GZIP = True

    #-- read data from FILE
    print('{0} -->'.format(os.path.basename(FILE))) if VERBOSE else None
    IS2_atl07_mds,IS2_atl07_attrs,IS2_atl07_beams = read_HDF5_ATL07(FILE,
        ATTRIBUTES=True)
    DIRECTORY = os.path.dirname(FILE)
    #-- extract parameters from ICESat-2 ATLAS HDF5 sea ice file name
    rx = re.compile(r'(processed_)?(ATL\d{2})-(\d{2})_(\d{4})(\d{2})(\d{2})'
        r'(\d{2})(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})_(\d{3})_(\d{2})(.*?).h5$')
    SUB,PRD,HEM,YY,MM,DD,HH,MN,SS,TRK,CYCL,SN,RL,VERS,AUX=rx.findall(FILE).pop()

    #-- number of GPS seconds between the GPS epoch
    #-- and ATLAS Standard Data Product (SDP) epoch
    atlas_sdp_gps_epoch = IS2_atl07_mds['ancillary_data']['atlas_sdp_gps_epoch']
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])

    #-- copy variables for outputting to HDF5 file
    IS2_atl07_tide = {}
    IS2_atl07_fill = {}
    IS2_atl07_dims = {}
    IS2_atl07_tide_attrs = {}
    #-- 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)
    #-- Add this value to delta time parameters to compute full gps_seconds
    IS2_atl07_tide['ancillary_data'] = {}
    IS2_atl07_tide_attrs['ancillary_data'] = {}
    for key in ['atlas_sdp_gps_epoch']:
        #-- get each HDF5 variable
        IS2_atl07_tide['ancillary_data'][key] = IS2_atl07_mds['ancillary_data'][key]
        #-- Getting attributes of group and included variables
        IS2_atl07_tide_attrs['ancillary_data'][key] = {}
        for att_name,att_val in IS2_atl07_attrs['ancillary_data'][key].items():
            IS2_atl07_tide_attrs['ancillary_data'][key][att_name] = att_val

    #-- for each input beam within the file
    for gtx in sorted(IS2_atl07_beams):
        #-- output data dictionaries for beam
        IS2_atl07_tide[gtx] = dict(sea_ice_segments={})
        IS2_atl07_fill[gtx] = dict(sea_ice_segments={})
        IS2_atl07_dims[gtx] = dict(sea_ice_segments={})
        IS2_atl07_tide_attrs[gtx] = dict(sea_ice_segments={})

        #-- number of segments
        val = IS2_atl07_mds[gtx]['sea_ice_segments']
        n_seg = len(val['height_segment_id'])

        #-- convert time from ATLAS SDP to days relative to Jan 1, 1992
        gps_seconds = atlas_sdp_gps_epoch + val['delta_time']
        leap_seconds = pyTMD.time.count_leap_seconds(gps_seconds)
        tide_time = pyTMD.time.convert_delta_time(gps_seconds-leap_seconds,
            epoch1=(1980,1,6,0,0,0), epoch2=(1992,1,1,0,0,0), scale=1.0/86400.0)
        #-- read tidal constants and interpolate to grid points
        if model_format in ('OTIS','ATLAS'):
            amp,ph,D,c = extract_tidal_constants(val['longitude'],
                val['latitude'], grid_file, model_file, EPSG, TYPE=TYPE,
                METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, GRID=model_format)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'netcdf'):
            amp,ph,D,c = extract_netcdf_constants(val['longitude'],
                val['latitude'], grid_file, model_file, TYPE=TYPE, METHOD=METHOD,
                EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE, GZIP=GZIP)
            deltat = np.zeros_like(tide_time)
        elif (model_format == 'GOT'):
            amp,ph,c = extract_GOT_constants(val['longitude'], val['latitude'],
                model_file, METHOD=METHOD, EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE,
                GZIP=GZIP)
            #-- interpolate delta times from calendar dates to tide time
            deltat = calc_delta_time(delta_file, tide_time)
        elif (model_format == 'FES'):
            amp,ph = extract_FES_constants(val['longitude'], val['latitude'],
                model_file, TYPE=TYPE, VERSION=TIDE_MODEL, METHOD=METHOD,
                EXTRAPOLATE=EXTRAPOLATE, SCALE=SCALE, GZIP=GZIP)
            #-- interpolate delta times from calendar dates to tide time
            deltat = calc_delta_time(delta_file, tide_time)

        #-- calculate complex phase in radians for Euler's
        cph = -1j*ph*np.pi/180.0
        #-- calculate constituent oscillation
        hc = amp*np.exp(cph)

        #-- predict tidal elevations at time and infer minor corrections
        tide = np.ma.empty((n_seg))
        tide.mask = np.any(hc.mask,axis=1)
        tide.data[:] = predict_tide_drift(tide_time, hc, c,
            DELTAT=deltat, CORRECTIONS=model_format)
        minor = infer_minor_corrections(tide_time, hc, c,
            DELTAT=deltat, CORRECTIONS=model_format)
        tide.data[:] += minor.data[:]
        #-- replace masked and nan values with fill value
        invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
        tide.data[invalid] = tide.fill_value
        tide.mask[invalid] = True

        #-- group attributes for beam
        IS2_atl07_tide_attrs[gtx]['Description'] = IS2_atl07_attrs[gtx]['Description']
        IS2_atl07_tide_attrs[gtx]['atlas_pce'] = IS2_atl07_attrs[gtx]['atlas_pce']
        IS2_atl07_tide_attrs[gtx]['atlas_beam_type'] = IS2_atl07_attrs[gtx]['atlas_beam_type']
        IS2_atl07_tide_attrs[gtx]['groundtrack_id'] = IS2_atl07_attrs[gtx]['groundtrack_id']
        IS2_atl07_tide_attrs[gtx]['atmosphere_profile'] = IS2_atl07_attrs[gtx]['atmosphere_profile']
        IS2_atl07_tide_attrs[gtx]['atlas_spot_number'] = IS2_atl07_attrs[gtx]['atlas_spot_number']
        IS2_atl07_tide_attrs[gtx]['sc_orientation'] = IS2_atl07_attrs[gtx]['sc_orientation']
        #-- group attributes for sea_ice_segments
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['Description'] = ("Top group for sea "
            "ice segments as computed by the ATBD algorithm.")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['data_rate'] = ("Data within this "
            "group are stored at the variable segment rate.")

        #-- geolocation, time and segment ID
        #-- delta time
        IS2_atl07_tide[gtx]['sea_ice_segments']['delta_time'] = val['delta_time'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['delta_time'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['delta_time'] = None
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['units'] = "seconds since 2018-01-01"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['long_name'] = "Elapsed GPS seconds"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['standard_name'] = "time"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['source'] = "telemetry"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['calendar'] = "standard"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['description'] = ("Number of "
            "GPS seconds since the ATLAS SDP epoch. The ATLAS Standard Data Products (SDP) epoch "
            "offset is defined within /ancillary_data/atlas_sdp_gps_epoch as the number of GPS "
            "seconds between the GPS epoch (1980-01-06T00:00:00.000000Z UTC) and the ATLAS SDP "
            "epoch. By adding the offset contained within atlas_sdp_gps_epoch to delta time "
            "parameters, the time in gps_seconds relative to the GPS epoch can be computed.")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['delta_time']['coordinates'] = \
            "height_segment_id latitude longitude"
        #-- latitude
        IS2_atl07_tide[gtx]['sea_ice_segments']['latitude'] = val['latitude'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['latitude'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['latitude'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['units'] = "degrees_north"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['contentType'] = "physicalMeasurement"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['long_name'] = "Latitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['standard_name'] = "latitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['description'] = ("Latitude of "
            "segment center")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['valid_min'] = -90.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['valid_max'] = 90.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['latitude']['coordinates'] = \
            "height_segment_id delta_time longitude"
        #-- longitude
        IS2_atl07_tide[gtx]['sea_ice_segments']['longitude'] = val['longitude'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['longitude'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['longitude'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['units'] = "degrees_east"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['contentType'] = "physicalMeasurement"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['long_name'] = "Longitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['standard_name'] = "longitude"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['description'] = ("Longitude of "
            "segment center")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['valid_min'] = -180.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['valid_max'] = 180.0
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['longitude']['coordinates'] = \
            "height_segment_id delta_time latitude"
        #-- segment ID
        IS2_atl07_tide[gtx]['sea_ice_segments']['height_segment_id'] = val['height_segment_id']
        IS2_atl07_fill[gtx]['sea_ice_segments']['height_segment_id'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['height_segment_id'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['long_name'] = \
            "Identifier of each height segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['description'] = \
            "Identifier of each height segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['height_segment_id']['coordinates'] = \
            "delta_time latitude longitude"
        #-- geolocation segment beginning
        IS2_atl07_tide[gtx]['sea_ice_segments']['geoseg_beg'] = val['geoseg_beg'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['geoseg_beg'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['geoseg_beg'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['long_name'] = "Beginning GEOSEG"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['description'] = \
            "Geolocation segment (geoseg) ID associated with the first photon used in this sea ice segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_beg']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"
        #-- geolocation segment ending
        IS2_atl07_tide[gtx]['sea_ice_segments']['geoseg_end'] = val['geoseg_end'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['geoseg_end'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['geoseg_end'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['units'] = "1"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['long_name'] = "Ending GEOSEG"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['description'] = \
            "Geolocation segment (geoseg) ID associated with the last photon used in this sea ice segment"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geoseg_end']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"
        #-- along track distance
        IS2_atl07_tide[gtx]['sea_ice_segments']['seg_dist_x'] = val['seg_dist_x'].copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['seg_dist_x'] = None
        IS2_atl07_dims[gtx]['sea_ice_segments']['seg_dist_x'] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['units'] = "meters"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['long_name'] = "Along track distance"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['description'] = \
            "Along-track distance from the equator crossing to the segment center."
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['seg_dist_x']['coordinates'] = \
            "height_segment_id delta_time latitude longitude"

        #-- geophysical variables
        IS2_atl07_tide[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_fill[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_dims[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical']['Description'] = ("Contains geophysical "
            "parameters and corrections used to correct photon heights for geophysical effects, such as tides.")
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical']['data_rate'] = ("Data within this group "
            "are stored at the sea_ice_height segment rate.")

        #-- computed tide
        IS2_atl07_tide[gtx]['sea_ice_segments']['geophysical'][variable] = tide.copy()
        IS2_atl07_fill[gtx]['sea_ice_segments']['geophysical'][variable] = tide.fill_value
        IS2_atl07_dims[gtx]['sea_ice_segments']['geophysical'][variable] = ['delta_time']
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable] = {}
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['units'] = "meters"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['contentType'] = "referenceInformation"
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['long_name'] = long_name
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['description'] = description
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['source'] = TIDE_MODEL
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['reference'] = reference
        IS2_atl07_tide_attrs[gtx]['sea_ice_segments']['geophysical'][variable]['coordinates'] = \
            "../height_segment_id ../delta_time ../latitude ../longitude"

    #-- output tidal HDF5 file
    args = (PRD,HEM,TIDE_MODEL,YY,MM,DD,HH,MN,SS,TRK,CYCL,SN,RL,VERS,AUX)
    ff = '{0}-{1}_{2}_TIDES_{3}{4}{5}{6}{7}{8}_{9}{10}{11}_{12}_{13}{14}.h5'
    #-- print file information
    print('\t{0}'.format(ff.format(*args))) if VERBOSE else None
    HDF5_ATL07_tide_write(IS2_atl07_tide, IS2_atl07_tide_attrs,
        CLOBBER=True, INPUT=os.path.basename(FILE),
        FILL_VALUE=IS2_atl07_fill, DIMENSIONS=IS2_atl07_dims,
        FILENAME=os.path.join(DIRECTORY,ff.format(*args)))
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY,ff.format(*args)), MODE)
예제 #25
0
def compute_tides_ICESat(tide_dir,
                         INPUT_FILE,
                         TIDE_MODEL=None,
                         METHOD='spline',
                         EXTRAPOLATE=False,
                         CUTOFF=None,
                         VERBOSE=False,
                         MODE=0o775):
    #-- select between tide models
    if (TIDE_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'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_MODEL == 'CATS2008'):
        grid_file = os.path.join(tide_dir, 'CATS2008', 'grid_CATS2008')
        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/')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        TYPE = 'z'
    elif (TIDE_MODEL == 'TPXO9-atlas'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas')
        grid_file = os.path.join(model_directory, '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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas_v2')
        grid_file = os.path.join(model_directory,
                                 'grid_tpxo9_atlas_30_v2.nc.gz')
        model_files = [
            'h_q1_tpxo9_atlas_30_v2.nc.gz', 'h_o1_tpxo9_atlas_30_v2.nc.gz',
            'h_p1_tpxo9_atlas_30_v2.nc.gz', 'h_k1_tpxo9_atlas_30_v2.nc.gz',
            'h_n2_tpxo9_atlas_30_v2.nc.gz', 'h_m2_tpxo9_atlas_30_v2.nc.gz',
            'h_s2_tpxo9_atlas_30_v2.nc.gz', 'h_k2_tpxo9_atlas_30_v2.nc.gz',
            'h_m4_tpxo9_atlas_30_v2.nc.gz', 'h_ms4_tpxo9_atlas_30_v2.nc.gz',
            'h_mn4_tpxo9_atlas_30_v2.nc.gz', 'h_2n2_tpxo9_atlas_30_v2.nc.gz'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v3'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas_v3')
        grid_file = os.path.join(model_directory,
                                 'grid_tpxo9_atlas_30_v3.nc.gz')
        model_files = [
            'h_q1_tpxo9_atlas_30_v3.nc.gz', 'h_o1_tpxo9_atlas_30_v3.nc.gz',
            'h_p1_tpxo9_atlas_30_v3.nc.gz', 'h_k1_tpxo9_atlas_30_v3.nc.gz',
            'h_n2_tpxo9_atlas_30_v3.nc.gz', 'h_m2_tpxo9_atlas_30_v3.nc.gz',
            'h_s2_tpxo9_atlas_30_v3.nc.gz', 'h_k2_tpxo9_atlas_30_v3.nc.gz',
            'h_m4_tpxo9_atlas_30_v3.nc.gz', 'h_ms4_tpxo9_atlas_30_v3.nc.gz',
            'h_mn4_tpxo9_atlas_30_v3.nc.gz', 'h_2n2_tpxo9_atlas_30_v3.nc.gz',
            'h_mf_tpxo9_atlas_30_v3.nc.gz', 'h_mm_tpxo9_atlas_30_v3.nc.gz'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'netcdf'
        TYPE = 'z'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_MODEL == 'TPXO9-atlas-v4'):
        model_directory = os.path.join(tide_dir, 'TPXO9_atlas_v4')
        grid_file = os.path.join(model_directory, 'grid_tpxo9_atlas_30_v4')
        model_files = [
            'h_q1_tpxo9_atlas_30_v4', 'h_o1_tpxo9_atlas_30_v4',
            'h_p1_tpxo9_atlas_30_v4', 'h_k1_tpxo9_atlas_30_v4',
            'h_n2_tpxo9_atlas_30_v4', 'h_m2_tpxo9_atlas_30_v4',
            'h_s2_tpxo9_atlas_30_v4', 'h_k2_tpxo9_atlas_30_v4',
            'h_m4_tpxo9_atlas_30_v4', 'h_ms4_tpxo9_atlas_30_v4',
            'h_mn4_tpxo9_atlas_30_v4', 'h_2n2_tpxo9_atlas_30_v4',
            'h_mf_tpxo9_atlas_30_v4', 'h_mm_tpxo9_atlas_30_v4'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        reference = 'https://www.tpxo.net/global/tpxo9-atlas'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'ATLAS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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'
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'OTIS'
        EPSG = '4326'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_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/')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'AOTIM-5-2018'):
        grid_file = os.path.join(tide_dir, 'Arc5km2018', 'grid_Arc5km2018')
        model_file = os.path.join(tide_dir, 'Arc5km2018', 'h_Arc5km2018')
        reference = ('https://www.esr.org/research/polar-tide-models/'
                     'list-of-polar-tide-models/aotim-5/')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = 'PSNorth'
        TYPE = 'z'
    elif (TIDE_MODEL == 'Gr1km-v2'):
        grid_file = os.path.join(tide_dir, 'greenlandTMD_v2',
                                 'grid_Greenland8.v2')
        model_file = os.path.join(tide_dir, 'greenlandTMD_v2',
                                  'h_Greenland8.v2')
        reference = 'https://doi.org/10.1002/2016RG000546'
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'OTIS'
        EPSG = '3413'
        TYPE = 'z'
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
        GZIP = True
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
        GZIP = True
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
        GZIP = True
    elif (TIDE_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'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = ['q1', 'o1', 'p1', 'k1', 'n2', 'm2', 's2', 'k2', 's1', 'm4']
        reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
                     'MiscPubs/19990089548_1999150788.pdf')
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014'):
        model_directory = os.path.join(tide_dir, 'fes2014', 'ocean_tide')
        model_files = [
            '2n2.nc.gz', 'eps2.nc.gz', 'j1.nc.gz', 'k1.nc.gz', 'k2.nc.gz',
            'l2.nc.gz', 'la2.nc.gz', 'm2.nc.gz', 'm3.nc.gz', 'm4.nc.gz',
            'm6.nc.gz', 'm8.nc.gz', 'mf.nc.gz', 'mks2.nc.gz', 'mm.nc.gz',
            'mn4.nc.gz', 'ms4.nc.gz', 'msf.nc.gz', 'msqm.nc.gz', 'mtm.nc.gz',
            'mu2.nc.gz', 'n2.nc.gz', 'n4.nc.gz', 'nu2.nc.gz', 'o1.nc.gz',
            'p1.nc.gz', 'q1.nc.gz', 'r2.nc.gz', 's1.nc.gz', 's2.nc.gz',
            's4.nc.gz', 'sa.nc.gz', 'ssa.nc.gz', 't2.nc.gz'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = [
            '2n2', 'eps2', 'j1', 'k1', 'k2', 'l2', 'lambda2', 'm2', 'm3', 'm4',
            'm6', 'm8', 'mf', 'mks2', 'mm', 'mn4', 'ms4', 'msf', 'msqm', 'mtm',
            'mu2', 'n2', 'n4', 'nu2', 'o1', 'p1', 'q1', 'r2', 's1', 's2', 's4',
            'sa', 'ssa', 't2'
        ]
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
                     'auxiliary-products/global-tide-fes.html')
        variable = 'd_ocElv'
        long_name = "Ocean Tide Elevation"
        description = (
            "Ocean Tides including diurnal and semi-diurnal "
            "(harmonic analysis), and longer period tides (dynamic and "
            "self-consistent equilibrium).")
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0 / 100.0
        GZIP = True
    elif (TIDE_MODEL == 'FES2014_load'):
        model_directory = os.path.join(tide_dir, 'fes2014', 'load_tide')
        model_files = [
            '2n2.nc.gz', 'eps2.nc.gz', 'j1.nc.gz', 'k1.nc.gz', 'k2.nc.gz',
            'l2.nc.gz', 'la2.nc.gz', 'm2.nc.gz', 'm3.nc.gz', 'm4.nc.gz',
            'm6.nc.gz', 'm8.nc.gz', 'mf.nc.gz', 'mks2.nc.gz', 'mm.nc.gz',
            'mn4.nc.gz', 'ms4.nc.gz', 'msf.nc.gz', 'msqm.nc.gz', 'mtm.nc.gz',
            'mu2.nc.gz', 'n2.nc.gz', 'n4.nc.gz', 'nu2.nc.gz', 'o1.nc.gz',
            'p1.nc.gz', 'q1.nc.gz', 'r2.nc.gz', 's1.nc.gz', 's2.nc.gz',
            's4.nc.gz', 'sa.nc.gz', 'ssa.nc.gz', 't2.nc.gz'
        ]
        model_file = [os.path.join(model_directory, m) for m in model_files]
        c = [
            '2n2', 'eps2', 'j1', 'k1', 'k2', 'l2', 'lambda2', 'm2', 'm3', 'm4',
            'm6', 'm8', 'mf', 'mks2', 'mm', 'mn4', 'ms4', 'msf', 'msqm', 'mtm',
            'mu2', 'n2', 'n4', 'nu2', 'o1', 'p1', 'q1', 'r2', 's1', 's2', 's4',
            'sa', 'ssa', 't2'
        ]
        reference = ('https://www.aviso.altimetry.fr/en/data/products'
                     'auxiliary-products/global-tide-fes.html')
        variable = 'd_ldElv'
        long_name = "Load Tide Elevation"
        description = "Local displacement due to Ocean Loading (-6 to 0 cm)"
        model_format = 'FES'
        TYPE = 'z'
        SCALE = 1.0 / 100.0
        GZIP = True

    #-- get directory from INPUT_FILE
    print('{0} -->'.format(os.path.basename(INPUT_FILE))) if VERBOSE else None
    DIRECTORY = os.path.dirname(INPUT_FILE)

    #-- compile regular expression operator for extracting information from file
    rx = re.compile((r'GLAH(\d{2})_(\d{3})_(\d{1})(\d{1})(\d{2})_(\d{3})_'
                     r'(\d{4})_(\d{1})_(\d{2})_(\d{4})\.H5'), re.VERBOSE)
    #-- extract parameters from ICESat/GLAS HDF5 file name
    #-- PRD:  Product number (01, 05, 06, 12, 13, 14, or 15)
    #-- RL:  Release number for process that created the product = 634
    #-- RGTP:  Repeat ground-track phase (1=8-day, 2=91-day, 3=transfer orbit)
    #-- ORB:   Reference orbit number (starts at 1 and increments each time a
    #--           new reference orbit ground track file is obtained.)
    #-- INST:  Instance number (increments every time the satellite enters a
    #--           different reference orbit)
    #-- CYCL:   Cycle of reference orbit for this phase
    #-- TRK: Track within reference orbit
    #-- SEG:   Segment of orbit
    #-- GRAN:  Granule version number
    #-- TYPE:  File type
    try:
        PRD, RL, RGTP, ORB, INST, CYCL, TRK, SEG, GRAN, TYPE = rx.findall(
            INPUT_FILE).pop()
    except:
        #-- output tide HDF5 file (generic)
        fileBasename, fileExtension = os.path.splitext(INPUT_FILE)
        args = (fileBasename, TIDE_MODEL, fileExtension)
        OUTPUT_FILE = '{0}_{1}_TIDES{2}'.format(*args)
    else:
        #-- output tide HDF5 file for NSIDC granules
        args = (PRD, RL, TIDE_MODEL, RGTP, ORB, INST, CYCL, TRK, SEG, GRAN,
                TYPE)
        file_format = 'GLAH{0}_{1}_{2}_TIDES_{3}{4}{5}_{6}_{7}_{8}_{9}_{10}.h5'
        OUTPUT_FILE = file_format.format(*args)

    #-- read GLAH12 HDF5 file
    fileID = h5py.File(INPUT_FILE, 'r')
    n_40HZ, = fileID['Data_40HZ']['Time']['i_rec_ndx'].shape
    #-- get variables and attributes
    rec_ndx_40HZ = fileID['Data_40HZ']['Time']['i_rec_ndx'][:].copy()
    #-- seconds since 2000-01-01 12:00:00 UTC (J2000)
    DS_UTCTime_40HZ = fileID['Data_40HZ']['DS_UTCTime_40'][:].copy()
    #-- Latitude (degrees North)
    lat_TPX = fileID['Data_40HZ']['Geolocation']['d_lat'][:].copy()
    #-- Longitude (degrees East)
    lon_40HZ = fileID['Data_40HZ']['Geolocation']['d_lon'][:].copy()
    #-- Elevation (height above TOPEX/Poseidon ellipsoid in meters)
    elev_TPX = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'][:].copy()
    fv = fileID['Data_40HZ']['Elevation_Surfaces']['d_elev'].attrs[
        '_FillValue']

    #-- semimajor axis (a) and flattening (f) for TP and WGS84 ellipsoids
    atop, ftop = (6378136.3, 1.0 / 298.257)
    awgs, fwgs = (6378137.0, 1.0 / 298.257223563)
    #-- convert from Topex/Poseidon to WGS84 Ellipsoids
    lat_40HZ, elev_40HZ = pyTMD.spatial.convert_ellipsoid(lat_TPX,
                                                          elev_TPX,
                                                          atop,
                                                          ftop,
                                                          awgs,
                                                          fwgs,
                                                          eps=1e-12,
                                                          itmax=10)

    #-- convert time from J2000 to days relative to Jan 1, 1992 (48622mjd)
    #-- J2000: seconds since 2000-01-01 12:00:00 UTC
    tide_time = pyTMD.time.convert_delta_time(DS_UTCTime_40HZ,
                                              epoch1=(2000, 1, 1, 12, 0, 0),
                                              epoch2=(1992, 1, 1, 0, 0, 0),
                                              scale=1.0 / 86400.0)
    #-- delta time (TT - UT1) file
    delta_file = pyTMD.utilities.get_data_path(['data', 'merged_deltat.data'])
    #-- read tidal constants and interpolate to grid points
    if model_format in ('OTIS', 'ATLAS'):
        amp, ph, D, c = extract_tidal_constants(lon_40HZ,
                                                lat_40HZ,
                                                grid_file,
                                                model_file,
                                                EPSG,
                                                TYPE=TYPE,
                                                METHOD=METHOD,
                                                EXTRAPOLATE=EXTRAPOLATE,
                                                CUTOFF=CUTOFF,
                                                GRID=model_format)
        deltat = np.zeros_like(tide_time)
    elif (model_format == 'netcdf'):
        amp, ph, D, c = extract_netcdf_constants(lon_40HZ,
                                                 lat_40HZ,
                                                 grid_file,
                                                 model_file,
                                                 TYPE=TYPE,
                                                 METHOD=METHOD,
                                                 EXTRAPOLATE=EXTRAPOLATE,
                                                 CUTOFF=CUTOFF,
                                                 SCALE=SCALE,
                                                 GZIP=GZIP)
        deltat = np.zeros_like(tide_time)
    elif (model_format == 'GOT'):
        amp, ph, c = extract_GOT_constants(lon_40HZ,
                                           lat_40HZ,
                                           model_file,
                                           METHOD=METHOD,
                                           EXTRAPOLATE=EXTRAPOLATE,
                                           CUTOFF=CUTOFF,
                                           SCALE=SCALE,
                                           GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, tide_time)
    elif (model_format == 'FES'):
        amp, ph = extract_FES_constants(lon_40HZ,
                                        lat_40HZ,
                                        model_file,
                                        TYPE=TYPE,
                                        VERSION=TIDE_MODEL,
                                        METHOD=METHOD,
                                        EXTRAPOLATE=EXTRAPOLATE,
                                        CUTOFF=CUTOFF,
                                        SCALE=SCALE,
                                        GZIP=GZIP)
        #-- interpolate delta times from calendar dates to tide time
        deltat = calc_delta_time(delta_file, tide_time)

    #-- calculate complex phase in radians for Euler's
    cph = -1j * ph * np.pi / 180.0
    #-- calculate constituent oscillation
    hc = amp * np.exp(cph)

    #-- predict tidal elevations at time and infer minor corrections
    tide = np.ma.empty((n_40HZ), fill_value=fv)
    tide.mask = np.any(hc.mask, axis=1)
    tide.data[:] = predict_tide_drift(tide_time,
                                      hc,
                                      c,
                                      DELTAT=deltat,
                                      CORRECTIONS=model_format)
    minor = infer_minor_corrections(tide_time,
                                    hc,
                                    c,
                                    DELTAT=deltat,
                                    CORRECTIONS=model_format)
    tide.data[:] += minor.data[:]
    #-- replace masked and nan values with fill value
    invalid, = np.nonzero(np.isnan(tide.data) | tide.mask)
    tide.data[invalid] = tide.fill_value
    tide.mask[invalid] = True

    #-- copy variables for outputting to HDF5 file
    IS_gla12_tide = dict(Data_40HZ={})
    IS_gla12_fill = dict(Data_40HZ={})
    IS_gla12_tide_attrs = dict(Data_40HZ={})

    #-- copy global file attributes
    global_attribute_list = [
        'featureType', 'title', 'comment', 'summary', 'license', 'references',
        'AccessConstraints', 'CitationforExternalPublication',
        'contributor_role', 'contributor_name', 'creator_name',
        'creator_email', 'publisher_name', 'publisher_email', 'publisher_url',
        'platform', 'instrument', 'processing_level', 'date_created',
        'spatial_coverage_type', 'history', 'keywords', 'keywords_vocabulary',
        'naming_authority', 'project', 'time_type', 'date_type',
        'time_coverage_start', 'time_coverage_end', 'time_coverage_duration',
        'source', 'HDFVersion', 'identifier_product_type',
        'identifier_product_format_version', 'Conventions', 'institution',
        'ReprocessingPlanned', 'ReprocessingActual', 'LocalGranuleID',
        'ProductionDateTime', 'LocalVersionID', 'PGEVersion', 'OrbitNumber',
        'StartOrbitNumber', 'StopOrbitNumber', 'EquatorCrossingLongitude',
        'EquatorCrossingTime', 'EquatorCrossingDate', 'ShortName', 'VersionID',
        'InputPointer', 'RangeBeginningTime', 'RangeEndingTime',
        'RangeBeginningDate', 'RangeEndingDate', 'PercentGroundHit',
        'OrbitQuality', 'Cycle', 'Track', 'Instrument_State', 'Timing_Bias',
        'ReferenceOrbit', 'SP_ICE_PATH_NO', 'SP_ICE_GLAS_StartBlock',
        'SP_ICE_GLAS_EndBlock', 'Instance', 'Range_Bias',
        'Instrument_State_Date', 'Instrument_State_Time', 'Range_Bias_Date',
        'Range_Bias_Time', 'Timing_Bias_Date', 'Timing_Bias_Time',
        'identifier_product_doi', 'identifier_file_uuid',
        'identifier_product_doi_authority'
    ]
    for att in global_attribute_list:
        IS_gla12_tide_attrs[att] = fileID.attrs[att]

    #-- add attributes for input GLA12 file
    IS_gla12_tide_attrs['input_files'] = os.path.basename(INPUT_FILE)
    #-- update geospatial ranges for ellipsoid
    IS_gla12_tide_attrs['geospatial_lat_min'] = np.min(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_max'] = np.max(lat_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_min'] = np.min(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lon_max'] = np.max(lon_40HZ)
    IS_gla12_tide_attrs['geospatial_lat_units'] = "degrees_north"
    IS_gla12_tide_attrs['geospatial_lon_units'] = "degrees_east"
    IS_gla12_tide_attrs['geospatial_ellipsoid'] = "WGS84"

    #-- copy 40Hz group attributes
    for att_name, att_val in fileID['Data_40HZ'].attrs.items():
        IS_gla12_tide_attrs['Data_40HZ'][att_name] = att_val
    #-- copy attributes for time, geolocation and geophysical groups
    for var in ['Time', 'Geolocation', 'Geophysical']:
        IS_gla12_tide['Data_40HZ'][var] = {}
        IS_gla12_fill['Data_40HZ'][var] = {}
        IS_gla12_tide_attrs['Data_40HZ'][var] = {}
        for att_name, att_val in fileID['Data_40HZ'][var].attrs.items():
            IS_gla12_tide_attrs['Data_40HZ'][var][att_name] = att_val

    #-- J2000 time
    IS_gla12_tide['Data_40HZ']['DS_UTCTime_40'] = DS_UTCTime_40HZ
    IS_gla12_fill['Data_40HZ']['DS_UTCTime_40'] = None
    IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'] = {}
    for att_name, att_val in fileID['Data_40HZ']['DS_UTCTime_40'].attrs.items(
    ):
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['DS_UTCTime_40'][
                att_name] = att_val
    #-- record
    IS_gla12_tide['Data_40HZ']['Time']['i_rec_ndx'] = rec_ndx_40HZ
    IS_gla12_fill['Data_40HZ']['Time']['i_rec_ndx'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name, att_val in fileID['Data_40HZ']['Time'][
            'i_rec_ndx'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Time']['i_rec_ndx'][
                att_name] = att_val
    #-- latitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lat'] = lat_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lat'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name, att_val in fileID['Data_40HZ']['Geolocation'][
            'd_lat'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lat'][
                att_name] = att_val
    #-- longitude
    IS_gla12_tide['Data_40HZ']['Geolocation']['d_lon'] = lon_40HZ
    IS_gla12_fill['Data_40HZ']['Geolocation']['d_lon'] = None
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon']['coordinates'] = \
        "../DS_UTCTime_40"
    for att_name, att_val in fileID['Data_40HZ']['Geolocation'][
            'd_lon'].attrs.items():
        if att_name not in ('DIMENSION_LIST', 'CLASS', 'NAME'):
            IS_gla12_tide_attrs['Data_40HZ']['Geolocation']['d_lon'][
                att_name] = att_val

    #-- geophysical variables
    #-- computed tide
    IS_gla12_tide['Data_40HZ']['Geophysical'][variable] = tide
    IS_gla12_fill['Data_40HZ']['Geophysical'][variable] = tide.fill_value
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable] = {}
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable][
        'units'] = "meters"
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable][
        'long_name'] = long_name
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable][
        'description'] = description
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable][
        'source'] = TIDE_MODEL
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable][
        'reference'] = reference
    IS_gla12_tide_attrs['Data_40HZ']['Geophysical'][variable]['coordinates'] = \
        "../DS_UTCTime_40"

    #-- close the input HDF5 file
    fileID.close()

    #-- print file information
    print('\t{0}'.format(OUTPUT_FILE)) if VERBOSE else None
    HDF5_GLA12_tide_write(IS_gla12_tide,
                          IS_gla12_tide_attrs,
                          FILENAME=os.path.join(DIRECTORY, OUTPUT_FILE),
                          FILL_VALUE=IS_gla12_fill,
                          CLOBBER=True)
    #-- change the permissions mode
    os.chmod(os.path.join(DIRECTORY, OUTPUT_FILE), MODE)
예제 #26
0
def plot_tide_forecasts(tide_dir, LON, LAT, DATE, TIDE_MODEL=''):
    #-- select between tide models
    if (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = 'CATS2008'
        type = 'z'
    elif (TIDE_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'
        model_format = 'netcdf'
        type = 'z'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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'
        model_format = 'ATLAS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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'
        model_format = 'OTIS'
        EPSG = '4326'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (TIDE_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/')
        model_format = 'OTIS'
        EPSG = '3996'
        type = 'z'
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 100.0
    elif (TIDE_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')
        model_format = 'GOT'
        SCALE = 1.0 / 1000.0

    #-- calculate the modified Julian day from the calendar date
    MJD = calc_modified_julian_day(DATE.tm_year, DATE.tm_mon, DATE.tm_mday)
    TIME = np.arange(7 * 1440) / 1440.0

    #-- read tidal constants and interpolate to grid points
    if model_format in ('OTIS', 'ATLAS'):
        amp, ph, D, c = extract_tidal_constants(np.array([LON]),
                                                np.array([LAT]),
                                                grid_file,
                                                model_file,
                                                EPSG,
                                                type,
                                                METHOD='spline',
                                                GRID=model_format)
        deltat = np.zeros_like(MJD)
    elif (model_format == 'netcdf'):
        amp, ph, D, c = extract_netcdf_constants(np.array([LON]),
                                                 np.array([LAT]),
                                                 model_directory,
                                                 grid_file,
                                                 model_files,
                                                 type,
                                                 METHOD='spline',
                                                 SCALE=SCALE)
        deltat = np.zeros_like(MJD)
    elif (model_format == 'GOT'):
        amp, ph = extract_GOT_constants(np.array([LON]),
                                        np.array([LAT]),
                                        model_directory,
                                        model_files,
                                        METHOD='spline',
                                        SCALE=SCALE)
        delta_file = os.path.join(tide_dir, 'deltat.data')
        deltat = calc_delta_time(delta_file, MJD + TIME)

    #-- convert phase to radians
    cph = -1j * ph * np.pi / 180.0
    hc = amp * np.exp(cph)

    #-- convert time from MJD to days relative to Jan 1, 1992 (48622 MJD)
    #-- predict tidal elevations at time 1 and infer minor corrections
    TIDE = predict_tidal_ts(MJD + TIME - 48622.0,
                            hc,
                            c,
                            DELTAT=deltat,
                            CORRECTIONS=model_format)
    TIDE += infer_minor_corrections(MJD + TIME - 48622.0,
                                    hc,
                                    c,
                                    DELTAT=deltat,
                                    CORRECTIONS=model_format)
    #-- convert to centimeters
    TIDE *= 100.0

    #-- differentiate to calculate high and low tides
    diff = np.zeros_like(TIME, dtype=np.float)
    #-- forward differentiation for starting point
    diff[0] = TIDE[1] - TIDE[0]
    #-- backward differentiation for end point
    diff[-1] = TIDE[-1] - TIDE[-2]
    #-- centered differentiation for all others
    diff[1:-1] = (TIDE[2:] - TIDE[0:-2]) / 2.0
    #-- indices of high and low tides
    htindex, = np.nonzero((np.sign(diff[0:-1]) >= 0) & (np.sign(diff[1:]) < 0))
    ltindex, = np.nonzero((np.sign(diff[0:-1]) <= 0) & (np.sign(diff[1:]) > 0))

    #-- create plot with tidal displacements, high and low tides and dates
    fig, ax1 = plt.subplots(num=1)
    ax1.plot(TIME * 24.0, TIDE, 'k')
    ax1.plot(TIME[htindex] * 24.0, TIDE[htindex], 'r*')
    ax1.plot(TIME[ltindex] * 24.0, TIDE[ltindex], 'b*')
    for h in range(24, 192, 24):
        ax1.axvline(h, color='gray', lw=0.5, ls='dashed', dashes=(11, 5))
    ax1.set_xlim(0, 7 * 24)
    ax1.set_ylabel('{0} Tidal Displacement [cm]'.format(TIDE_MODEL))
    args = (DATE.tm_year, DATE.tm_mon, DATE.tm_mday)
    ax1.set_xlabel(
        'Time from {0:4d}-{1:02d}-{2:02d} UTC [Hours]'.format(*args))
    ax1.set_title(u'{0:0.6f}\u00b0N {1:0.6f}\u00b0W'.format(LAT, LON))
    fig.subplots_adjust(left=0.10, right=0.98, bottom=0.10, top=0.95)
    plt.show()