Plots the daily tidal displacements for a given location
OTIS format tidal solutions provided by Ohio State University and ESR
Global Tide Model (GOT) solutions provided by Richard Ray at GSFC
Finite Element Solution (FES) provided by AVISO
calc_astrol_longitudes.py
: computes the basic astronomical mean longitudescalc_delta_time.py
: calculates difference between universal and dynamic timeconvert_ll_xy.py
: convert lat/lon points to and from projected coordinatesload_constituent.py
: loads parameters for a given tidal constituentload_nodal_corrections.py
: load the nodal corrections for tidal constituentsinfer_minor_corrections.py
: return corrections for minor constituentsread_tide_model.py
: extract tidal harmonic constants from OTIS tide modelsread_netcdf_model.py
: extract tidal harmonic constants from netcdf modelsread_GOT_model.py
: extract tidal harmonic constants from GSFC GOT modelsread_FES_model.py
: extract tidal harmonic constants from FES tide modelspredict_tidal_ts.py
: predict tidal time series at a location using harmonic constantsThis notebook uses Jupyter widgets to set parameters for calculating the tidal maps.
The widgets can be installed as described below.
pip3 install --user ipywidgets
jupyter nbextension install --user --py widgetsnbextension
jupyter nbextension enable --user --py widgetsnbextension
jupyter-notebook
from __future__ import print_function
import sys
import os
import getopt
import datetime
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as widgets
import ipyleaflet as leaflet
import pyTMD.time
from pyTMD.calc_delta_time import calc_delta_time
from pyTMD.infer_minor_corrections import infer_minor_corrections
from pyTMD.predict_tidal_ts import predict_tidal_ts
from pyTMD.read_tide_model import extract_tidal_constants
from pyTMD.read_netcdf_model import extract_netcdf_constants
from pyTMD.read_GOT_model import extract_GOT_constants
from pyTMD.read_FES_model import extract_FES_constants
#-- autoreload
%load_ext autoreload
%autoreload 2
#-- set the directory with tide models
dirText = widgets.Text(
value=os.getcwd(),
description='Directory:',
disabled=False
)
#-- dropdown menu for setting tide model
model_list = ['CATS0201','CATS2008','TPXO9-atlas','TPXO9-atlas-v2',
'TPXO9-atlas-v3','TPXO9.1','TPXO8-atlas','TPXO7.2',
'AODTM-5','AOTIM-5','AOTIM-5-2018',
'GOT4.7','GOT4.8','GOT4.10','FES2014']
modelDropdown = widgets.Dropdown(
options=model_list,
value='GOT4.10',
description='Model:',
disabled=False,
)
#-- date picker widget for setting time
datepick = widgets.DatePicker(
description='Date:',
value = datetime.date.today(),
disabled=False
)
#-- display widgets for setting directory, model and date
widgets.VBox([dirText,modelDropdown,datepick])
#-- default coordinates to use
LAT,LON = (32.93301304,242.7294513)
m = leaflet.Map(center=(LAT,LON), zoom=12, basemap=leaflet.basemaps.Esri.WorldTopoMap)
#-- add control for zoom
zoom_slider = widgets.IntSlider(description='Zoom level:', min=0, max=15, value=7)
widgets.jslink((zoom_slider, 'value'), (m, 'zoom'))
zoom_control = leaflet.WidgetControl(widget=zoom_slider, position='topright')
m.add_control(zoom_control)
#-- add marker with default location
marker = leaflet.Marker(location=(LAT,LON), draggable=True)
m.add_layer(marker)
#-- add text with marker location
markerText = widgets.Text(
value='{0:0.8f},{1:0.8f}'.format(LAT,LON),
description='Lat/Lon:',
disabled=False
)
#-- add function for setting marker text if location changed
def set_marker_text(sender):
LAT,LON = marker.location
markerText.value = '{0:0.8f},{1:0.8f}'.format(LAT,LON % 360)
#-- add function for setting map center if location changed
def set_map_center(sender):
m.center = marker.location
#-- add function for setting marker location if text changed
def set_marker_location(sender):
LAT,LON = [float(i) for i in markerText.value.split(',')]
marker.location = (LAT,LON % 360)
#-- watch marker widgets for changes
marker.observe(set_marker_text)
markerText.observe(set_marker_location)
m.observe(set_map_center)
#-- add control for marker location
marker_control = leaflet.WidgetControl(widget=markerText, position='bottomright')
m.add_control(marker_control)
m
#-- directory with tide models
tide_dir = os.path.expanduser(dirText.value)
TIDE_MODEL = modelDropdown.value
LAT,LON = marker.location
#-- verify longitudes
LON %= 360
#-- convert from calendar date to days relative to Jan 1, 1992 (48622 MJD)
YMD = datepick.value
#-- calculate a weeks forecast every minute
tide_time = pyTMD.time.convert_calendar_dates(YMD.year, YMD.month,
YMD.day, minute=np.arange(7*1440))
#-- select between tide models
if (TIDE_MODEL == 'CATS0201'):
grid_file = os.path.join(tide_dir,'cats0201_tmd','grid_CATS')
model_file = os.path.join(tide_dir,'cats0201_tmd','h0_CATS02_01')
reference = 'https://mail.esr.org/polar_tide_models/Model_CATS0201.html'
model_format = 'OTIS'
EPSG = '4326'
TYPE = 'z'
elif (TIDE_MODEL == 'CATS2008'):
grid_file = os.path.join(tide_dir,'CATS2008','grid_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/')
model_format = 'OTIS'
EPSG = 'CATS2008'
TYPE = 'z'
elif (TIDE_MODEL == 'TPXO9-atlas'):
model_directory = os.path.join(tide_dir,'TPXO9_atlas')
grid_file = 'grid_tpxo9_atlas.nc.gz'
model_files = ['h_q1_tpxo9_atlas_30.nc.gz','h_o1_tpxo9_atlas_30.nc.gz',
'h_p1_tpxo9_atlas_30.nc.gz','h_k1_tpxo9_atlas_30.nc.gz',
'h_n2_tpxo9_atlas_30.nc.gz','h_m2_tpxo9_atlas_30.nc.gz',
'h_s2_tpxo9_atlas_30.nc.gz','h_k2_tpxo9_atlas_30.nc.gz',
'h_m4_tpxo9_atlas_30.nc.gz','h_ms4_tpxo9_atlas_30.nc.gz',
'h_mn4_tpxo9_atlas_30.nc.gz','h_2n2_tpxo9_atlas_30.nc.gz']
reference = 'http://volkov.oce.orst.edu/tides/tpxo9_atlas.html'
model_format = 'netcdf'
TYPE = 'z'
SCALE = 1.0/1000.0
elif (TIDE_MODEL == 'TPXO9-atlas-v2'):
model_directory = os.path.join(tide_dir,'TPXO9_atlas_v2')
grid_file = 'grid_tpxo9_atlas_30_v2.nc.gz'
model_files = ['h_q1_tpxo9_atlas_30_v2.nc.gz','h_o1_tpxo9_atlas_30_v2.nc.gz',
'h_p1_tpxo9_atlas_30_v2.nc.gz','h_k1_tpxo9_atlas_30_v2.nc.gz',
'h_n2_tpxo9_atlas_30_v2.nc.gz','h_m2_tpxo9_atlas_30_v2.nc.gz',
'h_s2_tpxo9_atlas_30_v2.nc.gz','h_k2_tpxo9_atlas_30_v2.nc.gz',
'h_m4_tpxo9_atlas_30_v2.nc.gz','h_ms4_tpxo9_atlas_30_v2.nc.gz',
'h_mn4_tpxo9_atlas_30_v2.nc.gz','h_2n2_tpxo9_atlas_30_v2.nc.gz']
model_format = 'netcdf'
TYPE = 'z'
SCALE = 1.0/1000.0
elif (TIDE_MODEL == 'TPXO9.1'):
grid_file = os.path.join(tide_dir,'TPXO9.1','DATA','grid_tpxo9')
model_file = os.path.join(tide_dir,'TPXO9.1','DATA','h_tpxo9.v1')
reference = 'http://volkov.oce.orst.edu/tides/global.html'
model_format = 'OTIS'
EPSG = '4326'
TYPE = 'z'
elif (TIDE_MODEL == 'TPXO8-atlas'):
grid_file = os.path.join(tide_dir,'tpxo8_atlas','grid_tpxo8atlas_30_v1')
model_file = os.path.join(tide_dir,'tpxo8_atlas','hf.tpxo8_atlas_30_v1')
reference = 'http://volkov.oce.orst.edu/tides/tpxo8_atlas.html'
model_format = 'ATLAS'
EPSG = '4326'
TYPE = 'z'
elif (TIDE_MODEL == 'TPXO7.2'):
grid_file = os.path.join(tide_dir,'TPXO7.2_tmd','grid_tpxo7.2')
model_file = os.path.join(tide_dir,'TPXO7.2_tmd','h_tpxo7.2')
reference = 'http://volkov.oce.orst.edu/tides/global.html'
model_format = 'OTIS'
EPSG = '4326'
TYPE = 'z'
elif (TIDE_MODEL == 'AODTM-5'):
grid_file = os.path.join(tide_dir,'aodtm5_tmd','grid_Arc5km')
model_file = os.path.join(tide_dir,'aodtm5_tmd','h0_Arc5km.oce')
reference = ('https://www.esr.org/research/polar-tide-models/'
'list-of-polar-tide-models/aodtm-5/')
model_format = 'OTIS'
EPSG = 'PSNorth'
TYPE = 'z'
elif (TIDE_MODEL == 'AOTIM-5'):
grid_file = os.path.join(tide_dir,'aotim5_tmd','grid_Arc5km')
model_file = os.path.join(tide_dir,'aotim5_tmd','h_Arc5km.oce')
reference = ('https://www.esr.org/research/polar-tide-models/'
'list-of-polar-tide-models/aotim-5/')
model_format = 'OTIS'
EPSG = 'PSNorth'
TYPE = 'z'
elif (TIDE_MODEL == 'AOTIM-5-2018'):
grid_file = os.path.join(tide_dir,'Arc5km2018','grid_Arc5km2018')
model_file = os.path.join(tide_dir,'Arc5km2018','h_Arc5km2018')
reference = ('https://www.esr.org/research/polar-tide-models/'
'list-of-polar-tide-models/aotim-5/')
model_format = 'OTIS'
EPSG = 'PSNorth'
TYPE = 'z'
elif (TIDE_MODEL == 'GOT4.7'):
model_directory = os.path.join(tide_dir,'GOT4.7','grids_oceantide')
model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz',
'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz']
c = ['q1','o1','p1','k1','n2','m2','s2','k2','s1','m4']
reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
'MiscPubs/19990089548_1999150788.pdf')
model_format = 'GOT'
SCALE = 1.0/100.0
elif (TIDE_MODEL == 'GOT4.8'):
model_directory = os.path.join(tide_dir,'got4.8','grids_oceantide')
model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz',
'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz']
c = ['q1','o1','p1','k1','n2','m2','s2','k2','s1','m4']
reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
'MiscPubs/19990089548_1999150788.pdf')
model_format = 'GOT'
SCALE = 1.0/100.0
elif (TIDE_MODEL == 'GOT4.10'):
model_directory = os.path.join(tide_dir,'GOT4.10c','grids_oceantide')
model_files = ['q1.d.gz','o1.d.gz','p1.d.gz','k1.d.gz','n2.d.gz',
'm2.d.gz','s2.d.gz','k2.d.gz','s1.d.gz','m4.d.gz']
c = ['q1','o1','p1','k1','n2','m2','s2','k2','s1','m4']
reference = ('https://denali.gsfc.nasa.gov/personal_pages/ray/'
'MiscPubs/19990089548_1999150788.pdf')
model_format = 'GOT'
SCALE = 1.0/100.0
elif (TIDE_MODEL == 'FES2014'):
model_directory = os.path.join(tide_dir,'fes2014','ocean_tide')
model_files = ['2n2.nc.gz','eps2.nc.gz','j1.nc.gz','k1.nc.gz',
'k2.nc.gz','l2.nc.gz','la2.nc.gz','m2.nc.gz','m3.nc.gz','m4.nc.gz',
'm6.nc.gz','m8.nc.gz','mf.nc.gz','mks2.nc.gz','mm.nc.gz',
'mn4.nc.gz','ms4.nc.gz','msf.nc.gz','msqm.nc.gz','mtm.nc.gz',
'mu2.nc.gz','n2.nc.gz','n4.nc.gz','nu2.nc.gz','o1.nc.gz','p1.nc.gz',
'q1.nc.gz','r2.nc.gz','s1.nc.gz','s2.nc.gz','s4.nc.gz','sa.nc.gz',
'ssa.nc.gz','t2.nc.gz']
c = ['2n2','eps2','j1','k1','k2','l2','lambda2','m2','m3','m4','m6',
'm8','mf','mks2','mm','mn4','ms4','msf','msqm','mtm','mu2','n2',
'n4','nu2','o1','p1','q1','r2','s1','s2','s4','sa','ssa','t2']
model_format = 'FES'
TYPE = 'z'
SCALE = 1.0/100.0
#-- read tidal constants and interpolate to grid points
if model_format in ('OTIS','ATLAS'):
amp,ph,D,c = extract_tidal_constants(np.array([LON]), np.array([LAT]),
grid_file,model_file,EPSG,TYPE=TYPE,METHOD='spline',GRID=model_format)
deltat = np.zeros_like(tide_time)
elif (model_format == 'netcdf'):
amp,ph,D,c = extract_netcdf_constants(np.array([LON]), np.array([LAT]),
model_directory, grid_file, model_files, TYPE=TYPE, METHOD='spline',
SCALE=SCALE)
deltat = np.zeros_like(tide_time)
elif (model_format == 'GOT'):
amp,ph = extract_GOT_constants(np.array([LON]), np.array([LAT]),
model_directory, model_files, METHOD='spline', SCALE=SCALE)
delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])
deltat = calc_delta_time(delta_file, tide_time)
elif (model_format == 'FES'):
amp,ph = extract_FES_constants(np.array([LON]), np.array([LAT]),
model_directory, model_files, TYPE=TYPE, VERSION=TIDE_MODEL,
METHOD='spline', SCALE=SCALE)
#-- interpolate delta times from calendar dates to tide time
delta_file = pyTMD.utilities.get_data_path(['data','merged_deltat.data'])
deltat = calc_delta_time(delta_file, tide_time)
#-- calculate complex phase in radians for Euler's
cph = -1j*ph*np.pi/180.0
#-- calculate constituent oscillation
hc = amp*np.exp(cph)
#-- convert time from MJD to days relative to Jan 1, 1992 (48622 MJD)
#-- predict tidal elevations at time 1 and infer minor corrections
TIDE = predict_tidal_ts(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[:]
#-- convert to centimeters
TIDE.data[:] *= 100.0
#-- differentiate to calculate high and low tides
diff = np.zeros_like(tide_time, dtype=np.float)
#-- forward differentiation for starting point
diff[0] = TIDE.data[1] - TIDE.data[0]
#-- backward differentiation for end point
diff[-1] = TIDE.data[-1] - TIDE.data[-2]
#-- centered differentiation for all others
diff[1:-1] = (TIDE.data[2:] - TIDE.data[0:-2])/2.0
#-- indices of high and low tides
htindex, = np.nonzero((np.sign(diff[0:-1]) >= 0) & (np.sign(diff[1:]) < 0))
ltindex, = np.nonzero((np.sign(diff[0:-1]) <= 0) & (np.sign(diff[1:]) > 0))
#-- create plot with tidal displacements, high and low tides and dates
fig,ax1 = plt.subplots(num=1)
ax1.plot(TIME*24.0,TIDE.data,'k')
ax1.plot(TIME[htindex]*24.0,TIDE.data[htindex],'r*')
ax1.plot(TIME[ltindex]*24.0,TIDE.data[ltindex],'b*')
for h in range(24,192,24):
ax1.axvline(h,color='gray',lw=0.5,ls='dashed',dashes=(11,5))
ax1.set_xlim(0,7*24)
ax1.set_ylabel('{0} Tidal Displacement [cm]'.format(TIDE_MODEL))
args = (YMD.year,YMD.month,YMD.day)
ax1.set_xlabel('Time from {0:4d}-{1:02d}-{2:02d} UTC [Hours]'.format(*args))
ax1.set_title(u'{0:0.6f}\u00b0N {1:0.6f}\u00b0W'.format(LAT,LON))
fig.subplots_adjust(left=0.10,right=0.98,bottom=0.10,top=0.95)
plt.show()