Skip to content

Commit

Permalink
feat: add spherical harmonic functions (#362)
Browse files Browse the repository at this point in the history
* refactor: move generic `astro` functions to `math.py`
* feat: add function to calculate altitude, azimuth and D
* test: add test for unnormalized legendre polynomials
* test: moved `normalize_angle` test to `test_math.py`
* test: add ECEF to altaz test at USNO
  • Loading branch information
tsutterley authored Nov 14, 2024
1 parent 654cc15 commit 872a091
Show file tree
Hide file tree
Showing 17 changed files with 448 additions and 147 deletions.
6 changes: 0 additions & 6 deletions doc/source/api_reference/astro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ Calling Sequence

.. __: https://github.com/tsutterley/pyTMD/blob/main/pyTMD/astro.py

.. autofunction:: pyTMD.astro.polynomial_sum

.. autofunction:: pyTMD.astro.normalize_angle

.. autofunction:: pyTMD.astro.rotate

.. autofunction:: pyTMD.astro.mean_longitudes

.. autofunction:: pyTMD.astro.doodson_arguments
Expand Down
27 changes: 27 additions & 0 deletions doc/source/api_reference/math.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
====
math
====

- Special functions of mathematical physics

Calling Sequence
----------------

.. code-block:: python
import pyTMD.math
P = pyTMD.math.legendre(2, x, m=0)
`Source code`__

.. __: https://github.com/tsutterley/pyTMD/blob/main/pyTMD/math.py

.. autofunction:: pyTMD.math.polynomial_sum

.. autofunction:: pyTMD.math.normalize_angle

.. autofunction:: pyTMD.math.rotate

.. autofunction:: pyTMD.math.legendre

.. autofunction:: pyTMD.math.sph_harm
2 changes: 2 additions & 0 deletions doc/source/api_reference/spatial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,6 @@ General Methods

.. autofunction:: pyTMD.spatial.from_ENU

.. autofunction:: pyTMD.spatial.to_horizontal

.. autofunction:: pyTMD.spatial.scale_factors
3 changes: 3 additions & 0 deletions doc/source/getting_started/Glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ Glossary
Pole Tide
apparent tide due to variations in the Earth's axis of rotation about its mean

Radiational Tide
tidal constituents or components induced by the absorption and re-emission of solar radiation

Range
height difference between the :term:`High Water Height` and the :term:`Low Water Height`

Expand Down
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ocean, load, solid Earth and pole tides
api_reference/ellipse.rst
api_reference/interpolate.rst
api_reference/io/io.rst
api_reference/math.rst
api_reference/predict.rst
api_reference/solve/solve.rst
api_reference/spatial.rst
Expand Down
2 changes: 1 addition & 1 deletion doc/source/release_notes/release-v2.1.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* ``docs``: add citations to included data `(#353) <https://github.com/tsutterley/pyTMD/pull/353>`_
* ``fix``: remove default bounds being ``None`` for `#356 <https://github.com/tsutterley/pyTMD/issues/356>`_ `(#357) <https://github.com/tsutterley/pyTMD/pull/357>`_
* ``docs``: move notebooks to docs and use myst to render `(#359) <https://github.com/tsutterley/pyTMD/pull/359>`_
* ``fix``: correct error when using default bounds in `extract_constants` for `#356 <https://github.com/tsutterley/pyTMD/issues/356>`_ `(#359) <https://github.com/tsutterley/pyTMD/pull/359>`_
* ``fix``: correct error when using default bounds in ``extract_constants`` for `#356 <https://github.com/tsutterley/pyTMD/issues/356>`_ `(#359) <https://github.com/tsutterley/pyTMD/pull/359>`_
* ``fix``: correct ``TPXO10-atlas-v2`` binary grid filename for `#358 <https://github.com/tsutterley/pyTMD/issues/358>`_ `(#359) <https://github.com/tsutterley/pyTMD/pull/359>`_
* ``fix``: some `Cartwright and Edden (1973) <http://dx.doi.org/10.1111/j.1365-246X.1971.tb01803.x>`_ table entries `(#359) <https://github.com/tsutterley/pyTMD/pull/359>`_
* ``docs``: use cards for notebook examples page `(#360) <https://github.com/tsutterley/pyTMD/pull/360>`_
Expand Down
1 change: 1 addition & 0 deletions pyTMD/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import pyTMD.compute
import pyTMD.ellipse
import pyTMD.interpolate
import pyTMD.math
import pyTMD.predict
import pyTMD.spatial
import pyTMD.tools
Expand Down
84 changes: 10 additions & 74 deletions pyTMD/astro.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
u"""
astro.py
Written by Tyler Sutterley (07/2024)
Written by Tyler Sutterley (11/2024)
Astronomical and nutation routines
PYTHON DEPENDENCIES:
Expand All @@ -16,6 +16,7 @@
Oliver Montenbruck, Practical Ephemeris Calculations, 1989.
UPDATE HISTORY:
Updated 11/2024: moved three generic mathematical functions to math.py
Updated 07/2024: made a wrapper function for normalizing angles
make number of days to convert days since an epoch to MJD variables
Updated 04/2024: use wrapper to importlib for optional dependencies
Expand Down Expand Up @@ -53,6 +54,11 @@
import numpy as np
import timescale.eop
import timescale.time
from pyTMD.math import (
polynomial_sum,
normalize_angle,
rotate
)
from pyTMD.utilities import (
get_data_path,
import_dependency,
Expand All @@ -62,9 +68,6 @@
jplephem_spk = import_dependency('jplephem.spk')

__all__ = [
"polynomial_sum",
"normalize_angle",
"rotate",
"mean_longitudes",
"phase_angles",
"doodson_arguments",
Expand Down Expand Up @@ -101,74 +104,6 @@
# Julian century
_century = 36525.0

# PURPOSE: calculate the sum of a polynomial function of time
def polynomial_sum(coefficients: list | np.ndarray, t: np.ndarray):
"""
Calculates the sum of a polynomial function using Horner's method
Parameters
----------
coefficients: list or np.ndarray
leading coefficient of polynomials of increasing order
t: np.ndarray
delta time in units for a given astronomical longitudes calculation
"""
# convert time to array if importing a single value
t = np.atleast_1d(t)
return np.sum([c * (t ** i) for i, c in enumerate(coefficients)], axis=0)

def normalize_angle(theta: float | np.ndarray, circle: float = 360.0):
"""
Normalize an angle to a single rotation
Parameters
----------
theta: float or np.ndarray
Angle to normalize
circle: float, default 360.0
Circle of the angle
"""
return np.mod(theta, circle)

def rotate(theta: float | np.ndarray, axis: str = 'x'):
"""
Rotate a 3-dimensional matrix about a given axis
Parameters
----------
theta: float or np.ndarray
Angle of rotation in radians
axis: str
Axis of rotation (``'x'``, ``'y'``, or ``'z'``)
"""
# allocate for output rotation matrix
R = np.zeros((3, 3, len(np.atleast_1d(theta))))
if (axis.lower() == 'x'):
# rotate about x-axis
R[0,0,:] = 1.0
R[1,1,:] = np.cos(theta)
R[1,2,:] = np.sin(theta)
R[2,1,:] = -np.sin(theta)
R[2,2,:] = np.cos(theta)
elif (axis.lower() == 'y'):
# rotate about y-axis
R[0,0,:] = np.cos(theta)
R[0,2,:] = -np.sin(theta)
R[1,1,:] = 1.0
R[2,0,:] = np.sin(theta)
R[2,2,:] = np.cos(theta)
elif (axis.lower() == 'z'):
# rotate about z-axis
R[0,0,:] = np.cos(theta)
R[0,1,:] = np.sin(theta)
R[1,0,:] = -np.sin(theta)
R[1,1,:] = np.cos(theta)
R[2,2,:] = 1.0
else:
raise ValueError(f'Invalid axis {axis}')
# return the rotation matrix
return R

# PURPOSE: compute the basic astronomical mean longitudes
def mean_longitudes(
MJD: np.ndarray,
Expand Down Expand Up @@ -352,8 +287,9 @@ def doodson_arguments(
# Equinox method converted to degrees
TAU = 360.0*ts.st + 180.0 - S
else:
TAU = ((hour*15.0) - S + polynomial_sum(np.array([280.4606184,
36000.7700536, 3.8793e-4, -2.58e-8]), T))
LAMBDA = polynomial_sum(np.array([280.4606184,
36000.7700536, 3.8793e-4, -2.58e-8]), T)
TAU = (hour*15.0) - S + LAMBDA
# calculate correction for mean lunar longitude (degrees)
if apply_correction:
PR = polynomial_sum(np.array([0.0, 1.396971278,
Expand Down
Loading

0 comments on commit 872a091

Please sign in to comment.