Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add minor inference for long period tides to address #327 #342

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
# 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 @@
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
Loading