示例#1
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_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
示例#3
0
def compute_tidal_elevations(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,
                             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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '4326'
        model_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'
        model_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'
        model_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'
        model_type = 'z'
        model_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'
        model_type = 'z'
        model_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"
        model_format = 'netcdf'
        model_type = 'z'
        model_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 = 'tide_ocean'
        long_name = "Ocean_Tide"
        model_format = 'OTIS'
        EPSG = '4326'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        output_variable = 'tide_ocean'
        variable_long_name = 'Ocean_Tide'
        model_format = 'OTIS'
        EPSG = '3413'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_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'
        model_type = 'z'
        model_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'
        model_type = 'z'
        model_scale = 1.0 / 100.0
        GZIP = True

    #-- 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=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:
        #-- EPSG projection code string or int
        crs1 = pyproj.CRS.from_string("epsg:{0:d}".format(int(PROJECTION)))
    except (ValueError, pyproj.exceptions.CRSError):
        #-- Projection SRS string
        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)
    #-- 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(lon.flatten(),
                                                lat.flatten(),
                                                grid_file,
                                                model_file,
                                                EPSG,
                                                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(),
                                                 grid_file,
                                                 model_file,
                                                 TYPE=model_type,
                                                 METHOD=METHOD,
                                                 EXTRAPOLATE=EXTRAPOLATE,
                                                 CUTOFF=CUTOFF,
                                                 SCALE=model_scale,
                                                 GZIP=GZIP)
        deltat = np.zeros((nt))
    elif (model_format == 'GOT'):
        amp, ph, c = extract_GOT_constants(lon.flatten(),
                                           lat.flatten(),
                                           model_file,
                                           METHOD=METHOD,
                                           EXTRAPOLATE=EXTRAPOLATE,
                                           CUTOFF=CUTOFF,
                                           SCALE=model_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.flatten(),
                                        lat.flatten(),
                                        model_file,
                                        TYPE=model_type,
                                        VERSION=TIDE_MODEL,
                                        METHOD=METHOD,
                                        EXTRAPOLATE=EXTRAPOLATE,
                                        CUTOFF=CUTOFF,
                                        SCALE=model_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
    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],
                               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=output_variable)
    #-- change the permissions level to MODE
    os.chmod(output_file, MODE)
示例#4
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
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)