GithubHelp home page GithubHelp logo

tsutterley / pytmd Goto Github PK

View Code? Open in Web Editor NEW
104.0 9.0 34.0 15.1 MB

Python-based tidal prediction software

Home Page: https://pytmd.readthedocs.io

License: MIT License

Python 91.74% Jupyter Notebook 8.26%
tides geodesy geophysics oceanography

pytmd's Introduction

pyTMD

Language License PyPI Version Anaconda-Server Documentation Status codecov zenodo

Python-based tidal prediction software for estimating ocean, load, solid Earth and pole tides

Ocean and load tidal predictions using OTIS, GOT and FES formatted tidal solutions

Radial solid Earth and pole tide displacements following IERS conventions

Dependencies

References

T. C. Sutterley, T. Markus, T. A. Neumann, M. R. van den Broeke, J. M. van Wessem, and S. R. M. Ligtenberg, "Antarctic ice shelf thickness change from multimission lidar mapping", The Cryosphere, 13, 1801-1817, (2019). doi: 10.5194/tc-13-1801-2019

L. Padman, M. R. Siegfried, H. A. Fricker, "Ocean Tide Influences on the Antarctic and Greenland Ice Sheets", Reviews of Geophysics, 56, 142-184, (2018). doi: 10.1002/2016RG000546

Download

The program homepage is:
https://github.com/tsutterley/pyTMD
A zip archive of the latest version is available directly at:
https://github.com/tsutterley/pyTMD/archive/main.zip

Software

Matlab Tide Model Driver from Earth & Space Research is available at:
https://github.com/EarthAndSpaceResearch/TMD_Matlab_Toolbox_v2.5
Fortran OSU Tidal Prediction Software OTPS is available at:
https://www.tpxo.net/otps
Incorporated into the NASA Cryosphere Altimetry Processing Toolkit at:
https://github.com/fspaolo/captoolkit

Disclaimer

This package includes software developed at NASA Goddard Space Flight Center (GSFC) and the University of Washington Applied Physics Laboratory (UW-APL). It is not sponsored or maintained by the Universities Space Research Association (USRA), AVISO or NASA. The software is provided here for your convenience but with no guarantees whatsoever. It should not be used for coastal navigation or any application that may risk life or property.

Credits

This project contains work and contributions from the scientific community. The Tidal Model Driver (TMD) Matlab Toolbox was developed by Laurie Padman, Lana Erofeeva and Susan Howard. The OSU Tidal Inversion Software (OTIS) and OSU Tidal Prediction Software (OTPS) were developed by Lana Erofeeva and Gary Egbert (copyright OSU, licensed for non-commercial use). The NASA Goddard Space Flight Center (GSFC) PREdict Tidal Heights (PERTH3) software was developed by Richard Ray and Remko Scharroo.

License

The content of this project is licensed under the Creative Commons Attribution 4.0 Attribution license and the source code is licensed under the MIT license.

pytmd's People

Contributors

github-actions[bot] avatar tsutterley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytmd's Issues

Interpolation `METHOD="spline"` fails for TPXO8

Issue

I can easily model tides for TPXO8 using "bilinear" interpolation:

import numpy as np
import pandas as pd
from pyTMD import compute_tide_corrections

compute_tide_corrections(
    x=np.linspace(155, 160, 10),
    y=np.linspace(-30, -40, 10),
    delta_time=pd.date_range("2020-01", "2020-02", periods=10),
    DIRECTORY="/home/jovyan/tide_models_clipped",
    MODEL="TPXO8-atlas",
    EPSG=4326,
    TYPE="drift",
    TIME="datetime",
    METHOD="bilinear",
)

However, if I try the same code with "spline" interpolation (the default), this fails with ValueError: x dimension of z must have same number of elements as x:

compute_tide_corrections(
    x=np.linspace(155, 160, 10),
    y=np.linspace(-30, -40, 10),
    delta_time=pd.date_range("2020-01", "2020-02", periods=10),
    DIRECTORY="/home/jovyan/tide_models_clipped",
    MODEL="TPXO8-atlas",
    EPSG=4326,
    TYPE="drift",
    TIME="datetime",
    METHOD="spline",
)

Other models work fine with "spline" interpolation, e.g. FES2014:

compute_tide_corrections(
    x=np.linspace(155, 160, 10),
    y=np.linspace(-30, -40, 10),
    delta_time=pd.date_range("2020-01", "2020-02", periods=10),
    DIRECTORY="/home/jovyan/tide_models_clipped",
    MODEL="FES2014",
    EPSG=4326,
    TYPE="drift",
    TIME="datetime",
    METHOD="spline",
)

Expected outcome

All supported tide models can be run with the default "spline" interpolation method without raising errors.

Details

I'm using pyTMD=2.0.7 and scipy=1.10.1. Full error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[23], line 1
----> 1 compute_tide_corrections(
      2     x=np.linspace(155, 160, 10),
      3     y=np.linspace(-30, -40, 10),
      4     delta_time=pd.date_range("2020-01", "2020-02", periods=10),
      5     DIRECTORY="/home/jovyan/tide_models_clipped",
      6     MODEL="TPXO8-atlas",
      7     EPSG=4326,
      8     TYPE="drift",
      9     TIME="datetime",
     10     METHOD="spline",
     11 )

File /env/lib/python3.8/site-packages/pyTMD/compute_tide_corrections.py:318, in compute_tide_corrections(x, y, delta_time, DIRECTORY, MODEL, ATLAS_FORMAT, GZIP, DEFINITION_FILE, EPSG, EPOCH, TYPE, TIME, METHOD, EXTRAPOLATE, CUTOFF, APPLY_FLEXURE, FILL_VALUE, **kwargs)
    316 # read tidal constants and interpolate to grid points
    317 if model.format in ('OTIS','ATLAS','TMD3'):
--> 318     amp,ph,D,c = pyTMD.io.OTIS.extract_constants(lon, lat, model.grid_file,
    319         model.model_file, model.projection, type=model.type,
    320         method=METHOD, extrapolate=EXTRAPOLATE, cutoff=CUTOFF,
    321         grid=model.format, apply_flexure=APPLY_FLEXURE)
    322     # use delta time at 2000.0 to match TMD outputs
    323     deltat = np.zeros((nt), dtype=np.float64)

File /env/lib/python3.8/site-packages/pyTMD/io/OTIS.py:410, in extract_constants(ilon, ilat, grid_file, model_file, EPSG, **kwargs)
    407     hci.data[hci.mask] = hci.fill_value
    408 elif (kwargs['method'] == 'spline'):
    409     # use scipy bivariate splines to interpolate values
--> 410     hci = pyTMD.interpolate.spline(xi, yi, hc, x, y,
    411         dtype=hc.dtype,
    412         reducer=np.ceil,
    413         kx=1, ky=1)
    414     # replace zero values with fill_value
    415     hci.mask |= D.mask

File /env/lib/python3.8/site-packages/pyTMD/interpolate.py:172, in spline(ilon, ilat, idata, lon, lat, fill_value, dtype, reducer, **kwargs)
    170 # construct splines for input data and mask
    171 if np.iscomplexobj(idata):
--> 172     s1 = scipy.interpolate.RectBivariateSpline(ilon, ilat,
    173         idata.data.real.T, **kwargs)
    174     s2 = scipy.interpolate.RectBivariateSpline(ilon, ilat,
    175         idata.data.imag.T, **kwargs)
    176     s3 = scipy.interpolate.RectBivariateSpline(ilon, ilat,
    177         idata.mask.T, **kwargs)

File /env/lib/python3.8/site-packages/scipy/interpolate/_fitpack2.py:1494, in RectBivariateSpline.__init__(self, x, y, z, bbox, kx, ky, s)
   1492     raise ValueError('y must be strictly increasing')
   1493 if not x.size == z.shape[0]:
-> 1494     raise ValueError('x dimension of z must have same number of '
   1495                      'elements as x')
   1496 if not y.size == z.shape[1]:
   1497     raise ValueError('y dimension of z must have same number of '
   1498                      'elements as y')

ValueError: x dimension of z must have same number of elements as x

Error on import

Hello, just to let you know that, installing from conda and trying to run the "Plot Tidal Forecasts at a Location" example, the pyTMD.tools module is not found.
Trying to troubleshoot now, but I am not sure what to do.

Inconsistency between GDAL and PROJ dependencies

Hi,

I am trying to install pyTMD by the source code on a conda environment, but I am having some problems with the dependencies of the project.

First, I created a new conda environment, ran conda install python=3.8.12 (to install Python 3.8), and executed python setup.py install. The last command caused the following error: [Errno 2] No such file or directory: 'gdal-config'\n\nCould not find gdal-config. Make sure you have installed the GDAL native library and development headers.').

I assumed this problem occurred because I had not installed GDAL on the conda environment yet. So, I ran conda install gdal and then executed python setup.py install again. This time, I have gotten the error:

Running Cartopy-0.20.2/setup.py -q bdist_egg --dist-dir /tmp/easy_install-368fd3wt/Cartopy-0.20.2/egg-dist-tmp-obj9zsyp
Proj version 6.2.1 is installed, but cartopy requires at least version 8.0.0.
error: Setup script exited with 1

