Skip to content

Commit

Permalink
test: added test for model definition files (#69)
Browse files Browse the repository at this point in the history
* test: added test for model definition files

* fix: check that compressed attr is string

* fix: use model class when retrieving files from s3
  • Loading branch information
tsutterley authored Sep 29, 2021
1 parent 8ac1574 commit 9635cbe
Show file tree
Hide file tree
Showing 20 changed files with 286 additions and 161 deletions.
7 changes: 6 additions & 1 deletion doc/source/user_guide/check_tide_points.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ valid = check_tide_points(x, y, DIRECTORY=DIRECTORY,

#### Keyword arguments
- `DIRECTORY`: working data directory for tide models
- `MODEL`: Tide model to use in correction
- `MODEL`: Tide model to use
- `ATLAS_FORMAT`: ATLAS tide model format
* `'OTIS'`
* `'netcdf'`
- `GZIP`: Tide model files are gzip compressed
- `DEFINITION_FILE`: Tide model definition file for use
- `EPSG`: input coordinate system
* default: `3031` Polar Stereographic South, WGS84
- `METHOD`: interpolation method
Expand Down
4 changes: 3 additions & 1 deletion doc/source/user_guide/compute_tide_corrections.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ tide = compute_tide_corrections(x, y, delta_time, DIRECTORY=DIRECTORY,
#### Keyword arguments
- `DIRECTORY`: working data directory for tide models
- `MODEL`: Tide model to use in correction
- `ATLAS_FORMAT`: ATLAS tide model format (`'OTIS'`, `'netcdf'`)
- `ATLAS_FORMAT`: ATLAS tide model format
* `'OTIS'`
* `'netcdf'`
- `GZIP`: Tide model files are gzip compressed
- `DEFINITION_FILE`: Tide model definition file for use as correction
- `EPOCH`: time period for calculating delta times
Expand Down
34 changes: 33 additions & 1 deletion doc/source/user_guide/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
model.py
========

Class with parameters for named tide models
Retrieves tide model parameters for named tide models and from model definition files

`Source code`__

Expand Down Expand Up @@ -61,6 +61,10 @@ General Attributes and Methods

Model grid file for ``OTIS`` and ``ATLAS`` models

.. attribute:: model.gzip

Suffix if model is compressed

.. attribute:: model.long_name

HDF5 ``long_name`` attribute string for output tide heights
Expand All @@ -85,6 +89,34 @@ General Attributes and Methods

Model scaling factor for converting to output units

.. attribute:: model.suffix

Suffix if ATLAS model is ``'netcdf'`` format

.. attribute:: model.type

Model type (``z``, ``u``, ``v``)

.. attribute:: model.verify

Verify that all model files exist

.. attribute:: model.version

Tide model version

.. method:: model.pathfinder(model_file)

Completes file paths and appends file and gzip suffixes

.. method:: model.from_file(definition_file)

Create a model object from an input definition file

.. method:: model.from_dict(d)

Create a model object from a python dictionary

.. method:: model.to_bool(val)

Converts strings of True/False to a boolean values
121 changes: 33 additions & 88 deletions pyTMD/check_tide_points.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
u"""
check_tide_points.py
Written by Tyler Sutterley (07/2021)
Written by Tyler Sutterley (09/2021)
Check if points are within a tide model domain
OTIS format tidal solutions provided by Ohio State University and ESR
Expand All @@ -17,7 +17,10 @@
OPTIONS:
DIRECTORY: working data directory for tide models
MODEL: Tide model to use in correction
MODEL: Tide model to use
ATLAS_FORMAT: ATLAS tide model format (OTIS, netcdf)
GZIP: Tide model files are gzip compressed
DEFINITION_FILE: Tide model definition file for use
EPSG: input coordinate system
default: 3031 Polar Stereographic South, WGS84
METHOD: interpolation method
Expand All @@ -40,6 +43,7 @@
https://pypi.org/project/pyproj/
PROGRAM DEPENDENCIES:
model.py: retrieves tide model parameters for named tide models
convert_ll_xy.py: convert lat/lon points to and from projected coordinates
read_tide_model.py: extract tidal harmonic constants from OTIS tide models
read_netcdf_model.py: extract tidal harmonic constants from netcdf models
Expand All @@ -48,6 +52,7 @@
bilinear_interp.py: bilinear interpolation of data to coordinates
UPDATE HISTORY:
Updated 09/2021: refactor to use model class for files and attributes
Updated 07/2021: added check that tide model directory is accessible
Updated 06/2021: add try/except for input projection strings
Written 05/2021
Expand All @@ -58,6 +63,7 @@
import pyproj
import numpy as np
import scipy.interpolate
import pyTMD.model
import pyTMD.convert_ll_xy
import pyTMD.read_tide_model
import pyTMD.read_netcdf_model
Expand All @@ -66,7 +72,9 @@
from pyTMD.bilinear_interp import bilinear_interp

# PURPOSE: compute tides at points and times using tide model algorithms
def check_tide_points(x,y,DIRECTORY=None,MODEL=None,EPSG=3031,METHOD='spline'):
def check_tide_points(x, y, DIRECTORY=None, MODEL=None,
ATLAS_FORMAT='netcdf', GZIP=False, DEFINITION_FILE=None,
EPSG=3031, METHOD='spline'):
"""
Check if points are within a tide model domain
Expand All @@ -78,7 +86,10 @@ def check_tide_points(x,y,DIRECTORY=None,MODEL=None,EPSG=3031,METHOD='spline'):
Keyword arguments
-----------------
DIRECTORY: working data directory for tide models
MODEL: Tide model to use in correction
MODEL: Tide model to use
ATLAS_FORMAT: ATLAS tide model format (OTIS, netcdf)
GZIP: Tide model files are gzip compressed
DEFINITION_FILE: Tide model definition file for use
EPSG: input coordinate system
default: 3031 Polar Stereographic South, WGS84
METHOD: interpolation method
Expand All @@ -97,77 +108,12 @@ def check_tide_points(x,y,DIRECTORY=None,MODEL=None,EPSG=3031,METHOD='spline'):
except:
raise FileNotFoundError("Invalid tide directory")

# select between tide models
if (MODEL == 'CATS0201'):
grid_file = os.path.join(DIRECTORY,'cats0201_tmd','grid_CATS')
model_format = 'OTIS'
model_EPSG = '4326'
elif (MODEL == 'CATS2008'):
grid_file = os.path.join(DIRECTORY,'CATS2008','grid_CATS2008')
model_format = 'OTIS'
model_EPSG = 'CATS2008'
elif (MODEL == 'TPXO9-atlas'):
grid_file = os.path.join(DIRECTORY,'TPXO9_atlas','grid_tpxo9_atlas.nc.gz')
model_format = 'netcdf'
elif (MODEL == 'TPXO9-atlas-v2'):
grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v2','grid_tpxo9_atlas_30_v2.nc.gz')
model_format = 'netcdf'
elif (MODEL == 'TPXO9-atlas-v3'):
grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v3','grid_tpxo9_atlas_30_v3.nc.gz')
model_format = 'netcdf'
elif (MODEL == 'TPXO9-atlas-v4'):
grid_file = os.path.join(DIRECTORY,'TPXO9_atlas_v4','grid_tpxo9_atlas_30_v4')
model_format = 'OTIS'
model_EPSG = '4326'
elif (MODEL == 'TPXO9.1'):
grid_file = os.path.join(DIRECTORY,'TPXO9.1','DATA','grid_tpxo9')
model_format = 'OTIS'
model_EPSG = '4326'
elif (MODEL == 'TPXO8-atlas'):
grid_file = os.path.join(DIRECTORY,'tpxo8_atlas','grid_tpxo8atlas_30_v1')
model_format = 'ATLAS'
model_EPSG = '4326'
elif (MODEL == 'TPXO7.2'):
grid_file = os.path.join(DIRECTORY,'TPXO7.2_tmd','grid_tpxo7.2')
model_format = 'OTIS'
model_EPSG = '4326'
elif (MODEL == 'AODTM-5'):
grid_file = os.path.join(DIRECTORY,'aodtm5_tmd','grid_Arc5km')
model_format = 'OTIS'
model_EPSG = 'PSNorth'
elif (MODEL == 'AOTIM-5'):
grid_file = os.path.join(DIRECTORY,'aotim5_tmd','grid_Arc5km')
model_format = 'OTIS'
model_EPSG = 'PSNorth'
elif (MODEL == 'AOTIM-5-2018'):
grid_file = os.path.join(DIRECTORY,'Arc5km2018','grid_Arc5km2018')
model_format = 'OTIS'
model_EPSG = 'PSNorth'
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_format = 'GOT'
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_format = 'GOT'
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_format = 'GOT'
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_format = 'FES'
#-- 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)

# input shape of data
idim = np.shape(x)
Expand All @@ -184,39 +130,38 @@ def check_tide_points(x,y,DIRECTORY=None,MODEL=None,EPSG=3031,METHOD='spline'):
np.atleast_1d(y).flatten())

# read tidal constants and interpolate to grid points
if model_format in ('OTIS','ATLAS'):
if model.format in ('OTIS','ATLAS'):
# if reading a single OTIS solution
xi,yi,hz,mz,iob,dt = pyTMD.read_tide_model.read_tide_grid(grid_file)
xi,yi,hz,mz,iob,dt = pyTMD.read_tide_model.read_tide_grid(model.grid_file)
# invert model mask
mz = np.logical_not(mz)
# adjust dimensions of input coordinates to be iterable
# run wrapper function to convert coordinate systems of input lat/lon
X,Y = pyTMD.convert_ll_xy(lon,lat,model_EPSG,'F')
elif (model_format == 'netcdf'):
X,Y = pyTMD.convert_ll_xy(lon,lat,model.projection,'F')
elif (model.format == 'netcdf'):
# if reading a netCDF OTIS atlas solution
xi,yi,hz = pyTMD.read_netcdf_model.read_netcdf_grid(grid_file,
GZIP=True, TYPE='z')
xi,yi,hz = pyTMD.read_netcdf_model.read_netcdf_grid(model.grid_file,
GZIP=model.compressed, TYPE=model.type)
# copy bathymetry mask
mz = np.copy(hz.mask)
# copy latitude and longitude and adjust longitudes
X,Y = np.copy([lon,lat]).astype(np.float64)
lt0, = np.nonzero(X < 0)
X[lt0] += 360.0
elif (model_format == 'GOT'):
elif (model.format == 'GOT'):
# if reading a NASA GOT solution
input_file = os.path.join(model_directory,model_files[0])
hc,xi,yi,c = pyTMD.read_GOT_model.read_GOT_grid(input_file, GZIP=True)
hc,xi,yi,c = pyTMD.read_GOT_model.read_GOT_grid(model.model_file[0],
GZIP=model.compressed)
# copy tidal constituent mask
mz = np.copy(hc.mask)
# copy latitude and longitude and adjust longitudes
X,Y = np.copy([lon,lat]).astype(np.float64)
lt0, = np.nonzero(X < 0)
X[lt0] += 360.0
elif (model_format == 'FES'):
elif (model.format == 'FES'):
# if reading a FES netCDF solution
input_file = os.path.join(model_directory,model_files[0])
hc,xi,yi = pyTMD.read_FES_model.read_netcdf_file(input_file,GZIP=True,
TYPE='z',VERSION='FES2014')
hc,xi,yi = pyTMD.read_FES_model.read_netcdf_file(model.model_file[0],
GZIP=model.compressed, TYPE=model.type, VERSION=model.version)
# copy tidal constituent mask
mz = np.copy(hc.mask)
# copy latitude and longitude and adjust longitudes
Expand Down
1 change: 1 addition & 0 deletions pyTMD/compute_tide_corrections.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
PROGRAM DEPENDENCIES:
time.py: utilities for calculating time operations
model.py: retrieves tide model parameters for named tide models
spatial: utilities for reading, writing and operating on spatial data
utilities.py: download and management utilities for syncing files
calc_astrol_longitudes.py: computes the basic astronomical mean longitudes
Expand Down
Loading

0 comments on commit 9635cbe

Please sign in to comment.