Skip to content

Commit

Permalink
feat: add minor inference for long period tides to address #327 (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutterley authored Sep 25, 2024
1 parent 43dbc92 commit da9de5e
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')
# set function for astronomical longitudes
# use ASTRO5 routines if not using an OTIS type model
ASTRO5 = kwargs['corrections'] not in ('OTIS','ATLAS','TMD3','netcdf')
# Modified Julian Dates at J2000
MJD = np.array([51544.5, 51544.55])
# time interval in seconds
deltat = 86400.0*(MJD[1] - MJD[0])
# calculate the mean longitudes of the sun and moon
s, h, p, n, pp = pyTMD.astro.mean_longitudes(MJD, ASTRO5=ASTRO5)

# number of temporal values
nt = len(np.atleast_1d(MJD))
# initial time conversions
hour = 24.0*np.mod(MJD, 1)
# convert from hours solar time into mean lunar time in degrees
tau = 15.0*hour - s + h
# variable for multiples of 90 degrees (Ray technical note 2017)
k = 90.0 + np.zeros((nt))

# 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))
# convert to radians per second
omega = 2.0*np.pi*fd/360.0
return omega

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'
else:
return 'short'

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

0 comments on commit da9de5e

Please sign in to comment.