In order to install the correct version of proj, I ran conda search proj and found out that the only available versions greater than 8.0.0 are 8.0.1 and 8.2.1. But, when I try to install PROJ with one of those versions (using conda install proj=8.0.1, for example) I allways get an inconsistency between proj and gdal.

I have tried to solve this problem in many ways but I have not been successful.

I know I can try to install pyTMD using conda-forge but, due to the way I want to use the project, it would be much better if I could install it from the source code.

Thank you very much in advance for all your help!

How to get extract tidal constants with OTIS format tidal solutions

Hi, sorry to bother, I'm new in this area and found this library amazing, I'm figuring out how to use it.

I'm trying to extract tidal constants with this function in PyTMD: extract_tidal_constants.

I downloaded the OTIS format tidal solutions there: http://people.oregonstate.edu/~erofeevs/

The specific data used is "East Coast of America 1/30º"

Code as follows:

from pyTMD import read_tide_model

grid_file = "F:/Z-Main Affairs(USA)/US Stusy/PyTMD/historical data/EC/DATA/grid_EC"
model_file = "F:/Z-Main Affairs(USA)/US Stusy/PyTMD/historical data/EC/DATA/Model_EC"
EPSG = "4326"
ilon = "-73.935242"
ilat = "40.730610"
amp,ph,D,c = read_tide_model.extract_tidal_constants(ilon, ilat, grid_file, model_file, EPSG,
                             TYPE=type, METHOD='spline', GRID='OTPS')
print("amp: ",amp)
print("ph: ",ph)
print("D: ",D)
print("c: ",c)

Console error info:

C:\Users\tonys\Anaconda3\envs\Tide_scratch2\lib\site-packages\pyTMD\read_tide_model.py:596: RuntimeWarning: overflow encountered in long_scalars
  constituents = [c.decode("utf-8").rstrip() for c in fid.read(nc*4).split()]
Traceback (most recent call last):
  File "F:/pycharm-workspace/Tide_scratch/main.py", line 21, in <module>
    TYPE=type, METHOD='spline', GRID='OTPS')
  File "C:\Users\tonys\Anaconda3\envs\Tide_scratch2\lib\site-packages\pyTMD\read_tide_model.py", line 223, in extract_tidal_constants
    constituents,nc = read_constituents(model_file)
  File "C:\Users\tonys\Anaconda3\envs\Tide_scratch2\lib\site-packages\pyTMD\read_tide_model.py", line 596, in read_constituents
    constituents = [c.decode("utf-8").rstrip() for c in fid.read(nc*4).split()]
ValueError: read length must be non-negative or -1

Process finished with exit code 1

Some questions about the input parameter:

  • model_file/grid_file: There are two binary data files in one data package: h_EC2010 and UV_2010. Should I use one of them as model_file? Or using the Moudel_EC file which is the path info of those two files.

  • EPSG : Which EPSG should I use for OTIS format tidal solutions.

  • ilon/ilat: Should be str or float? Or should I write an array of longitudes and latitudes in a file?

I know those questions are basic and maybe a waste of your time to answer it, but they did trouble me a couple of days. If you can give answers or provide a complete example code to show me how to use it, will be appreciated! Thanks in advance!

Weird behaviour in bilinear_interp.py

Issue one:
np.nonzero returns a tuple of 2 np.array to represent the indices.
in line 63 of bilinear_interp.py, there is an extra , behind the assignment.
This causes the output of the tuple to be unpacked into 2 variables, one of them being always empty.
As each "row" of the indices are the length of the flattened array, as shown in the usage in line 75,76 it can be used to extract from tuple elegantly, however at this line this causes the following Error:
ValueError: operands could not be broadcast together with shapes ( lon , ) ( ilon * ilat , ilat)

Proposed "Fix" :
Removing the , makes the function execute pass this line

Issue two:
in line 66 to 68 , the array data is created using the shape npts, which when applied to a 2d numpy matrix, only shows part of its shape.
e.g. 1000 x 500 matrix would have a len() of 1000 only, this then would produce a 1d array used to store data. This would then cause another error of non-broadcastable shapes:
e.g.
ValueError: could not broadcast input array from shape ( x , y ) into shape ( x ,)

Unable to compute current data using extract_tidal_constants

Hi,

Really appreciate your work with this as the Matlab TMD package has been the only reason I've kept Matlab installed for the past 3 years.

I have no problems getting elevations using this function, but I don't get anything meaningful when I try to get currents, e.g.

lat = [-66.2]
lon = [71.45]

model_grid = '/Users/.../py_nb/TIDES/CATS2008/grid_CATS2008'
model_elevation = '/Users/.../py_nb/TIDES/CATS2008/hf.CATS2008.out'
model_current = '/Users/.../py_nb/TIDES/CATS2008/uv.CATS2008.out'

amp,ph,D,c = extract_tidal_constants(lon, lat, model_grid, model_elevation, 'CATS2008', type='z',
            method='spline', grid='OTIS', extrapolate=True)
print('elevation: ', np.round(D), amp[:,0], amp[:,4])

amp,ph,D,c = extract_tidal_constants(lon, lat, model_grid, model_current, 'CATS2008', type='u', 
           method='spline', grid='OTIS')
print('current (u):', np.round(D), amp[:,0], amp[:,4])

which outputs:

elevation:  [2320.] [0.1318957358598709] [0.22610248625278473]
current (u): [2320.] [--] [--]

Not sure if this is a bug or a mistake on my part? But I seem to have the same issue with the "Plot Antarctic Tidal Currents" notebook.

Cheers

Issue with Iterating Over Model Files in pyTMD.io.ATLAS.extract_constants()

Description:
I have encountered an issue in the extract_constants function in pyTMD.io.ATLAS, specifically when using the 'TPXO9-atlas-v2' model for currents. In previous versions, the function iterated over a list of model files directly, while in the latest version, it iterates over the keys ("u" and "v") of a dictionary containing the model files. This change causes the function to incorrectly loop over the dictionary keys instead of the actual files.

Affected Code:
The relevant code snippets in the latest version looks like this:
# number of constituents nc = len(model_files)

for i, model_file in enumerate(model_files):

Proposed Fix:
I have found that these corrections fix this issue, at least in my specific case.
The loop should iterate over the list of model files corresponding to the specified type. The modified snippets should be:
# number of constituents nc = len(model_files[kwargs['type']])

for i, model_file in enumerate(model_files[kwargs['type']]):

These changes ensure that the function correctly calculates the number of constituents and iterates over the actual files associated with the specified type.

Steps to Reproduce:

  1. Use a 'TPXO9-atlas-v2' currents model.
    model = pyTMD.io.model(tpxodirectory).current('TPXO9-atlas-v2')
  2. Call the extract_constants function, specifying 'u' or 'v' as the type.
    (amplitude, phase, D, constituents) = extract_constants(ilon, ilat, model.grid_file, model.model_file, type="u")

Expected Result:
The function should iterate over the list of model files for the specified type.

Actual Result:
The function currently iterates over the dictionary keys, causing a FileNotFoundError.

Additional Information:

  • pyTMD version: 2.0.8
  • Model: 'TPXO9-atlas-v2' currents
  • Type: 'u' or 'v'

Thank you for your attention to this matter.

Best regards,
Mirko.

setting directory and model

Hi Tyler,

I managed to install pyTMD on my MacBook. Now, I'm trying to run the first tutorial to calculate the tidal displacements for a given location. Importing the modules went fine. However, I can't make it through the TMDwidgets = pyTMD.tools.widgets() I keep getting an error as below:

TraitError: The 'value' trait of a Text instance expected a unicode string, not the PosixPath PosixPath('/Users/mohammad/Documents/GitHub/pyTMD-main').

I appreciate any help from your side to overcome this problem.

Compute u and v velocities for TPXO9-atlas

Thank you for sharing this conversion of the TMD to python.

I think that extraction of velocities is not described in your codes but, Do you know if the code will work using velocities if I refer type=u and select the correct UV_* source files?

I need to extract TPXO9-atlas currents for spatial domains over months and I need some quick solution to do this in python.

Thank you in advance!

Suggestion: show tidal models in help

This is a suggestion regarding the script-API, eg compute_tidal_elevations.py
It falls squarely in "nice-to-have", so no rush to implement. This is not a bug report.

The --help for --tide/-T does not show the (hard-coded) choices, which are available.

It is possible to get the list if a wrong value is given on purpose, for instance:

python3 compute_tidal_elevations.py . . . --tide=BUMMER . . 
. . .
usage: compute_tidal_elevations.py [-h] [--directory DIRECTORY] [--tide TIDE] [--atlas-format {OTIS,netcdf}]
                                   [--gzip] [--definition-file DEFINITION_FILE]
                                   [--format {csv,netCDF4,HDF5,geotiff}]
                                   [--variables VARIABLES [VARIABLES ...]] [--header HEADER]
                                   [--delimiter DELIMITER] [--type {drift,grid}] [--epoch EPOCH]
                                   [--deltatime DELTATIME [DELTATIME ...]]
                                   [--standard {UTC,GPS,TAI,LORAN,datetime}] [--projection PROJECTION]
                                   [--interpolate METHOD] [--extrapolate] [--cutoff CUTOFF]
                                   [--apply-flexure] [--verbose] [--mode MODE]
                                   [infile] [outfile]
