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