pyTMD 2.2.5__tar.gz → 2.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {pytmd-2.2.5 → pytmd-2.2.7}/PKG-INFO +30 -7
  2. {pytmd-2.2.5 → pytmd-2.2.7}/README.rst +29 -3
  3. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/__init__.py +1 -1
  4. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/arguments.py +215 -60
  5. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/astro.py +75 -84
  6. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/compute.py +37 -26
  7. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/crs.py +1 -1
  8. pytmd-2.2.7/pyTMD/data/ct1971_tab6.txt +31 -0
  9. pytmd-2.2.7/pyTMD/data/d1921_tab.txt +21 -0
  10. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/database.json +61 -0
  11. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/ellipse.py +8 -9
  12. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/ATLAS.py +4 -3
  13. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/FES.py +5 -4
  14. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/GOT.py +12 -11
  15. pytmd-2.2.7/pyTMD/io/NOAA.py +215 -0
  16. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/OTIS.py +4 -3
  17. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/__init__.py +1 -0
  18. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/constituents.py +3 -2
  19. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/model.py +10 -4
  20. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/math.py +82 -22
  21. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/predict.py +362 -112
  22. {pytmd-2.2.5 → pytmd-2.2.7/pyTMD}/scripts/arcticdata_tides.py +4 -2
  23. {pytmd-2.2.5 → pytmd-2.2.7/pyTMD}/scripts/aviso_fes_tides.py +19 -5
  24. {pytmd-2.2.5 → pytmd-2.2.7/pyTMD}/scripts/gsfc_got_tides.py +10 -8
  25. {pytmd-2.2.5 → pytmd-2.2.7/pyTMD}/scripts/reduce_OTIS_files.py +5 -3
  26. {pytmd-2.2.5 → pytmd-2.2.7/pyTMD}/scripts/verify_box_tpxo.py +4 -2
  27. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/solve/constants.py +4 -3
  28. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/spatial.py +50 -54
  29. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/tools.py +33 -103
  30. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/utilities.py +22 -598
  31. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/version.py +1 -1
  32. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD.egg-info/PKG-INFO +30 -7
  33. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD.egg-info/SOURCES.txt +9 -21
  34. pytmd-2.2.7/pyTMD.egg-info/entry_points.txt +6 -0
  35. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD.egg-info/requires.txt +0 -3
  36. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD.egg-info/top_level.txt +0 -1
  37. {pytmd-2.2.5 → pytmd-2.2.7}/pyproject.toml +65 -6
  38. pytmd-2.2.5/.gitignore +0 -96
  39. pytmd-2.2.5/CITATION.cff +0 -47
  40. pytmd-2.2.5/CODE_OF_CONDUCT.rst +0 -136
  41. pytmd-2.2.5/CONTRIBUTORS.rst +0 -7
  42. pytmd-2.2.5/providers/AVISO.json +0 -404
  43. pytmd-2.2.5/providers/ESR.json +0 -360
  44. pytmd-2.2.5/providers/GSFC.json +0 -344
  45. pytmd-2.2.5/providers/README.rst +0 -11
  46. pytmd-2.2.5/providers/TPXO.json +0 -898
  47. pytmd-2.2.5/providers/_model_to_database.py +0 -88
  48. pytmd-2.2.5/providers/_providers_to_database.py +0 -57
  49. pytmd-2.2.5/providers/_update_providers.py +0 -159
  50. pytmd-2.2.5/providers/providers.json +0 -182
  51. pytmd-2.2.5/pyTMD/data/d1921_tab.txt +0 -21
  52. pytmd-2.2.5/setup.py +0 -24
  53. pytmd-2.2.5/version.txt +0 -1
  54. {pytmd-2.2.5 → pytmd-2.2.7}/LICENSE +0 -0
  55. {pytmd-2.2.5 → pytmd-2.2.7}/MANIFEST.in +0 -0
  56. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/compute_tide_corrections.py +0 -0
  57. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/ce1973_tab1.txt +0 -0
  58. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/ct1971_tab5.txt +0 -0
  59. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/doodson.json +0 -0
  60. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/opoleloadcoefcmcor.txt.gz +0 -0
  61. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/tab5.2e.txt +0 -0
  62. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/tab5.3a.txt +0 -0
  63. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/data/tab5.3b.txt +0 -0
  64. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/interpolate.py +0 -0
  65. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/io/IERS.py +0 -0
  66. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD/solve/__init__.py +0 -0
  67. {pytmd-2.2.5 → pytmd-2.2.7}/pyTMD.egg-info/dependency_links.txt +0 -0
  68. {pytmd-2.2.5 → pytmd-2.2.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyTMD
3
- Version: 2.2.5
3
+ Version: 2.2.7
4
4
  Summary: Python-based tidal prediction software for estimating ocean, load, solid Earth and pole tides
5
5
  Author: Tyler Sutterley
6
6
  Author-email: tsutterl@uw.edu
@@ -55,12 +55,9 @@ Requires-Dist: numpy
55
55
  Requires-Dist: pyproj
56
56
  Requires-Dist: python-dateutil
57
57
  Requires-Dist: scipy>=1.10.1
58
- Requires-Dist: setuptools_scm
59
58
  Requires-Dist: timescale>=0.0.8
60
59
  Provides-Extra: doc
61
60
  Requires-Dist: docutils; extra == "doc"
62
- Requires-Dist: fontconfig; extra == "doc"
63
- Requires-Dist: freetype; extra == "doc"
64
61
  Requires-Dist: graphviz; extra == "doc"
65
62
  Requires-Dist: myst-nb; extra == "doc"
66
63
  Requires-Dist: numpydoc; extra == "doc"
@@ -133,7 +130,7 @@ To include all optional dependencies:
133
130
 
134
131
  python3 -m pip install pyTMD[all]
135
132
 
136
- Using `conda` or `mamba` from conda-forge:
133
+ Using ``conda`` or ``mamba`` from conda-forge:
137
134
 
138
135
  .. code-block:: bash
139
136
 
@@ -149,6 +146,33 @@ Development version from GitHub:
149
146
 
150
147
  python3 -m pip install git+https://github.com/pyTMD/pyTMD.git
151
148
 
149
+ Running with Pixi
150
+ -----------------
151
+
152
+ Alternatively, you can use `Pixi <https://pixi.sh/>`_ for a streamlined workspace environment:
153
+
154
+ 1. Install Pixi following the `installation instructions <https://pixi.sh/latest/#installation>`_
155
+
156
+ 2. Clone the project repository:
157
+
158
+ .. code-block:: bash
159
+
160
+ git clone https://github.com/pyTMD/pyTMD.git
161
+
162
+ 3. Move into the ``pyTMD`` directory
163
+
164
+ .. code-block:: bash
165
+
166
+ cd pyTMD
167
+
168
+ 4. Install dependencies and start JupyterLab:
169
+
170
+ .. code-block:: bash
171
+
172
+ pixi run start
173
+
174
+ This will automatically create the environment, install all dependencies, and launch JupyterLab in the `notebooks <./doc/source/notebooks/>`_ directory.
175
+
152
176
  Dependencies
153
177
  ############
154
178
 
@@ -158,7 +182,6 @@ Dependencies
158
182
  - `numpy: Scientific Computing Tools For Python <https://www.numpy.org>`_
159
183
  - `pyproj: Python interface to PROJ library <https://pypi.org/project/pyproj/>`_
160
184
  - `scipy: Scientific Tools for Python <https://www.scipy.org/>`_
161
- - `setuptools_scm: manager for python package versions using scm metadata <https://pypi.org/project/setuptools-scm>`_
162
185
  - `timescale: Python tools for time and astronomical calculations <https://pypi.org/project/timescale/>`_
163
186
 
164
187
  References
@@ -202,7 +225,7 @@ Contributing
202
225
  ############
203
226
 
204
227
  This project contains work and contributions from the `scientific community <./CONTRIBUTORS.rst>`_.
205
- If you would like to contribute to the project, please have a look at the `open issues <https://github.com/pyTMD/pyTMD/issues>`_ and `discussions board <https://github.com/pyTMD/pyTMD/discussions>`_.
228
+ If you would like to contribute to the project, please have a look at the `contribution guidelines <./doc/source/getting_started/Contributing.rst>`_, `open issues <https://github.com/pyTMD/pyTMD/issues>`_ and `discussions board <https://github.com/pyTMD/pyTMD/discussions>`_.
206
229
 
207
230
  Credits
208
231
  #######
@@ -46,7 +46,7 @@ To include all optional dependencies:
46
46
 
47
47
  python3 -m pip install pyTMD[all]
48
48
 
49
- Using `conda` or `mamba` from conda-forge:
49
+ Using ``conda`` or ``mamba`` from conda-forge:
50
50
 
51
51
  .. code-block:: bash
52
52
 
@@ -62,6 +62,33 @@ Development version from GitHub:
62
62
 
63
63
  python3 -m pip install git+https://github.com/pyTMD/pyTMD.git
64
64
 
65
+ Running with Pixi
66
+ -----------------
67
+
68
+ Alternatively, you can use `Pixi <https://pixi.sh/>`_ for a streamlined workspace environment:
69
+
70
+ 1. Install Pixi following the `installation instructions <https://pixi.sh/latest/#installation>`_
71
+
72
+ 2. Clone the project repository:
73
+
74
+ .. code-block:: bash
75
+
76
+ git clone https://github.com/pyTMD/pyTMD.git
77
+
78
+ 3. Move into the ``pyTMD`` directory
79
+
80
+ .. code-block:: bash
81
+
82
+ cd pyTMD
83
+
84
+ 4. Install dependencies and start JupyterLab:
85
+
86
+ .. code-block:: bash
87
+
88
+ pixi run start
89
+
90
+ This will automatically create the environment, install all dependencies, and launch JupyterLab in the `notebooks <./doc/source/notebooks/>`_ directory.
91
+
65
92
  Dependencies
66
93
  ############
67
94
 
@@ -71,7 +98,6 @@ Dependencies
71
98
  - `numpy: Scientific Computing Tools For Python <https://www.numpy.org>`_
72
99
  - `pyproj: Python interface to PROJ library <https://pypi.org/project/pyproj/>`_
73
100
  - `scipy: Scientific Tools for Python <https://www.scipy.org/>`_
74
- - `setuptools_scm: manager for python package versions using scm metadata <https://pypi.org/project/setuptools-scm>`_
75
101
  - `timescale: Python tools for time and astronomical calculations <https://pypi.org/project/timescale/>`_
76
102
 
77
103
  References
@@ -115,7 +141,7 @@ Contributing
115
141
  ############
116
142
 
117
143
  This project contains work and contributions from the `scientific community <./CONTRIBUTORS.rst>`_.
118
- If you would like to contribute to the project, please have a look at the `open issues <https://github.com/pyTMD/pyTMD/issues>`_ and `discussions board <https://github.com/pyTMD/pyTMD/discussions>`_.
144
+ If you would like to contribute to the project, please have a look at the `contribution guidelines <./doc/source/getting_started/Contributing.rst>`_, `open issues <https://github.com/pyTMD/pyTMD/issues>`_ and `discussions board <https://github.com/pyTMD/pyTMD/discussions>`_.
119
145
 
120
146
  Credits
121
147
  #######
@@ -36,7 +36,7 @@ from pyTMD.compute_tide_corrections import (
36
36
  compute_SET_corrections,
37
37
  )
38
38
 
39
- # get semantic version from setuptools-scm
39
+ # get version information
40
40
  __version__ = pyTMD.version.version
41
41
  # read model database
42
42
  models = io.load_database()
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  u"""
3
3
  arguments.py
4
- Written by Tyler Sutterley (04/2025)
4
+ Written by Tyler Sutterley (08/2025)
5
5
  Calculates the nodal corrections for tidal constituents
6
6
  Modification of ARGUMENTS fortran subroutine by Richard Ray 03/1999
7
7
 
@@ -39,6 +39,13 @@ REFERENCES:
39
39
  Ocean Tides", Journal of Atmospheric and Oceanic Technology, (2002).
40
40
 
41
41
  UPDATE HISTORY:
42
+ Updated 08/2025: add Cartwright and Tayler table with radiational tides
43
+ make frequency function a wrapper around one that calculates using
44
+ Doodson coefficients (Cartwright numbers)
45
+ add complex love numbers function for correcting out-of-phase effects
46
+ use Mathews et al. (2002) functions for diurnal complex love numbers
47
+ take the absolute value of the constituent angular frequencies
48
+ convert angles with numpy radians and degrees functions
42
49
  Updated 04/2025: convert longitudes p and n to radians within nodal function
43
50
  use schureman_arguments function to get nodal variables for FES models
44
51
  added Schureman to list of M1 options in nodal arguments
@@ -113,7 +120,9 @@ __all__ = [
113
120
  "_arguments_table",
114
121
  "_minor_table",
115
122
  "_constituent_parameters",
123
+ "_frequency",
116
124
  "_love_numbers",
125
+ "_complex_love_numbers",
117
126
  "_parse_tide_potential_table",
118
127
  "_to_constituent_id",
119
128
  "_to_doodson_number",
@@ -233,8 +242,6 @@ def minor_arguments(
233
242
  kwargs.setdefault('deltat', 0.0)
234
243
  kwargs.setdefault('corrections', 'OTIS')
235
244
 
236
- # degrees to radians
237
- dtr = np.pi/180.0
238
245
  # set function for astronomical longitudes
239
246
  # use ASTRO5 routines if not using an OTIS type model
240
247
  if kwargs['corrections'] in ('OTIS','ATLAS','TMD3','netcdf'):
@@ -259,8 +266,8 @@ def minor_arguments(
259
266
  arg = np.dot(fargs, _minor_table())
260
267
 
261
268
  # convert mean longitudes to radians
262
- P = p*dtr
263
- N = n*dtr
269
+ P = np.radians(p)
270
+ N = np.radians(n)
264
271
  # determine nodal corrections f and u
265
272
  sinn = np.sin(N)
266
273
  cosn = np.cos(N)
@@ -554,11 +561,9 @@ def nodal_modulation(
554
561
  FES_TYPE = kwargs['corrections'] in ('FES',)
555
562
  PERTH3_TYPE = kwargs['corrections'] in ('perth3',)
556
563
 
557
- # degrees to radians
558
- dtr = np.pi/180.0
559
564
  # convert longitudes to radians
560
- N = dtr*n
561
- P = dtr*p
565
+ N = np.radians(n)
566
+ P = np.radians(p)
562
567
  # trigonometric factors for nodal corrections
563
568
  sinn = np.sin(N)
564
569
  cosn = np.cos(N)
@@ -615,7 +620,7 @@ def nodal_modulation(
615
620
  term2 = 1.0 - 0.1308*cosn - 0.0534*cos2p - 0.0219*np.cos(2.0*P - N)
616
621
  elif c in ('mf','msqm','msp','mq','mtm') and OTIS_TYPE:
617
622
  f[:,i] = 1.043 + 0.414*cosn
618
- u[:,i] = dtr*(-23.7*sinn + 2.7*sin2n - 0.4*sin3n)
623
+ u[:,i] = np.radians(-23.7*sinn + 2.7*sin2n - 0.4*sin3n)
619
624
  continue
620
625
  elif c in ('mf','msqm','msp','mq','mt','mtm') and FES_TYPE:
621
626
  # Schureman: Table 2, Page 164
@@ -651,7 +656,7 @@ def nodal_modulation(
651
656
  term1 = 0.189*sinn - 0.0058*sin2n
652
657
  term2 = 1.0 + 0.189*cosn - 0.0058*cos2n
653
658
  f[:,i] = np.sqrt(term1**2 + term2**2) # O1
654
- u[:,i] = dtr*(10.8*sinn - 1.3*sin2n + 0.2*sin3n)
659
+ u[:,i] = np.radians(10.8*sinn - 1.3*sin2n + 0.2*sin3n)
655
660
  continue
656
661
  elif c in ('o1','so3','op2','2q1','q1','rho1','sigma1') and FES_TYPE:
657
662
  # Schureman: Table 2, Page 164
@@ -661,7 +666,7 @@ def nodal_modulation(
661
666
  continue
662
667
  elif c in ('q1','o1') and PERTH3_TYPE:
663
668
  f[:,i] = 1.009 + 0.187*cosn - 0.015*cos2n
664
- u[:,i] = dtr*(10.8*sinn - 1.3*sin2n)
669
+ u[:,i] = np.radians(10.8*sinn - 1.3*sin2n)
665
670
  continue
666
671
  elif c in ('o1','so3','op2'):
667
672
  term1 = 0.1886*sinn - 0.0058*sin2n - 0.0065*sin2p
@@ -725,7 +730,7 @@ def nodal_modulation(
725
730
  continue
726
731
  elif c in ('k1',) and PERTH3_TYPE:
727
732
  f[:,i] = 1.006 + 0.115*cosn - 0.009*cos2n
728
- u[:,i] = dtr*(-8.9*sinn + 0.7*sin2n)
733
+ u[:,i] = np.radians(-8.9*sinn + 0.7*sin2n)
729
734
  continue
730
735
  elif c in ('k1','sk3','2sk5'):
731
736
  term1 = -0.1554*sinn + 0.0031*sin2n
@@ -754,7 +759,7 @@ def nodal_modulation(
754
759
  continue
755
760
  elif c in ('m2','n2') and PERTH3_TYPE:
756
761
  f[:,i] = 1.000 - 0.037*cosn
757
- u[:,i] = dtr*(-2.1*sinn)
762
+ u[:,i] = np.radians(-2.1*sinn)
758
763
  continue
759
764
  elif c in ('m2','2n2','mu2','n2','nu2','lambda2','ms4','eps2','2sm6',
760
765
  '2sn6','mp1','mp3','sn4'):
@@ -789,7 +794,7 @@ def nodal_modulation(
789
794
  continue
790
795
  elif c in ('k2',) and PERTH3_TYPE:
791
796
  f[:,i] = 1.024 + 0.286*cosn + 0.008*cos2n
792
- u[:,i] = dtr*(-17.7*sinn + 0.7*sin2n)
797
+ u[:,i] = np.radians(-17.7*sinn + 0.7*sin2n)
793
798
  continue
794
799
  elif c in ('k2','sk4','2sk6','kp1'):
795
800
  term1 = -0.3108*sinn - 0.0324*sin2n
@@ -855,7 +860,7 @@ def nodal_modulation(
855
860
  elif c in ('mfdw',):
856
861
  # special test of Doodson-Warburg formula
857
862
  f[:,i] = 1.043 + 0.414*cosn
858
- u[:,i] = dtr*(-23.7*sinn + 2.7*sin2n - 0.4*sin3n)
863
+ u[:,i] = np.radians(-23.7*sinn + 2.7*sin2n - 0.4*sin3n)
859
864
  continue
860
865
  elif c in ('so1','2so3','2po1'):
861
866
  # compound tides calculated using recursion
@@ -1267,13 +1272,11 @@ def group_modulation(
1267
1272
  angle correction (radians)
1268
1273
  """
1269
1274
 
1270
- # degrees to radians
1271
- dtr = np.pi/180.0
1272
1275
  # convert longitudes to radians
1273
- H = dtr*h
1274
- Np = -dtr*n
1275
- P = dtr*p
1276
- Ps = dtr*ps
1276
+ H = np.radians(h)
1277
+ Np = -np.radians(n)
1278
+ P = np.radians(p)
1279
+ Ps = np.radians(ps)
1277
1280
  # mean anomaly of the sun
1278
1281
  lp = H - Ps
1279
1282
 
@@ -1521,8 +1524,8 @@ def frequency(
1521
1524
  **kwargs
1522
1525
  ):
1523
1526
  """
1524
- Calculates the angular frequency for tidal constituents
1525
- :cite:p:`Ray:1999vm`
1527
+ Wrapper function for calculating the angular frequency
1528
+ for tidal constituents :cite:p:`Ray:1999vm`
1526
1529
 
1527
1530
  Parameters
1528
1531
  ----------
@@ -1549,31 +1552,13 @@ def frequency(
1549
1552
  # set function for astronomical longitudes
1550
1553
  # use ASTRO5 routines if not using an OTIS type model
1551
1554
  if kwargs['corrections'] in ('OTIS','ATLAS','TMD3','netcdf'):
1552
- method = 'Cartwright'
1555
+ kwargs.setdefault('method', 'Cartwright')
1553
1556
  else:
1554
- method = 'ASTRO5'
1555
- # Modified Julian Dates at J2000
1556
- MJD = np.array([51544.5, 51544.55])
1557
- # time interval in seconds
1558
- deltat = 86400.0*(MJD[1] - MJD[0])
1559
- # calculate the mean longitudes of the sun and moon
1560
- s, h, p, n, pp = pyTMD.astro.mean_longitudes(MJD, method=method)
1561
-
1562
- # number of temporal values
1563
- nt = len(np.atleast_1d(MJD))
1564
- # initial time conversions
1565
- hour = 24.0*np.mod(MJD, 1)
1566
- # convert from hours solar time into mean lunar time in degrees
1567
- tau = 15.0*hour - s + h
1568
- # variable for multiples of 90 degrees (Ray technical note 2017)
1569
- k = 90.0 + np.zeros((nt))
1570
-
1571
- # determine equilibrium arguments
1572
- fargs = np.c_[tau, s, h, p, n, pp, k]
1573
- rates = (fargs[1,:] - fargs[0,:])/deltat
1574
- fd = np.dot(rates, coefficients_table(constituents, **kwargs))
1575
- # convert to radians per second
1576
- omega = 2.0*np.pi*fd/360.0
1557
+ kwargs.setdefault('method', 'ASTRO5')
1558
+ # get Doodson coefficients
1559
+ coef = coefficients_table(constituents, **kwargs)
1560
+ # calculate the angular frequency
1561
+ omega = _frequency(coef, **kwargs)
1577
1562
  return omega
1578
1563
 
1579
1564
  def aliasing_period(
@@ -1769,9 +1754,62 @@ def _constituent_parameters(c: str, **kwargs):
1769
1754
  # return the values for the constituent
1770
1755
  return (amplitude, phase, omega, alpha, species)
1771
1756
 
1757
+ def _frequency(
1758
+ coef: np.ndarray,
1759
+ **kwargs
1760
+ ):
1761
+ """
1762
+ Calculates the angular frequency for Doodson coefficients
1763
+ (Cartwright numbers) :cite:p:`Ray:1999vm`
1764
+
1765
+ Parameters
1766
+ ----------
1767
+ coef: list or np.ndarray
1768
+ Doodson coefficients (Cartwright numbers) for constituents
1769
+ method: str, default 'Cartwright'
1770
+ Method for computing the mean longitudes
1771
+
1772
+ - ``'Cartwright'``
1773
+ - ``'Meeus'``
1774
+ - ``'ASTRO5'``
1775
+ - ``'IERS'``
1776
+
1777
+ Returns
1778
+ -------
1779
+ omega: np.ndarray
1780
+ angular frequency in radians per second
1781
+ """
1782
+ # set default keyword arguments
1783
+ kwargs.setdefault('method', 'Cartwright')
1784
+ # Modified Julian Dates at J2000
1785
+ MJD = np.array([51544.5, 51544.55])
1786
+ # time interval in seconds
1787
+ deltat = 86400.0*(MJD[1] - MJD[0])
1788
+ # calculate the mean longitudes of the sun and moon
1789
+ s, h, p, n, pp = pyTMD.astro.mean_longitudes(MJD,
1790
+ method=kwargs['method'])
1791
+
1792
+ # number of temporal values
1793
+ nt = len(np.atleast_1d(MJD))
1794
+ # initial time conversions
1795
+ hour = 24.0*np.mod(MJD, 1)
1796
+ # convert from hours solar time into mean lunar time in degrees
1797
+ tau = 15.0*hour - s + h
1798
+ # variable for multiples of 90 degrees (Ray technical note 2017)
1799
+ k = 90.0 + np.zeros((nt))
1800
+
1801
+ # determine equilibrium arguments
1802
+ fargs = np.c_[tau, s, h, p, n, pp, k]
1803
+ rates = (fargs[1,:] - fargs[0,:])/deltat
1804
+ fd = np.dot(rates, coef)
1805
+ # convert to radians per second
1806
+ omega = 2.0*np.pi*fd/360.0
1807
+ return np.abs(omega)
1808
+
1772
1809
  def _love_numbers(
1773
1810
  omega: np.ndarray,
1774
- model: str = 'PREM'
1811
+ model: str = 'PREM',
1812
+ **kwargs
1775
1813
  ):
1776
1814
  """
1777
1815
  Compute the body tide Love/Shida numbers for a given frequency
@@ -1790,6 +1828,8 @@ def _love_numbers(
1790
1828
  - 'PEM-C'
1791
1829
  - 'C2'
1792
1830
  - 'PREM'
1831
+ astype: np.dtype, default np.float64
1832
+ data type for the output Love numbers
1793
1833
 
1794
1834
  Returns
1795
1835
  -------
@@ -1800,6 +1840,8 @@ def _love_numbers(
1800
1840
  l2: float
1801
1841
  Degree-2 Love (Shida) number of horizontal displacement
1802
1842
  """
1843
+ # set default keyword arguments
1844
+ kwargs.setdefault('astype', np.float64)
1803
1845
  # free core nutation frequencies (cycles per sidereal day) and
1804
1846
  # Love number parameters from Wahr (1981) table 6
1805
1847
  # and Mathews et al. (1995) table 3
@@ -1850,7 +1892,7 @@ def _love_numbers(
1850
1892
  # calculate love numbers following J. Wahr (1979)
1851
1893
  # use resonance formula for tides in the diurnal band
1852
1894
  # frequency of the o1 tides (radians/second)
1853
- omega_o1, = frequency('o1')
1895
+ omega_o1, = frequency('o1', **kwargs)
1854
1896
  # convert frequency from cycles per sidereal day
1855
1897
  # frequency of free core nutation (radians/second)
1856
1898
  omega_fcn = lambda_fcn*7292115e-11
@@ -1861,22 +1903,127 @@ def _love_numbers(
1861
1903
  k2 = k0 + k1*ratio
1862
1904
  l2 = l0 + l1*ratio
1863
1905
  # return the Love numbers for frequency
1864
- return (h2, k2, l2)
1906
+ return np.array([h2, k2, l2], dtype=kwargs['astype'])
1907
+
1908
+ def _complex_love_numbers(
1909
+ omega: np.ndarray,
1910
+ **kwargs
1911
+ ):
1912
+ """
1913
+ Compute the complex body tide Love/Shida numbers with in-phase
1914
+ and out-of-phase components for a given frequency
1915
+ :cite:p:`Mathews:1997js,Mathews:2002cr,Petit:2010tp`
1916
+
1917
+ Parameters
1918
+ ----------
1919
+ omega: np.ndarray
1920
+ angular frequency (radians per second)
1921
+ kwargs: dict
1922
+ additional keyword arguments for love number calculation
1923
+
1924
+ Returns
1925
+ -------
1926
+ h2: complex
1927
+ Degree-2 Love number of vertical displacement
1928
+ k2: complex
1929
+ Degree-2 Love number of gravitational potential
1930
+ l2: complex
1931
+ Degree-2 Love (Shida) number of horizontal displacement
1932
+ """
1933
+ # (number of sidereal days per solar day)
1934
+ sidereal_ratio = 1.002737909
1935
+ # number of seconds in a sidereal day (approx 86164.1)
1936
+ sidereal_day = 86400.0/sidereal_ratio
1937
+ # frequency in cycles per sidereal day
1938
+ f = omega*sidereal_day/(2.0*np.pi)
1939
+ # Love numbers for different frequency bands
1940
+ if (omega == 0.0):
1941
+ # use real-valued body tide love numbers for permanent tide
1942
+ h2, k2, l2 = _love_numbers(omega, **kwargs)
1943
+ elif (omega > 1e-4):
1944
+ # in-phase and out-of-phase components for the semi-diurnal band
1945
+ h2 = 0.6078 - 0.0022j
1946
+ k2 = 0.30102 - 0.0013j
1947
+ l2 = 0.0847 - 0.0007j
1948
+ elif (omega < 2e-5):
1949
+ # compute in-phase and out-of-phase components for the long period band
1950
+ # variation largely due to mantle anelasticity
1951
+ alpha = 0.15
1952
+ # frequency equivalent to 200s
1953
+ fm = sidereal_day/200.0
1954
+ factor = np.tan(alpha*np.pi/2.0)**(-1)
1955
+ anelasticity_model = factor*(1.0 - (fm/f)**alpha) + 1j*(fm/f)**alpha
1956
+ # model for the variation of love numbers across the zonal tide band
1957
+ h2 = 0.5998 - 9.96e-4*anelasticity_model
1958
+ k2 = 0.29525 - 5.796e-4*anelasticity_model
1959
+ l2 = 0.0831 - 3.01e-4*anelasticity_model
1960
+ else:
1961
+ # in-phase and out-of-phase components for the diurnal band
1962
+ # following IERS conventions and Mathews et al. (2002)
1963
+ # values from equation 6.10 of IERS conventions 2010
1964
+ # and from Mathews et al. (2002)
1965
+ sigma = np.zeros((4), dtype=np.complex128)
1966
+ # factor for calculating L0
1967
+ sigma[0] = f - 1.0
1968
+ # Chandler wobble
1969
+ sigma[1] = -0.0026010 - 0.0001361j
1970
+ # retrograde free core nutation
1971
+ sigma[2] = 1.0023181 + 0.000025j
1972
+ # prograde free core nutation
1973
+ sigma[3] = 0.999026 + 0.000780j
1974
+ # frequency dependence of Love number h2
1975
+ H2 = np.zeros((4), dtype=np.complex128)
1976
+ H2[0] = 0.60671 - 0.242e-2j
1977
+ H2[1] = -0.15777e-2 - 0.7630e-4j
1978
+ H2[2] = 0.18053e-3 - 0.6292e-5j
1979
+ H2[3] = -0.18616e-5 + 0.1379e-6j
1980
+ # frequency dependence of Love number k2
1981
+ K2 = np.zeros((4), dtype=np.complex128)
1982
+ K2[0] = 0.29954 - 0.1412e-2j
1983
+ K2[1] = -0.77896e-3 - 0.3711e-4j
1984
+ K2[2] = 0.90963e-4 - 0.2963e-5j
1985
+ K2[3] = -0.11416e-5 + 0.5325e-7j
1986
+ # frequency dependence of Love number l2
1987
+ L2 = np.zeros((4), dtype=np.complex128)
1988
+ L2[0] = 0.84963e-1 - 0.7395e-3j
1989
+ L2[1] = -0.22107e-3 - 0.9446e-5j
1990
+ L2[2] = 0.54710e-5 - 0.2990e-6j
1991
+ L2[3] = -0.29904e-7 - 0.7717e-8j
1992
+ # estimate the complex Love number fors diurnal tides
1993
+ # equation 6.9 of IERS conventions 2010
1994
+ h2 = np.sum(H2/(f - sigma))
1995
+ k2 = np.sum(K2/(f - sigma))
1996
+ l2 = np.sum(L2/(f - sigma))
1997
+
1998
+ # return the Love numbers as a complex number
1999
+ return np.array([h2, k2, l2], dtype=np.complex128)
1865
2000
 
1866
2001
  # Doodson (1921) table with values missing from Cartwright tables
2002
+ # Hs1: amplitude for epoch span 1 (1900 epoch)
1867
2003
  _d1921_table = get_data_path(['data','d1921_tab.txt'])
1868
2004
  # Cartwright and Tayler (1971) table with 3rd-degree values
2005
+ # Hs1: amplitude for epoch span 1 (1861-09-21 to 1879-09-22)
2006
+ # Hs2: amplitude for epoch span 2 (1915-05-16 to 1933-05-22)
2007
+ # Hs3: amplitude for epoch span 2 (1951-05-23 to 1969-05-22)
1869
2008
  _ct1971_table_5 = get_data_path(['data','ct1971_tab5.txt'])
1870
2009
  # Cartwright and Edden (1973) table with updated values
1871
2010
  _ce1973_table_1 = get_data_path(['data','ce1973_tab1.txt'])
2011
+ # Cartwright and Tayler (1971) table with radiational tides
2012
+ # Hs1: amplitude for epoch span 1 (1900 epoch)
2013
+ _ct1971_table_6 = get_data_path(['data','ct1971_tab6.txt'])
1872
2014
 
1873
- def _parse_tide_potential_table(table: str | pathlib.Path):
2015
+ def _parse_tide_potential_table(
2016
+ table: str | pathlib.Path,
2017
+ columns: int = 3,
2018
+ ):
1874
2019
  """Parse tables of tide-generating potential
1875
2020
 
1876
2021
  Parameters
1877
2022
  ----------
1878
2023
  table: str or pathlib.Path
1879
2024
  table of tide-generating potentials
2025
+ columns: int, default 3
2026
+ number of amplitude columns in the table
1880
2027
 
1881
2028
  Returns
1882
2029
  -------
@@ -1895,18 +2042,26 @@ def _parse_tide_potential_table(table: str | pathlib.Path):
1895
2042
  # p: coefficient for mean longitude of lunar perigee
1896
2043
  # n: coefficient for mean longitude of ascending lunar node
1897
2044
  # pp: coefficient for mean longitude of solar perigee
1898
- # Hs1: amplitude for epoch span 1 (1861-09-21 to 1879-09-22)
1899
- # Hs2: amplitude for epoch span 2 (1915-05-16 to 1933-05-22)
1900
- # Hs3: amplitude for epoch span 2 (1951-05-23 to 1969-05-22)
1901
- # DO: Doodson number for coefficient
1902
- # Hs0: Doodson scaled amplitude for 1900
1903
- names = ('tau','s','h','p','n','pp','Hs1','Hs2','Hs3','DO','Hs0')
1904
- formats = ('i','i','i','i','i','i','f','f','f','U7','f')
2045
+ names = ['tau','s','h','p','n','pp']
2046
+ formats = ['i','i','i','i','i','i']
2047
+ for c in range(columns):
2048
+ # add amplitude columns to names and formats
2049
+ names.append(f'Hs{c+1}')
2050
+ formats.append('f8')
2051
+ # add Doodson number
2052
+ names.append('DO')
2053
+ formats.append('U7')
2054
+ # create a structured numpy dtype for the table
2055
+ # names: names of the columns in the table
2056
+ # formats: data types for each column in the table
1905
2057
  dtype = np.dtype({'names':names, 'formats':formats})
1906
2058
  CTE = np.zeros((file_lines), dtype=dtype)
2059
+ # number of output columns
2060
+ columns = len(names)
2061
+ # iterate over each line in the file
1907
2062
  for i,line in enumerate(file_contents):
1908
2063
  # drop last column with values from Doodson (1921)
1909
- CTE[i] = np.array(tuple(line.split()[:11]), dtype=dtype)
2064
+ CTE[i] = np.array(tuple(line.split()[:columns]), dtype=dtype)
1910
2065
  # return the table values
1911
2066
  return CTE
1912
2067