compute_tidal_elevations.py: error: argument --tide/-T: invalid choice: 'BUMMER' (choose from 'AODTM-5', 'AOTIM-5', 'AOTIM-5-2018', 'Arc2kmTM', 'CATS0201', 'CATS2008', 'CATS2008_load', 'CATS2022', 'EOT20', 'EOT20_load', 'FES2014', 'FES2014_load', 'GOT4.10', 'GOT4.10_load', 'GOT4.7', 'GOT4.7_load', 'GOT4.8', 'GOT4.8_load', 'Gr1km-v2', 'Gr1kmTM', 'TPXO7.2', 'TPXO7.2_load', 'TPXO8-atlas', 'TPXO9-atlas', 'TPXO9-atlas-v2', 'TPXO9-atlas-v3', 'TPXO9-atlas-v4', 'TPXO9-atlas-v5', 'TPXO9.1')

I would find it helpful, if the choices were shown as part of the help.
One way to d it is to change the definition of the tide-option to eg:

    group.add_argument('--tide','-T',
                       metavar='TIDE', type=str,
                       choices=choices,
                       help=f'Tide model to use in correction. Choose from: {", ".join(choices)}')

It will then output (on --help) eg

  --tide TIDE, -T TIDE  Tide model to use in correction. Choose from: AODTM-5, AOTIM-5, AOTIM-5-2018,
                        Arc2kmTM, CATS0201, CATS2008, CATS2008_load, CATS2022, EOT20, EOT20_load, FES2014,
                        FES2014_load, GOT4.10, GOT4.10_load, GOT4.7, GOT4.7_load, GOT4.8, GOT4.8_load,
                        Gr1km-v2, Gr1kmTM, TPXO7.2, TPXO7.2_load, TPXO8-atlas, TPXO9-atlas, TPXO9-atlas-v2,
                        TPXO9-atlas-v3, TPXO9-atlas-v4, TPXO9-atlas-v5, TPXO9.1

Just a suggestion,
/Bajrne

Casting complex values to real discards the imaginary part

Hello,

First of all, thanks a lot for the tool !
I'm a new user of pyTMD and a novice in tidal prediction so please excuse me in advance if my question is not clear.

I'm using the FS2014 model (fes2014/ocean_tide data) to predict tide elevation at 1 specific location and for 1 specific datetime.
The obtained prediction results look good (and relatively close (~10cm) to local tide charts).

However, during the extract_FES_constants, a python warning is raised :

venv/lib/python3.7/site-packages/numpy/ma/core.py:462: ComplexWarning: Casting complex values to real discards the imaginary part
fill_value = np.array(fill_value, copy=False, dtype=ndtype)

I'm not sure how to handle this.
How to fix it ? Should I worry about the quality of the prediction ?

Many thanks,
Alexandre

From barotropic velocity to surface velocity

Dear all,
I have more of a theoretical question.
pyTMD, as far as I understood, provides the tidal current barotropic velocity. i.e. approximately equal to the dapth-averaged velocity.

The question is: does anyone know a methodology to derive, from the barotropic velocity, the surface tidal current velocity? It does not need to be super-accurate, since it is for a conceptual/preliminary design.

The only reference to this I found is in DNV-RP-C205, section 4.1.4.2:
When detailed field measurements are not available the variation in shallow of tidal current velocity water with depth may be modelled as a simple power law, assuming uni-directional current

but it does not seem to suggest a typical value for the alpha exponend in the in case data are not available to determine this parameter.

Many thanks

Windows builds

Fixing the GDAL issues with Windows

Creating a working windows test build in GitHub actions

pyTMD.io.model not working for current with FES2014

Hello,

Thanks for this fantastic library.

Trying to load velocity data from FES2014 using :

model = pyTMD.io.model('/data/DATASETS/FES2014/',
    format='netcdf',
    compressed=False
   ).current('FES2014')

Leads to an error line 1232 in io/model.py

I had to modify the code to get it working properly :

            for key,val in model_directory.items():                                                                                                                                                                
                self.model_directory = os.path.expanduser(model_directory[key])                                                                                                                                    
                self.model_file[key] = self.pathfinder(val)                                                                                                                                                        

adding the missing [key] argument to os.path.expanduser(model_directory)

Then it works fine.

FileNotFoundError

I am trying to follow Plot Tide Forecasts.ipynb notebook for obtaining earth and ocean tides times series at a certain inland point at the Canary Islands, and for a determined period range. Nevertheless, it is being a bit hard to understand how the program works and the inputs it requieres.

I have downloaded the EOT20 model data, since I think could be the most updated model within the area, and have linked it to the dir path in the widget box of the notebook -adding also the spatial coordinates of the desired point.

After executting the next cell for getting model parameters and creating plot with tidal displacements, aFileNotFoundError: is shown, not being able the program to find the model files.

I dont know if I am doing the right thing. I miss some documentation on how the ocean tide models are configured and how are used the functions and classes of the program.

Any help on this is welcome. Thanks by advance.

Cell In[6], line 7
      1 get_ipython().run_line_magic('matplotlib', 'widget')
      3 # get model parameters
      4 model = pyTMD.io.model(TMDwidgets.directory.value,
      5     format=TMDwidgets.atlas.value,
      6     compressed=TMDwidgets.compress.value
----> 7    ).elevation(TMDwidgets.model.value)
      9 # convert from calendar date to days relative to Jan 1, 1992 (48622 MJD)
     10 YMD = TMDwidgets.datepick.value

File ~\miniconda3\envs\pytmd\Lib\site-packages\pyTMD\io\model.py:628, in model.elevation(self, m)
    617 self.model_directory = self.directory.joinpath(
    618     'EOT20','ocean_tides')
    619 model_files = ['2N2_ocean_eot20.nc','J1_ocean_eot20.nc',
    620     'K1_ocean_eot20.nc','K2_ocean_eot20.nc',
    621     'M2_ocean_eot20.nc','M4_ocean_eot20.nc',
   (...)
    626     'SA_ocean_eot20.nc','SSA_ocean_eot20.nc',
    627     'T2_ocean_eot20.nc']
--> 628 self.model_file = self.pathfinder(model_files)
    629 self.constituents = ['2n2','j1','k1','k2','m2','m4',
    630     'mf','mm','n2','o1','p1','q1','s1','s2','sa',
    631     'ssa','t2']
    632 self.scale = 1.0/100.0

File ~\miniconda3\envs\pytmd\Lib\site-packages\pyTMD\io\model.py:1231, in model.pathfinder(self, model_file)
   1229 # check that (all) output files exist
   1230 if self.verify and not valid:
-> 1231     raise FileNotFoundError(output_file)
   1232 # return the complete output path
   1233 return output_file

