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