Skip to content

Commit

Permalink
feat: add minor inference for long period tides to address #327
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutterley committed Sep 25, 2024
1 parent 43dbc92 commit 8c74479
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 20 deletions.
2 changes: 2 additions & 0 deletions doc/source/api_reference/arguments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Calling Sequence

.. autofunction:: pyTMD.arguments.nodal

.. autofunction:: pyTMD.arguments.frequency

.. autofunction:: pyTMD.arguments._arguments_table

.. autofunction:: pyTMD.arguments._minor_table
Expand Down
4 changes: 4 additions & 0 deletions doc/source/api_reference/predict.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ Calling Sequence

.. autofunction:: pyTMD.predict.infer_minor

.. autofunction:: pyTMD.predict._infer_short_period

.. autofunction:: pyTMD.predict._infer_long_period

.. autofunction:: pyTMD.predict.equilibrium_tide

.. autofunction:: pyTMD.predict.load_pole_tide
Expand Down
74 changes: 67 additions & 7 deletions pyTMD/arguments.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
u"""
arguments.py
Written by Tyler Sutterley (08/2024)
Written by Tyler Sutterley (09/2024)
Calculates the nodal corrections for tidal constituents
Modification of ARGUMENTS fortran subroutine by Richard Ray 03/1999
Expand Down Expand Up @@ -38,6 +38,7 @@
Ocean Tides", Journal of Atmospheric and Oceanic Technology, (2002).
UPDATE HISTORY:
Updated 09/2024: add function to calculate tidal angular frequencies
Updated 08/2024: add support for constituents in PERTH5 tables
add back nodal arguments from PERTH3 for backwards compatibility
Updated 01/2024: add function to create arguments coefficients table
Expand Down Expand Up @@ -78,6 +79,7 @@
"coefficients_table",
"doodson_number",
"nodal",
"frequency",
"_arguments_table",
"_minor_table",
"_constituent_parameters",
Expand Down Expand Up @@ -1060,12 +1062,9 @@ def nodal(
model time series," *Advances in Water Resources*, 12(3), 109--120,
(1989). `doi: 10.1016/0309-1708(89)90017-1
<https://doi.org/10.1016/0309-1708(89)90017-1>`_
.. [4] G. D. Egbert and S. Y. Erofeeva, "Efficient Inverse Modeling of
Barotropic Ocean Tides," *Journal of Atmospheric and Oceanic
Technology*, 19(2), 183--204, (2002).
`doi: 10.1175/1520-0426(2002)019<0183:EIMOBO>2.0.CO;2`__
.. __: https://doi.org/10.1175/1520-0426(2002)019<0183:EIMOBO>2.0.CO;2
.. [4] R. D. Ray, "A global ocean tide model from
Topex/Poseidon altimetry: GOT99.2",
NASA Goddard Space Flight Center, TM-1999-209478, (1999).
"""
# set default keyword arguments
kwargs.setdefault('corrections', 'OTIS')
Expand Down Expand Up @@ -1724,6 +1723,67 @@ def nodal(
# return corrections for constituents
return (u, f)

def frequency(
constituents: list | np.ndarray,
**kwargs
):
"""
Calculates the angular frequency for tidal constituents [1]_
Parameters
----------
constituents: list
tidal constituent IDs
corrections: str, default 'OTIS'
use nodal corrections from OTIS, FES or GOT models
M1: str, default 'perth5'
coefficients to use for M1 tides
- ``'Doodson'``
- ``'Ray'``
- ``'perth5'``
Returns
-------
omega: np.ndarray
angular frequency in radians per second
References
----------
.. [1] R. D. Ray, "A global ocean tide model from
Topex/Poseidon altimetry: GOT99.2",
NASA Goddard Space Flight Center, TM-1999-209478, (1999).
"""
# set default keyword arguments
kwargs.setdefault('corrections', 'OTIS')
kwargs.setdefault('M1', 'perth5')

Check warning on line 1759 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1758-L1759

Added lines #L1758 - L1759 were not covered by tests
# set function for astronomical longitudes
# use ASTRO5 routines if not using an OTIS type model
ASTRO5 = kwargs['corrections'] not in ('OTIS','ATLAS','TMD3','netcdf')

Check warning on line 1762 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1762

Added line #L1762 was not covered by tests
# Modified Julian Dates at J2000
MJD = np.array([51544.5, 51544.55])

Check warning on line 1764 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1764

Added line #L1764 was not covered by tests
# time interval in seconds
deltat = 86400.0*(MJD[1] - MJD[0])

Check warning on line 1766 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1766

Added line #L1766 was not covered by tests
# calculate the mean longitudes of the sun and moon
s, h, p, n, pp = pyTMD.astro.mean_longitudes(MJD, ASTRO5=ASTRO5)

Check warning on line 1768 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1768

Added line #L1768 was not covered by tests

# number of temporal values
nt = len(np.atleast_1d(MJD))

Check warning on line 1771 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1771

Added line #L1771 was not covered by tests
# initial time conversions
hour = 24.0*np.mod(MJD, 1)

Check warning on line 1773 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1773

Added line #L1773 was not covered by tests
# convert from hours solar time into mean lunar time in degrees
tau = 15.0*hour - s + h

Check warning on line 1775 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1775

Added line #L1775 was not covered by tests
# variable for multiples of 90 degrees (Ray technical note 2017)
k = 90.0 + np.zeros((nt))

Check warning on line 1777 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1777

Added line #L1777 was not covered by tests

# determine equilibrium arguments
fargs = np.c_[tau, s, h, p, n, pp, k]
rates = (fargs[1,:] - fargs[0,:])/deltat
fd = np.dot(rates, coefficients_table(constituents, **kwargs))

Check warning on line 1782 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1780-L1782

Added lines #L1780 - L1782 were not covered by tests
# convert to radians per second
omega = 2.0*np.pi*fd/360.0
return omega

Check warning on line 1785 in pyTMD/arguments.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/arguments.py#L1784-L1785

Added lines #L1784 - L1785 were not covered by tests

def _arguments_table(**kwargs):
"""
Arguments table for tidal constituents [1]_ [2]_
Expand Down
13 changes: 7 additions & 6 deletions pyTMD/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
use model class attributes for file format and corrections
add keyword argument to select nodal corrections type
fix to use case insensitive assertions of string argument values
add model attribute for tide model bulk frequencies
Updated 08/2024: allow inferring only specific minor constituents
use prediction functions for pole tides in cartesian coordinates
use rotation matrix to convert from cartesian to spherical
Expand Down Expand Up @@ -402,7 +403,7 @@ def tide_elevations(
if INFER_MINOR:
MINOR = pyTMD.predict.infer_minor(ts.tide[i], hc, c,
deltat=deltat[i], corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
else:
MINOR = np.ma.zeros_like(TIDE)
# add major and minor components and reform grid
Expand All @@ -417,7 +418,7 @@ def tide_elevations(
if INFER_MINOR:
minor = pyTMD.predict.infer_minor(ts.tide, hc, c,
deltat=deltat, corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
tide.data[:] += minor.data[:]
elif (TYPE.lower() == 'time series'):
nstation = len(x)
Expand All @@ -431,7 +432,7 @@ def tide_elevations(
if INFER_MINOR:
MINOR = pyTMD.predict.infer_minor(ts.tide, HC, c,
deltat=deltat, corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
else:
MINOR = np.ma.zeros_like(TIDE)
# add major and minor components
Expand Down Expand Up @@ -635,7 +636,7 @@ def tide_currents(
if INFER_MINOR:
MINOR = pyTMD.predict.infer_minor(ts.tide[i], hc, c,
deltat=deltat[i], corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
else:
MINOR = np.ma.zeros_like(TIDE)
# add major and minor components and reform grid
Expand All @@ -650,7 +651,7 @@ def tide_currents(
if INFER_MINOR:
minor = pyTMD.predict.infer_minor(ts.tide, hc, c,
deltat=deltat, corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
tide[t].data[:] += minor.data[:]
elif (TYPE.lower() == 'time series'):
nstation = len(x)
Expand All @@ -664,7 +665,7 @@ def tide_currents(
if INFER_MINOR:
MINOR = pyTMD.predict.infer_minor(ts.tide, HC, c,
deltat=deltat, corrections=nodal_corrections,
minor=minor_constituents)
minor=minor_constituents, frequency=model.frequency)
else:
MINOR = np.ma.zeros_like(TIDE)
# add major and minor components
Expand Down
11 changes: 11 additions & 0 deletions pyTMD/io/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
add file_format and nodal correction attributes
export database as a dataclass for easier access
added variable name and descriptions for long period tides
added attribute for model bulk frequencies for long period tides
Updated 08/2024: added attribute for minor constituents to infer
allow searching over iterable glob strings in definition files
added option to try automatic detection of definition file format
Expand Down Expand Up @@ -301,6 +302,16 @@ def corrections(self) -> str:
else:
return part1

@property
def frequency(self) -> str:
"""
Returns the frequency type for the model
"""
if self.variable in ('tide_lpe',):
return 'long'

Check warning on line 311 in pyTMD/io/model.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/io/model.py#L311

Added line #L311 was not covered by tests
else:
return 'short'

@property
def file_format(self) -> str:
"""
Expand Down
Loading

0 comments on commit 8c74479

Please sign in to comment.