FileNotFoundError: [WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/2N2_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/J1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/K1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/K2_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/M2_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/M4_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/MF_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/MM_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/N2_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/O1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/P1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/Q1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/S1_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/S2_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/SA_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/SSA_ocean_eot20.nc'), WindowsPath('C:/Users/MiguelGJ/Downloads/borrar/EOT20/ocean_tides/EOT20/ocean_tides/T2_ocean_eot20.nc')]```

TypeError: extract_FES_constants() got multiple values for argument 'TYPE'

Hello,

Thanks again for the great work with this package !

I'm using pyTMD from a pip install.
Recently, I installed the latest version :

pip install pyTMD==1.0.2.18

But an error is now raised when extracting FES constants :

---------------------------------------------------------------------------`
TypeError                                 Traceback (most recent call last)
<ipython-input-3-f7f0e7858d5d> in <module>
     39 #-- read tidal constants and interpolate to grid points
     40 if (model_format == 'FES'):
---> 41     amp,ph = extract_FES_constants(np.array([LON]), np.array([LAT]), model_directory, model_files, TYPE=TYPE, VERSION=TIDE_MODEL, METHOD='spline', SCALE=SCALE)
     42 
     43     #-- interpolate delta times from calendar dates to tide time
TypeError: extract_FES_constants() got multiple values for argument 'TYPE'

I reverted back to the previous version pip install pyTMD==1.0.2.17 : works fine.

Alex

How to get a datum and a datum value?

Hello everybody. I'm new to tide prediction and have no idea what I'm doing :). I just had this crazy idea to try to create a Tide app for iOS and since then I have been playing with XTide. I'm trying to get the harmonics for my location with pyTMD to use on XTide. This is what I have so far: https://colab.research.google.com/drive/1CwNd0J0w_8of11B1cPLugUs_8NxjcG-2

How can I get a datum and its value from FES2014 or EOT20?

Sorry for posting this kind of question here. I didn't find a more appropriate place.
Thank you for this splendid library.

TypeError: combine_atlas_model() got an unexpected keyword argument 'variable'

Hi @tsutterley, I've been getting this error when trying to model tides using TPXO8-atlas on 1.1.1:

~/Robbi/dea-notebooks/Frequently_used_code/../Tools/dea_tools/coastal.py in model_tides(x, y, time, model, directory, epsg, method, extrapolate, cutoff)
    792     # Read tidal constants and interpolate to grid points
    793     if model.format in ("OTIS", "ATLAS"):
--> 794         amp, ph, D, c = extract_tidal_constants(
    795             lon,
    796             lat,

/env/lib/python3.8/site-packages/pyTMD/read_tide_model.py in extract_tidal_constants(ilon, ilat, grid_file, model_file, EPSG, **kwargs)
    318             if (kwargs['grid'] == 'ATLAS'):
    319                 z0,zlocal = read_atlas_elevation(model_file, i, c)
--> 320                 xi,yi,z = combine_atlas_model(x0, y0, z0, pmask, zlocal,
    321                     variable='z')
    322             elif (kwargs['grid'] == 'ESR'):

TypeError: combine_atlas_model() got an unexpected keyword argument 'variable'

This only occurs in versions > 1.0.6. I think it may be because the extract_tidal_constants code here passes a lowercase variable param to the combine_atlas_model func:
https://github.com/tsutterley/pyTMD/blob/main/pyTMD/read_tide_model.py#L330-L331
https://github.com/tsutterley/pyTMD/blob/main/pyTMD/read_tide_model.py#L399-L400
https://github.com/tsutterley/pyTMD/blob/main/pyTMD/read_tide_model.py#L465-L466

But combine_atlas_model actually accepts an all-caps param VARIABLE:
https://github.com/tsutterley/pyTMD/blob/main/pyTMD/read_tide_model.py#L1259

(it's correctly passed here: https://github.com/tsutterley/pyTMD/blob/main/pyTMD/read_tide_model.py#L211)

Longitude convention in tide models

I have a tiny suggestion for a change in the code of read_FES_model.py (and maybe also for similar other read_XXX_model.py).

In short, I suggest to remove (at l.132ff)

    #-- adjust longitudinal convention of input latitude and longitude
    #-- to fit tide model convention
    if (np.min(ilon) < 0.0):
        lt0, = np.nonzero(ilon < 0)
        ilon[lt0] += 360.0

and replace it by (at l.163 )

    #-- adjust longitudinal convention of input latitude and longitude
    #-- to fit tide model convention
    if(np.max(lon)>180. and np.min(ilon)<0.):         # nc: [0 - 360], points: [-180 - 180]
        ilon[ilon<0.] += 360.
    elif(np.min(lon)<0. and np.max(ilon)>180.):       # nc: [-180 - 180], points: [0 - 360]
        ilon[ilon>180.] -= 360.

So, instead of assuming that all NC-grids are [0 - 360], it will check the input data and the points and convert the points accordingly.
Surely, the FES data comes as [0 - 360], so the previous code works fine. However, I work with a modified version (explained below), therefore I need these changes and suggest to include them in your version as well.

My situation is as follows (sorry for the long text but I would like to explain why I ask for this change):

I want to calculate FES-tides for a few points. This is done nicely by pyTMD but it takes quite long (on my machine almost 2min for each call of extract_FES_constans). I have searched the code for what takes so long and found out that the reason is that pyTMD first reads the entire grids for all constituents into RAM before interpolating the specific point(s) data.
My first intention was that the code should maybe not read the entire grids if the requested point(s) are limited to a quite small area. However, I understand that interpolation/extrapolation needs at least a limited region around the point and if the points are located around the Greenwich meridian this can be quite complicated (I'm working with points in the North Sea).
Therefore I have another approach to solve this. I have extracted the region of northern Europe from the FES-NetCDFs to separate NCs, which are smaller and, hence, way faster to read (~5 sec). However, the is the problem with the Greenwich meridian. The original FES data longitudes range from 0°-360°. For northern Europe, this means that I need 355°-360° and 0°-30°. Extracting these two regions and joining them in a new NC causes makes Scipy.interpolate crash (ValueError: The points in dimension 1 must be strictly ascending). Therefore I converted the western hemisphere longitudes to negative values. My longitudes in the NCs are now -5°-30°. To work with such modified data, I need the modifications as suggested above. If you would include these changes, you would never have to care about longitude conventions any more.

Wrong unit in extrapolate

Hi,
first of all thanks for this great library. I'm new in working with ocean data and was quite surprised that apparently all the few other tidal prediction libraries out there seem to be outdated.

I think I've found a bug in your code. I've never uploaded something in Github, so I will just explain what I've found:
Your read_*_model.py modules have an option EXTRAPOLATE to predict tides where the models are undefined. In the code, there is a hardcoded upper bound of 10km for extrapolation. However, in nearest_extrap.py by default (EPSG=='4326'), the KDTree is build using carthesian coordinates [m]. Hence, on line 127, the tree.query is indeed cutoff after 10m, not 10km.

Moreover, I suggest to at least mention the hardcoded 10km cutoff in the header description of EXTRAPOLATE in read_*_model.py. Even better, this could be made an additional option...

Cheers,
Ludwig

Netcdf time needs to be double

When compute_tidal_elevations.py is used to create netcdf output, time is defined as a float (4-byte, NCFLOAT), using units:
time:units = "days since 1992-01-01T00:00:00" ;
Unfortunately, the default float does not contain enough accuracy for this process. At present time (>30 years after 1992-01-01), most of the significant digits are used on the days-part (integer part), leaving only about 2 digits for time-of-day.
For instance, when I define (input) time as every 10 minutes for an hour of 2023-01-30 (using another time:units), the values are correctly read and converted, but upon output the time values are:
time = 10622, 10622.01, 10622.01, 10622.02, 10622.03, 10622.04, 10622.04 ;
There is a clear loss of accuracy going on.
Other coordinate variables (x,y) are already defined as double. It is necessary that time be defined as double as well.

Thank you, Bjarne

Can't reshape array of data file in plot tide forecasts #123

Hi @tsutterley, i got this error when trying to run pyTMD/notebooks/Plot Tide Forecasts.ipynb

ValueError                                Traceback (most recent call last)
Cell In [7], line 23
     21 # read tidal constants and interpolate to leaflet points
     22 if model.format in ('OTIS','ATLAS','ESR'):
---> 23     amp,ph,D,c = extract_tidal_constants(np.atleast_1d(LON),
     24         np.atleast_1d(LAT), model.grid_file, model.model_file,
     25         model.projection, type=model.type, method='spline',
     26         extrapolate=True, grid=model.format)
     27     DELTAT = np.zeros_like(tide_time)
     28 elif (model.format == 'netcdf'):

File c:\users\admin\appdata\local\programs\python\python39\lib\site-packages\pyTMD\read_tide_model.py:219, in extract_tidal_constants(ilon, ilat, grid_file, model_file, EPSG, **kwargs)
    216     xi,yi,hz,mz,sf = read_netcdf_grid(grid_file)
    217 else:
    218     # if reading a single OTIS solution
--> 219     xi,yi,hz,mz,iob,dt = read_tide_grid(grid_file)
    220 # invert tide mask to be True for invalid points
    221 mz = np.logical_not(mz).astype(mz.dtype)

File c:\users\admin\appdata\local\programs\python\python39\lib\site-packages\pyTMD\read_tide_model.py:640, in read_tide_grid(input_file)
    638 else:
    639     fid.seek(8,1)
--> 640     iob=np.fromfile(fid, dtype=np.dtype('>i4'), count=2*nob).reshape(nob,2)
    641     fid.seek(8,1)
    642 # read hz matrix

ValueError: cannot reshape array of size 1377962 into shape (1768185716,2)

At first i got some error from reading the data file name in the first place, as each model requires a different file format, which i managed to negate by changing the data file name (and zipping) accordingly to what the model required. After then, this problem appears.

Thanks in advance.

Plot Tide Forecasts notebook returns unexpected output for TPXO9-altas-v4?

Hi Tyler,
Thanks for making this tool for Python. I am new to both this tool and python, so I might be doing something wrong, but when I compare the output of the "Plot Tide Forecasts" notebook at the La Jolla Tide Gauge (default location) using the TPXO9-altas-v4 model (Svetlana Erofeeva gave me access to the model files via the box app), I get output that seems incorrect. I have tried this for a variety of dates and compared to two other versions of La Jolla Tide data:
This GUI: https://tidesandcurrents.noaa.gov/noaatidepredictions.html?id=9410230&units=metric&bdate=20210629&edate=20210706&timezone=GMT&clock=24hour&datum=MSL&interval=hilo&action=dailychart
and this netCDF dataset water_levels.nc : https://datadryad.org/stash/dataset/doi:10.5061/dryad.n5qb383
Any chance you also see an inconsistency / have ideas what could be going on?
Thanks for your help!
-Bonnie

Mask not set when extrapolating NetCDF

I've found another issue related to the extrapolation:
In read_netcdf_model.py, the constituent NetCDFs do not include any information about invalid data (at least in TPXO9-atlas-v4 as NetCDF.). For this reason, you derive a mask from the grid_file bathymetry and apply this to the values:
#-- mask invalid values
z1.mask[:] |= np.copy(D.mask)
However, if the value is invalid, nearest_extrap tries to extrapolate using the z-Grid, which has no appropriate mask. Hence, extrapolation always returns 0 for all constituents in my case. I suggest to apply a bathymetry mask to z as well. After line 212 in read_netcdf_model.py:
z.mask = bathymetry.mask

NameError: name 'ipyleaflet' is not defined

I am trying to get using Plot Tide Forecast.ipynb to get a time series of the earth and ocean tide at a certain point, but in string:

m = pyTMD.tools.leaflet(center=(LAT,LON), zoom=3,
    zoom_control=True, marker_control=True)

I ran into the following problem:

NameError                                 Traceback (most recent call last)
Cell In[3], [line 3](vscode-notebook-cell:?execution_count=3&line=3)
      [1](vscode-notebook-cell:?execution_count=3&line=1) # default coordinates to use
      [2](vscode-notebook-cell:?execution_count=3&line=2) LAT,LON = (-76.0, -40.0)
----> [3](vscode-notebook-cell:?execution_count=3&line=3) m = pyTMD.tools.leaflet(center=(LAT,LON), zoom=3,
      [4](vscode-notebook-cell:?execution_count=3&line=4)     zoom_control=True, marker_control=True)
      [5](vscode-notebook-cell:?execution_count=3&line=5) # show map
      [6](vscode-notebook-cell:?execution_count=3&line=6) m.map

File [~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3)+gef78f74-py3.10.egg/pyTMD/tools.py:217, in leaflet.__init__(self, projection, **kwargs)
    [215](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:215) # create basemap in projection
    [216](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:216) if (projection == 'Global'):
--> [217](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:217)     self.map = ipyleaflet.Map(center=kwargs['center'],
    [218](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:218)         zoom=kwargs['zoom'], max_zoom=15, world_copy_jump=True,
    [219](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:219)         attribution_control=kwargs['attribution'],
    [220](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:220)         basemap=ipyleaflet.basemaps.Esri.WorldTopoMap)
    [221](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:221)     self.crs = 'EPSG:3857'
    [222](https://untitled+.vscode-resource.vscode-cdn.net/~/bin/jupiter/.venv/lib/python3.10/site-packages/pyTMD-2.1.1.dev3+gef78f74-py3.10.egg/pyTMD/tools.py:222) elif (projection == 'North'):

NameError: name 'ipyleaflet' is not defined

What could be the problem? There were no problems when installing pyTMD. I am grateful in advance for any help!

Unable to run "extract_netcdf_constants" [Windows 10 OS]

I am unable to successfully run the function "extract_netcdf_constants.py" to read the data from uncompressed netCDF files.

The related part of my code is as follows:

_import pyTMD as tmd

grd_mod = 'c:\Users\user01\Scripts_Python\TPXO9_atlas_nc\grid_tpxo9_atlas_v4.nc'
mod_M2_ = 'c:\Users\user01\Scripts_Python\TPXO9_atlas_nc\h_m2_tpxo9_atlas_30_v4.nc'

amp, ph, D, c = tmd.extract_netcdf_constants(XX, YY, grd_mod, mod_M2_, GZIP=False)_

When I run the code, I receive the following error message:

Traceback (most recent call last):
File "hycom2bnd.py", line 233, in
amp,ph,D,ccc = tmd.extract_netcdf_constants(bndA_X[0],bndA_Y[0],grd_mod,mod_M2
,GZIP=False)
File "C:\Users\user01\anaconda3\lib\site-packages\pyTMD\read_netcdf_model.py", line 189, in extract_netcdf_constants
z,con = read_elevation_file(model_file, GZIP=GZIP)
File "C:\Users\user01\anaconda3\lib\site-packages\pyTMD\read_netcdf_model.py", line 432, in read_elevation_file
fileID = netCDF4.Dataset(os.path.expanduser(input_file),'r')
File "netCDF4_netCDF4.pyx", line 2321, in netCDF4._netCDF4.Dataset.init
File "netCDF4_netCDF4.pyx", line 1885, in netCDF4._netCDF4.ensure_nc_success
FileNotFoundError: [Errno 2] No such file or directory: b'c'

I use the latest anaconda installation with all the packages further upgraded and the python version is 3.8.

It seems like such a straightforward piece of code but at this point, I have no idea what is wrong and couldn't manage to fix the problem. I'd be glad if you can help me with the issue.

Difficulties upgrading to version 1.0.8 due to `mpi4py` dependency

I've recently tried to update pyTMD to the latest 1.0.8 version, but have unfortunately run into some dependency issues relating to the mpi4py package - my install fails with a ERROR: Could not build wheels for mpi4py.

I've been told this may have something to do with me missing a C library (e.g. here), however, I'm unfortunately not able to install this on the managed system I'm using. Looking into the pyTMD requirements.txt however, it looks like mpi4py isn't a direct dependency of pyTMD but is instead possibly a dependency of icesat2-toolkit here.

Because of this, I was wondering if you had any suggestions for how I could get around this requirement, particularly as it didn't seem to be a hard/strict requirement in previous version of pyTMD? (I don't have a good idea of how much pyTMD depends on functionality from icesat2-toolkit)

Full error below:

Collecting pyTMD==1.0.8
  Using cached pyTMD-1.0.8-py3-none-any.whl (7.5 MB)
Requirement already satisfied: pyyaml in /home/jovyan/.local/lib/python3.8/site-packages (from pyTMD==1.0.8) (6.0)
Requirement already satisfied: setuptools-scm in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (7.0.3)
Collecting icesat2-toolkit
  Using cached icesat2_toolkit-1.0.0.22-py3-none-any.whl (1.9 MB)
Requirement already satisfied: lxml in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (4.9.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (1.22.4)
Requirement already satisfied: netCDF4 in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (1.5.8)
Requirement already satisfied: python-dateutil in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (2.8.2)
Requirement already satisfied: scipy in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (1.8.1)
Requirement already satisfied: pyproj in /usr/local/lib/python3.8/dist-packages (from pyTMD==1.0.8) (3.2.1)
Collecting ATM1b-QFIT
  Using cached ATM1b_QFIT-1.0.1-py3-none-any.whl (27 kB)
Requirement already satisfied: future in /usr/local/lib/python3.8/dist-packages (from ATM1b-QFIT->pyTMD==1.0.8) (0.18.2)
Requirement already satisfied: h5py in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (3.7.0)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (3.5.2)
Collecting scp
  Using cached scp-0.14.4-py2.py3-none-any.whl (8.6 kB)
Requirement already satisfied: zarr in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (2.12.0)
Collecting mpi4py
  Using cached mpi4py-3.1.3.tar.gz (2.5 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting pyYAPC
  Using cached pyYAPC-0.0.0.8-cp38-cp38-linux_x86_64.whl
Requirement already satisfied: pandas in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (1.4.3)
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (1.1.1)
Requirement already satisfied: fiona in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (1.8.21)
Requirement already satisfied: boto3 in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (1.21.21)
Requirement already satisfied: shapely in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (1.8.2)
Collecting paramiko
  Using cached paramiko-2.11.0-py2.py3-none-any.whl (212 kB)
Requirement already satisfied: cartopy in /usr/local/lib/python3.8/dist-packages (from icesat2-toolkit->pyTMD==1.0.8) (0.19.0.post1)
Requirement already satisfied: cftime in /usr/local/lib/python3.8/dist-packages (from netCDF4->pyTMD==1.0.8) (1.6.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.8/dist-packages (from pyproj->pyTMD==1.0.8) (2022.6.15)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.8/dist-packages (from python-dateutil->pyTMD==1.0.8) (1.16.0)
Requirement already satisfied: setuptools in /home/jovyan/.local/lib/python3.8/site-packages (from setuptools-scm->pyTMD==1.0.8) (65.3.0)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.8/dist-packages (from setuptools-scm->pyTMD==1.0.8) (21.3)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.8/dist-packages (from setuptools-scm->pyTMD==1.0.8) (4.2.0)
Requirement already satisfied: tomli>=1.0.0 in /usr/local/lib/python3.8/dist-packages (from setuptools-scm->pyTMD==1.0.8) (2.0.1)
Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.8/dist-packages (from packaging>=20.0->setuptools-scm->pyTMD==1.0.8) (2.4.7)
Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.8/dist-packages (from boto3->icesat2-toolkit->pyTMD==1.0.8) (1.0.1)
Requirement already satisfied: botocore<1.25.0,>=1.24.21 in /usr/local/lib/python3.8/dist-packages (from boto3->icesat2-toolkit->pyTMD==1.0.8) (1.24.21)
Requirement already satisfied: s3transfer<0.6.0,>=0.5.0 in /usr/local/lib/python3.8/dist-packages (from boto3->icesat2-toolkit->pyTMD==1.0.8) (0.5.2)
Requirement already satisfied: pyshp>=2 in /usr/local/lib/python3.8/dist-packages (from cartopy->icesat2-toolkit->pyTMD==1.0.8) (2.3.0)
Requirement already satisfied: attrs>=17 in /usr/local/lib/python3.8/dist-packages (from fiona->icesat2-toolkit->pyTMD==1.0.8) (21.4.0)
Requirement already satisfied: click-plugins>=1.0 in /usr/local/lib/python3.8/dist-packages (from fiona->icesat2-toolkit->pyTMD==1.0.8) (1.1.1)
Requirement already satisfied: click>=4.0 in /usr/local/lib/python3.8/dist-packages (from fiona->icesat2-toolkit->pyTMD==1.0.8) (8.1.3)
Requirement already satisfied: cligj>=0.5 in /usr/local/lib/python3.8/dist-packages (from fiona->icesat2-toolkit->pyTMD==1.0.8) (0.7.2)
Requirement already satisfied: munch in /usr/local/lib/python3.8/dist-packages (from fiona->icesat2-toolkit->pyTMD==1.0.8) (2.5.0)
Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.8/dist-packages (from matplotlib->icesat2-toolkit->pyTMD==1.0.8) (9.1.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.8/dist-packages (from matplotlib->icesat2-toolkit->pyTMD==1.0.8) (4.33.3)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.8/dist-packages (from matplotlib->icesat2-toolkit->pyTMD==1.0.8) (1.4.3)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.8/dist-packages (from matplotlib->icesat2-toolkit->pyTMD==1.0.8) (0.11.0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.8/dist-packages (from pandas->icesat2-toolkit->pyTMD==1.0.8) (2022.1)
Collecting pynacl>=1.0.1
  Using cached PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (856 kB)
Collecting bcrypt>=3.1.3
  Using cached bcrypt-4.0.0-cp36-abi3-manylinux_2_28_x86_64.whl (594 kB)
Requirement already satisfied: cryptography>=2.5 in /usr/local/lib/python3.8/dist-packages (from paramiko->icesat2-toolkit->pyTMD==1.0.8) (37.0.2)
Requirement already satisfied: cython in /usr/local/lib/python3.8/dist-packages (from pyYAPC->icesat2-toolkit->pyTMD==1.0.8) (0.29.30)
Requirement already satisfied: joblib>=1.0.0 in /usr/local/lib/python3.8/dist-packages (from scikit-learn->icesat2-toolkit->pyTMD==1.0.8) (1.1.0)
Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.8/dist-packages (from scikit-learn->icesat2-toolkit->pyTMD==1.0.8) (3.1.0)
Requirement already satisfied: asciitree in /usr/local/lib/python3.8/dist-packages (from zarr->icesat2-toolkit->pyTMD==1.0.8) (0.3.3)
Requirement already satisfied: fasteners in /usr/local/lib/python3.8/dist-packages (from zarr->icesat2-toolkit->pyTMD==1.0.8) (0.17.3)
Requirement already satisfied: numcodecs>=0.6.4 in /usr/local/lib/python3.8/dist-packages (from zarr->icesat2-toolkit->pyTMD==1.0.8) (0.10.0)
Requirement already satisfied: urllib3<1.27,>=1.25.4 in /usr/local/lib/python3.8/dist-packages (from botocore<1.25.0,>=1.24.21->boto3->icesat2-toolkit->pyTMD==1.0.8) (1.26.9)
Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.8/dist-packages (from cryptography>=2.5->paramiko->icesat2-toolkit->pyTMD==1.0.8) (1.15.0)
Requirement already satisfied: pycparser in /usr/local/lib/python3.8/dist-packages (from cffi>=1.12->cryptography>=2.5->paramiko->icesat2-toolkit->pyTMD==1.0.8) (2.21)
Building wheels for collected packages: mpi4py
  Building wheel for mpi4py (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for mpi4py (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [148 lines of output]
      running bdist_wheel
      running build
      running build_src
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-38
      creating build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/__init__.py -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/__main__.py -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/bench.py -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/run.py -> build/lib.linux-x86_64-cpython-38/mpi4py
      creating build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/__init__.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/__main__.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/_base.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/_core.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/_lib.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/aplus.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/pool.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/server.py -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      creating build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/util/__init__.py -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/util/dtlib.py -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/util/pkl5.py -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/py.typed -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/MPI.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/__init__.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/__main__.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/bench.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/dl.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/run.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/MPI.pxd -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/__init__.pxd -> build/lib.linux-x86_64-cpython-38/mpi4py
      copying src/mpi4py/libmpi.pxd -> build/lib.linux-x86_64-cpython-38/mpi4py
      creating build/lib.linux-x86_64-cpython-38/mpi4py/include
      creating build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/include/mpi4py/mpi4py.MPI.h -> build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/include/mpi4py/mpi4py.MPI_api.h -> build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/include/mpi4py/mpi4py.h -> build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/include/mpi4py/mpi4py.i -> build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/include/mpi4py/mpi.pxi -> build/lib.linux-x86_64-cpython-38/mpi4py/include/mpi4py
      copying src/mpi4py/futures/__init__.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/__main__.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/_core.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/_lib.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/aplus.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/pool.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/futures/server.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/futures
      copying src/mpi4py/util/__init__.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/util/dtlib.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      copying src/mpi4py/util/pkl5.pyi -> build/lib.linux-x86_64-cpython-38/mpi4py/util
      running build_clib
      MPI configuration: [mpi] from 'mpi.cfg'
      checking for library 'lmpe' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -llmpe -o _configtest
      /usr/bin/ld: cannot find -llmpe
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      building 'mpe' dylib library
      creating build/temp.linux-x86_64-cpython-38
      creating build/temp.linux-x86_64-cpython-38/src
      creating build/temp.linux-x86_64-cpython-38/src/lib-pmpi
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c src/lib-pmpi/mpe.c -o build/temp.linux-x86_64-cpython-38/src/lib-pmpi/mpe.o
      creating build/lib.linux-x86_64-cpython-38/mpi4py/lib-pmpi
      x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,--no-as-needed build/temp.linux-x86_64-cpython-38/src/lib-pmpi/mpe.o -o build/lib.linux-x86_64-cpython-38/mpi4py/lib-pmpi/libmpe.so
      checking for library 'vt-mpi' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt-mpi -o _configtest
      /usr/bin/ld: cannot find -lvt-mpi
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      checking for library 'vt.mpi' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt.mpi -o _configtest
      /usr/bin/ld: cannot find -lvt.mpi
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      building 'vt' dylib library
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c src/lib-pmpi/vt.c -o build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt.o
      x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,--no-as-needed build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt.o -o build/lib.linux-x86_64-cpython-38/mpi4py/lib-pmpi/libvt.so
      checking for library 'vt-mpi' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt-mpi -o _configtest
      /usr/bin/ld: cannot find -lvt-mpi
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      checking for library 'vt.mpi' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt.mpi -o _configtest
      /usr/bin/ld: cannot find -lvt.mpi
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      building 'vt-mpi' dylib library
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c src/lib-pmpi/vt-mpi.c -o build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt-mpi.o
      x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,--no-as-needed build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt-mpi.o -o build/lib.linux-x86_64-cpython-38/mpi4py/lib-pmpi/libvt-mpi.so
      checking for library 'vt-hyb' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt-hyb -o _configtest
      /usr/bin/ld: cannot find -lvt-hyb
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      checking for library 'vt.ompi' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -lvt.ompi -o _configtest
      /usr/bin/ld: cannot find -lvt.ompi
      collect2: error: ld returned 1 exit status
      failure.
      removing: _configtest.c _configtest.o
      building 'vt-hyb' dylib library
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -c src/lib-pmpi/vt-hyb.c -o build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt-hyb.o
      x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,--no-as-needed build/temp.linux-x86_64-cpython-38/src/lib-pmpi/vt-hyb.o -o build/lib.linux-x86_64-cpython-38/mpi4py/lib-pmpi/libvt-hyb.so
      running build_ext
      MPI configuration: [mpi] from 'mpi.cfg'
      checking for dlopen() availability ...
      checking for header 'dlfcn.h' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I/usr/include/python3.8 -c _configtest.c -o _configtest.o
      success!
      removing: _configtest.c _configtest.o
      success!
      checking for library 'dl' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I/usr/include/python3.8 -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -Lbuild/temp.linux-x86_64-cpython-38 -ldl -o _configtest
      success!
      removing: _configtest.c _configtest.o _configtest
      checking for function 'dlopen' ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I/usr/include/python3.8 -c _configtest.c -o _configtest.o
      x86_64-linux-gnu-gcc -pthread _configtest.o -Lbuild/temp.linux-x86_64-cpython-38 -ldl -o _configtest
      success!
      removing: _configtest.c _configtest.o _configtest
      building 'mpi4py.dl' extension
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -DHAVE_DLFCN_H=1 -DHAVE_DLOPEN=1 -I/usr/include/python3.8 -c src/dynload.c -o build/temp.linux-x86_64-cpython-38/src/dynload.o
      x86_64-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 build/temp.linux-x86_64-cpython-38/src/dynload.o -Lbuild/temp.linux-x86_64-cpython-38 -ldl -o build/lib.linux-x86_64-cpython-38/mpi4py/dl.cpython-38-x86_64-linux-gnu.so
      checking for MPI compile and link ...
      x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I/usr/include/python3.8 -c _configtest.c -o _configtest.o
      _configtest.c:2:10: fatal error: mpi.h: No such file or directory
          2 | #include <mpi.h>
            |          ^~~~~~~
      compilation terminated.
      failure.
      removing: _configtest.c _configtest.o
      error: Cannot compile MPI programs. Check your configuration!!!
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for mpi4py
Failed to build mpi4py
ERROR: Could not build wheels for mpi4py, which is required to install pyproject.toml-based projects
Note: you may need to restart the kernel to use updated packages.

read_FES_model.py: explicit definition of hc.mask fails on NaN fill_value

Hi,
in read_FES_model.py at the very end of read_netcdf_file you explicitly set the mask using
hc.mask = (amp.data == amp.fill_value) | (ph.data == ph.fill_value)
However, this doesn't work if fill_value is np.nan as comparing to nan is always false. Moreover, this is just creating the problem at all. When you read amp and ph using the NetCDF4 module, they are already masked arrays. So, calculating hc from these masked arrays already sets the mask correctly. On the next line, however, this correct mask is overwritten (without any need), causing this bug.
I suggest to simply remove #-- set masks and the following line from read_netcdf_file in read_FES_model.

Optimization of `compute_tide_corrections` with `FES2014` for multiple lat/lons

First of all, congrats @tsutterley on an incredible package... such an amazing resource! I've been looking into using pyTMD for modelling tide heights from FES2014 for our DEA Coastlines coastline mapping work. Essentially, our current process is to:

  • For a coastal study area, load every image taken by the Landsat satellites between 1987 and 2022
  • For each point on a 2 x 2 km point grid over the ocean, model tides for the exact time each Landsat image was taken (e.g. typically 1000-1500 images per point)

I've been testing out the compute_tide_corrections as a way to achieve this, passing in the lat/lon of a given 2 x 2 km grid point, and all of the times from my satellite datasets:

import pandas as pd
from pyTMD import compute_tide_corrections

lat, lon = -32, 155
example_times = pd.date_range("2022-01-01", "2022-01-02", freq="1h").values

out = compute_tide_corrections(
    x=lon,
    y=lat,
    delta_time=example_times,
    DIRECTORY="FES2014",
    MODEL="FES2014",
    EPSG=4326,
    TYPE="time series",
    TIME="datetime",
    METHOD="bilinear",
)

This works great, but it's pretty slow: about 38.4 seconds in total for a single point lat/lon. Because I can have up to 100+ lat/lon points in a given study area, this will quickly blow out if I want to apply compute_tide_corrections to multiple points.

Using line_profiler, it appears that by far most of this time (e.g. 38.2 seconds, or over 99%) is taken up in the extract_FES_constants function:

Timer unit: 1e-06 s

Total time: 38.408 s
File: /env/lib/python3.8/site-packages/pyTMD/compute_tide_corrections.py
Function: compute_tide_corrections at line 125

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
...
   277         2   38292108.0 19146054.0     99.7          amp,ph = extract_FES_constants(lon, lat, model.model_file,
   278         1          4.0      4.0      0.0              TYPE=model.type, VERSION=model.version, METHOD=METHOD,
   279         1          4.0      4.0      0.0              EXTRAPOLATE=EXTRAPOLATE, CUTOFF=CUTOFF, SCALE=model.scale,
   280         1          4.0      4.0      0.0              GZIP=model.compressed)
...

Profiling extract_FES_constants, it seems like by far the most amount of time in that function (37.5 seconds) is taken up by read_netcdf_file:

Timer unit: 1e-06 s

Total time: 38.2932 s
File: /env/lib/python3.8/site-packages/pyTMD/read_FES_model.py
Function: extract_FES_constants at line 86

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
...
   158        68   37470465.0 551036.2     97.9              hc,lon,lat = read_netcdf_file(os.path.expanduser(fi),
   159        34         53.0      1.6      0.0                  GZIP=GZIP, TYPE=TYPE, VERSION=VERSION)
...

So essentially, loading the FES2014 files with read_netcdf_file occupies almost all of the time taken to run compute_tide_corrections. For analyses involving many timesteps for a single lat/lon this isn't a problem, as the files only have to be read once. However, for analyses where compute_tide_corrections needs to be called multiple times to model tides for multiple lat/lons, the FES2014 data has to be loaded again and again, leading to extremely long processing times.

Instead of loading the FES2014 files with read_netcdf_file every time compute_tide_corrections is called, could it be possible to give users the option to load the FES files themselves outside of the function, and then pass in the loaded data (i.e. hc, lon, lat) directly to the function via an optional parameter? This would allow users to greatly optimise processing time for analyses that include many lat/lon tide modelling locations.

pyTMD.compute.tide_currents needing both u_* and v_* rather than only u_*

Hi,
following up on my last post, I basically went around by cloning and installing 2.1.1.

Anyway, when I try to use:
pyTMD,compute.tide_currents
it asks for separate u_* and v_* input files (the several ones for the different constituents).
In the database that I have, both the OTIS and netcdf, I only have h_* and u_, and when I asked Dr. Erofeeva, she told me that the u_ contains both the eastward and northward components of the tidal currents, so there should be no need for two separate input files?

As a patch in the short term, can i simply dubplicate and rename the u_* files into the v_*, or this would mess up something?

And a quick question: the results are in m/s, right?

Many thanks

Maurizio

Can the interpolation range be limited in advance to improve program efficiency?

It's very slow when I use the program to read TPXO9-atlas-v5 and compute tidal elevations. So I check the profile of the code and found that the most time-consuming function is the interpolation part, so I wonder if I can limit the interpolation range in advance to improve operation efficiency?

These two log files are profiles before and after my modification.
We can see that it's very useful when the data range we used is small.
Can it become universal?

test_pytmd.py.txt
before.log
after.log

AtributeError running compute_tidal_currents.py

Hi!

I am trying to run the compute_tidal_currents.py script to get the tidal components from TPXO9-atlas-v5. However, I am getting the following error message:

... line 430, in arguments
choices = sorted(pyTMD.io.model.ocean_current())
AttributeError: module 'pyTMD' has no attribute 'io'

Any thoughts on how to solve this?

Thanks!

Getting tons of DeprecationWarning upon import

Hi,

I am getting tons of DeprecationWarning on imports with version '1.1.3'.

/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/pyTMD/tools.py:55: UserWarning: ipyleaflet not available
  warnings.warn("ipyleaflet not available")
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/pyTMD/tools.py:56: UserWarning: Some functions will throw an exception if called
  warnings.warn("Some functions will throw an exception if called")
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widget_types is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget.widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._active_widgets is deprecated.
  value = getattr(cls, name)
/Users/aponte/.miniconda3/envs/pynsitu/lib/python3.10/site-packages/traitlets/traitlets.py:1016: DeprecationWarning: Widget._widget_types is deprecated.
  value = getattr(cls, name)
...

and so on

I'll try updating to version 2.0.0 to see if this was fixed.
In any case, I did not see mention of this in the issue tracker and thought this could be useful to other users.

module 'pyTMD' has no attribute 'compute'

Hi,
I fell I am missing something basic here.
I was trying to use the example given in here, i.e.:
tide_h = pyTMD.compute.tide_elevations(x, y, delta_time, DIRECTORY=path_to_tide_models, MODEL='CATS2008', EPSG=3031, EPOCH=(2000,1,1,0,0,0), TYPE='drift', TIME='GPS', METHOD='spline', FILL_VALUE=np.nan)

But, after I receive the error:
`AttributeError: module 'pyTMD' has no attribute 'compute'

What I have done:

  • created a separate conda environment
  • installed with conda the pyTMD package (conda install -c conda-forge pytmd)
  • Run the following script:
    `import numpy as np
    import pyTMD

x = 14.5625
y = 36.4375
delta_time = pyTMD.time.convert_calendar_dates(2000, 1, 1, minute = np.arange(0,24*60,30))
path_to_tide_models = 'D:\TPXO9\TPXO9_atlas\TPXO9_atlas_v5'
model_name = 'TPXO9-atlas-v5'
epoch_tuple = (1992,1,1,0,0,0)
tide_h = pyTMD.compute.tide_elevations(x, y, delta_time,
DIRECTORY = path_to_tide_models,
MODEL = model_name,
EPOCH = epoch_tuple,
TYPE='drift', TIME='GPS',
METHOD='spline', FILL_VALUE=np.nan)`

Can you please help?

Definition File for HAMTIDE constituents

Hi everybody,

I want to use the constituents provided by hamtide within pyTMD.
Basically, the data is provided as separate netcdf file for each constituent and split up into amplitude and current information.
Can someone please provide me with some guidance on how to setup the Definition Files?

Thank a lot in advance!
-Martin

compute_tidal_elevations.py --type=grid fails with shape mismatch

compute_tidal_elevations.py --type=grid --format=netCDF4 fails with shape mismatch before writing output.

To keep this issue simple, I have created a dummy input file with points (lat,lon,time) to be interpolated:

cat << EOF | tee pytmd_tll.cdl
netcdf pytmd_tll {
dimensions:
        time = 7 ;
        lat = 10;
        lon = 2;
variables:
        float lon(lon) ;
                lon:_FillValue = -9999.f ;
                lon:long_name = "longitude at T-points (cell centres)" ;
                lon:units = "degrees-east" ;
        float lat(lat) ;
                lat:_FillValue = -9999.f ;
                lat:long_name = "latitude at T-points (cell centres)" ;
                lat:units = "degrees-north" ;
        float time(time) ;
                time:_FillValue = -9999.f ;
                time:missing_value = -9999. ;
                time:long_name = "time" ;
                time:units = "seconds since 2021-01-30 00:00" ;
data:

lon = -51.88087, -51.88676 ;

lat = 63.08587, 63.09052, 63.09517, 63.09982, 63.10447, 63.10912, 63.11377,  63.11841, 63.12306, 63.12771 ;

time = 0., 600., 1200., 1800., 2400., 3000., 3600.;
}
EOF
cat pytmd_tll.cdl | ncgen -3  -o pytmd_tll.nc

I've used arcticdata_tides.py to download Gr1kmTM to ensure that I have the right data and the right format.
I use the latest code update (git), so that I do not need to specify "data" (4th varname).
My command line looks like:

python3 /home/bjb/pyTDM/install-2023-01-31/bin/compute_tidal_elevations.py --directory=/mnt/nfs/modeldev02-scratch/bjb_today/TDMdata --tide=Gr1kmTM --format=netCDF4 --type=grid --variables time lat lon --projection 4326 pytmd_tll.nc pytdm-test.nc

I have tested (debug/write statements), that the program does set up a tide-array of shape (ny,nx,nt)=(10,2,7), and it contains data.
However, there is an error when output is defined:

Traceback (most recent call last):
  File "/home/bjb/pyTDM/install-2023-01-31/bin/compute_tidal_elevations.py", line 4, in <module>
    __import__('pkg_resources').run_script('pyTMD==2.0.1.dev8+g664d6c0.d20230131', 'compute_tidal_elevations.py')
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 656, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1453, in run_script
    exec(code, namespace, namespace)
  File "/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/EGG-INFO/scripts/compute_tidal_elevations.py", line 553, in <module>
    main()
  File "/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/EGG-INFO/scripts/compute_tidal_elevations.py", line 530, in main
    compute_tidal_elevations(args.directory, args.infile, args.outfile,
  File "/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/EGG-INFO/scripts/compute_tidal_elevations.py", line 398, in compute_tidal_elevations
    pyTMD.spatial.to_netCDF4(output, attrib, output_file)
  File "/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/pyTMD/spatial.py", line 682, in to_netCDF4
    nc[key][:] = val
  File "src/netCDF4/_netCDF4.pyx", line 4903, in netCDF4._netCDF4.Variable.__setitem__
  File "/usr/lib/python3/dist-packages/netCDF4/utils.py", line 356, in _StartCountStride
    datashape = broadcasted_shape(shape, datashape)
  File "/usr/lib/python3/dist-packages/netCDF4/utils.py", line 964, in broadcasted_shape
    return np.broadcast(a, b).shape
ValueError: shape mismatch: objects cannot be broadcast to a single shape

If I am doing something completely wrong, then feel free to just point me in the right direction.

Thanks,
Bjarne

pyTMD without Jupyter

I'm running pyTMD under Linux, but I do not want to install Jupyter packages. I have no intentions of using Jupyter on this system, and the packages would only bloat the installation.
The "scripts" part of pyTMD seem to work fine without Jupyter, but every time I run a script, I get warnings:

/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/pyTMD/tools.py:54: ImportWarning: ipyleaflet not available
  warnings.warn("ipyleaflet not available", ImportWarning)
/home/bjb/pyTDM/install-2023-01-31/lib/python3.10/site-packages/pyTMD-2.0.1.dev8+g664d6c0.d20230131-py3.10.egg/pyTMD/tools.py:59: ImportWarning: ipywidgets not available
  warnings.warn("ipywidgets not available", ImportWarning)

Would it be possible to silence these warnings? If nothing else, then with an option stating that I am aware that the packages are not installed.

Thanks,
/Bjarne

nearest_extrap.py cuts model grid independent of cutoff distance

Hi,
I found a bug in nearest_extrap.py. This program shall find the nearest model data for locations where the model grid itself is NaN. To specify the search range, you specify a "cutoff" distance. However, before searching for nearest neighbors, the model data is pre-filtered to the vicinity of the data points. Here, however, you filter the points to the data locations plus 2x the model grid resolution. If you have a relatively high resolution grid, 2 x dlon/dlat is much smaller than "cutoff". This leads to NaN-values if there is model data within "cutoff" but only in distances larger than 2 x dlon/dlat. (I found this issue e.g. for FES2014 at Bergen/Norway, 5.3°E 60.4°N)

Instead, I suggest to modify nearest_extrap.py as follows:

    #-- create combined valid mask
    valid_bounds = (~idata.mask) & np.isfinite(idata.data)
    if(np.isfinite(cutoff)):
        #-- reduce to model points within bounds of input points
        # convert cutoff [km] into distance [°] on sphere (simplified)
        lat_max = np.max(np.abs(lat))
        R = 6371
        dlat = np.rad2deg( cutoff/R )
        dlon = np.rad2deg( cutoff/(R*np.cos(np.deg2rad(lat_max))) )
        
        valid_bounds &= (gridlon >= (xmin-dlon))
        valid_bounds &= (gridlon <= (xmax+dlon))
        valid_bounds &= (gridlat >= (ymin-dlat))
        valid_bounds &= (gridlat <= (ymax+dlat))

+ remove the definition of dlon/dlat earlier from the model grid

calc_astrol_longitudes.py: inconsistency between ASTRO5 and MEEUS solar perigee definition.

Hi there @tsutterley... I noticed a divergence between two definitions on calc_astrol_longitudes.py: equations are identical, but ASTRO5 has T defined in days and MEEUS uses T in centuries.

if MEEUS:
# convert from MJD to days relative to 2000-01-01T12:00:00
T = MJD - 51544.5
#...
# mean longitude of solar perigee (Simon et al., 1994)
PP = 282.94 + 1.7192 * T

elif ASTRO5:
# convert from MJD to centuries relative to 2000-01-01T12:00:00
T = (MJD - 51544.5)/36525.0
# ...
# mean longitude of solar perigee (Simon et al., 1994)
PP = 282.94 + 1.7192 * T

Using extract_netcdf_constants to read TPXO9-atlas-v5 files

Hello,

I’m trying to use extract_netcdf_constants to calculate constituents from TPXO9-atlas-v5 files. It is working great when nearest neighbours interpolation is used, but not when trying bilinear interpolation. It still gives the correct phase, but the amplitudes are significantly off.

Example code:

from pyTMD.read_netcdf_model import extract_netcdf_constants
import glob

# Coordinates
lat = 50.103
lon = -5.54283

# Listing all constituent files
files = glob.glob(tpx_path + "/h/*.nc")

# Assigning grid file
grid = glob.glob(tpx_path + "/grid/*.nc")[0]

amp, ph, D, c = extract_netcdf_constants(lon, lat, grid, files, TYPE="z", GZIP=False, METHOD="bilinear",
                                         EXTRAPOLATE=True, SCALE=1.0/1000)

Sorry to bother, I’m new to this field so it is likely something I am doing wrong. I must say I have found pyTMD extremely useful so far. thank you!

Compute tidal currents - variale referenced before assignment

Hi all,

I'm trying to obtain the u and v components of the tidal current at a fixed point from the attached CSV file. But after I run compute_tidal_current.py as follows:

compute_tidal_currents.py erebus_2017_2019_hourly.csv erebus_current.csv --tide 'CATS2008' --directory /home/UOCNT/rag110/ --variables y x time --header 1 --type 'drift' -projection 4326

I got this error. I tried to trace it and see if I made something wrong but could not find anything so far. Maybe my call to the program is wrong?

Traceback (most recent call last):
  File "/home/UOCNT/rag110/anaconda3/envs/pytmd-env/bin/compute_tidal_currents.py", line 515, in <module>
    main()
  File "/home/UOCNT/rag110/anaconda3/envs/pytmd-env/bin/compute_tidal_currents.py", line 503, in main
    compute_tidal_currents(args.directory, args.infile, args.outfile,
  File "/home/UOCNT/rag110/anaconda3/envs/pytmd-env/bin/compute_tidal_currents.py", line 244, in compute_tidal_currents
    dinput = pyTMD.spatial.from_ascii(input_file, columns=VARIABLES,
  File "/home/UOCNT/rag110/anaconda3/envs/pytmd-env/lib/python3.9/site-packages/pyTMD/spatial.py", line 160, in from_ascii
    for i,line in enumerate(file_contents[header:]):
UnboundLocalError: local variable 'header' referenced before assignment

Thanks for your help.

erebus_2017_2019_hourly.csv

Getting-Started.rst old link to Arc2kmTM

The Getting-Started.rst file has an old/obsolete link to the Arc2kmTM model:

 * `Arc2kmTM <https://arcticdata.io/catalog/view/doi:10.18739/A2PV6B79W>`_: ``<path_to_tide_models>/Arc2kmTM/``

The link should be corrected to A2D21RK6K.

The actual code use the new/updated link, so it is only a matter of updating doc. Also, if the old link is followed, the page has a notice that a new version of the dataset is available. The only problem that I really can see is that a user may be in doubt on whether pyTMD uses outdated data for Arc2kmTM.

Best,
Bjarne

Allow Glob patterns when specifying the model files in definition files

Hi, I see you made some fundamental changes in handling the model parameters in the last few months. I principle I like these changes. As I'm not a big fan of hard coded paths (even if they are just subpaths under tide_dir) I really like the possibility to use a definition file as an alternative. Here I have one suggestion to make the use of definition files easier.
In the current version under model_file the user needs to specify a long list of each single constituent file. I would suggest to allow to use a Glob pattern here as well. So instead of

model_file ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/2n2.nc, ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/eps2.nc, ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/j1.nc, ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/k1.nc, ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/k2.nc, ... + ~30 more files 

one could simply write

model_file ~/data/TIDE_MODEL/fes/fes2014_elevations_and_load/fes2014b_elevations/*.nc

To allow this (and at the same time allow the old behavior as well) I suggest to import glob and modify l.1518ff in model.py as follows:

        model_files = []
        for pattern in re.split(r'[\s\,]+',temp.model_file):
            for model_file1 in sorted(glob.glob(os.path.expanduser(pattern))):
                model_files.append(model_file1)
        temp.model_file = model_files

Furthermore, there is no need to search for the separator r'[\s\,]+' and make a difference between the cases. If no separator is found, the loop runs only once.

BTW: In l.1470 in model.py the print(test) was surely ment for test purposes and can be removed now. ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.