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

Add conversion routines between ellipsoidal-harmonic and geodetic coordinates #186

Closed
wants to merge 4 commits into from
Closed
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
122 changes: 120 additions & 2 deletions boule/_ellipsoid.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@
-------
longitude : array
Longitude coordinates on geocentric spherical coordinate system in
degrees.
The longitude coordinates are not modified during this conversion.
degrees. The longitude coordinates are not modified during this
conversion.
spherical_latitude : array
Converted latitude coordinates on geocentric spherical coordinate
system in degrees.
Expand Down Expand Up @@ -501,6 +501,124 @@
height = (k + self.eccentricity**2 - 1) / k * hypot_dz
return longitude, latitude, height

def geodetic_to_ellipsoidal_harmonic(self, longitude, latitude, height):
"""
Convert from geodetic to ellipsoidal-harmonic coordinates.

The geodetic datum is defined by this ellipsoid, and the coordinates
are converted following [Lakshmanan1991]_ and [LiGotze2001].

Parameters
----------
longitude : array
Longitude coordinates on geodetic coordinate system in degrees.
latitude : array
Latitude coordinates on geodetic coordinate system in degrees.
height : array
Ellipsoidal heights in meters.

Returns
-------
longitude : array
Longitude coordinates on ellipsoidal-harmonic coordinate system in
degrees. The longitude coordinates are not modified during this
conversion.
reduced_latitude : array
The reduced (or parametric) latitude in degrees.
u : array
The coordinate u, which is the semiminor axis of the ellipsoid that
passes through the input coordinates.
"""
if np.array(height).all() == 0:
# Use simple formula that relates geodetic and reduced latitude
beta = np.degrees(

Check warning on line 534 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L534

Added line #L534 was not covered by tests
np.arctan(
self.semiminor_axis
/ self.semimajor_axis
* np.tan(np.radians(latitude))
)
)
u = self.semiminor_axis

Check warning on line 541 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L541

Added line #L541 was not covered by tests

return longitude, beta, u

Check warning on line 543 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L543

Added line #L543 was not covered by tests

else:
# The variable names follow Li and Goetze (2001). The prime terms
# (*_p) refer to quantities on an ellipsoid passing through the
# computation point.
sinlat = np.sin(np.radians(latitude))
coslat = np.sqrt(1 - sinlat**2)

Check warning on line 550 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L549-L550

Added lines #L549 - L550 were not covered by tests

# Reduced latitude of the projection of the point on the
# reference ellipsoid
beta = np.arctan2(

Check warning on line 554 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L554

Added line #L554 was not covered by tests
self.semiminor_axis * sinlat, self.semimajor_axis * coslat
)
sinbeta = np.sin(beta)
cosbeta = np.sqrt(1 - sinbeta**2)

Check warning on line 558 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L557-L558

Added lines #L557 - L558 were not covered by tests

# Distance squared between computation point and equatorial plane
z_p2 = (self.semiminor_axis * sinbeta + height * sinlat) ** 2

Check warning on line 561 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L561

Added line #L561 was not covered by tests
# Distance squared between computation point and spin axis
r_p2 = (self.semimajor_axis * cosbeta + height * coslat) ** 2

Check warning on line 563 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L563

Added line #L563 was not covered by tests

# Auxiliary variables
big_d = (r_p2 - z_p2) / self.linear_eccentricity**2
big_r = (r_p2 + z_p2) / self.linear_eccentricity**2

Check warning on line 567 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L566-L567

Added lines #L566 - L567 were not covered by tests

# cos(reduced latitude) squared of the computation point
cosbeta_p2 = 0.5 + big_r / 2 - np.sqrt(0.25 + big_r**2 / 4 - big_d / 2)

Check warning on line 570 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L570

Added line #L570 was not covered by tests

# Semiminor axis of ellipsoid passing through the computation point
b_p = np.sqrt(r_p2 + z_p2 - self.linear_eccentricity**2 * cosbeta_p2)

Check warning on line 573 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L573

Added line #L573 was not covered by tests

beta_p = np.degrees(np.arccos(np.sqrt(cosbeta_p2)))

Check warning on line 575 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L575

Added line #L575 was not covered by tests

return longitude, beta_p, b_p

Check warning on line 577 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L577

Added line #L577 was not covered by tests

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit strange because in the docstring they have other names :)

Copy link
Contributor Author

@MarkWieczorek MarkWieczorek Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could change this to just u and reduced_latitude. The only reason I did it this way was that these are the names of the parameters in the paper we cite, and they are also the names of the variables used in the normal gravity routine. When writing this, I originally used u and then changed it at the end, so I don't have any preference either way...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it makes sense. Perhaps change just the docstring so you don't have surprise ;-) but it is a nit


def ellipsoidal_harmonic_to_geodetic(self, longitude, reduced_latitude, u):
"""
Convert from ellipsoidal-harmonic coordinates to geodetic coordinates.

The geodetic datum is defined by this ellipsoid.

Parameters
----------
longitude : array
Longitude coordinates on ellipsoidal-harmonic coordinate system in
degrees.
latitude : array
Reduced (parametric) latitude coordinates on ellipsoidal-harmonic
coordinate system in degrees.
u : array
The coordinate u, which is the semiminor axes of the ellipsoid that
passes through the input coordinates.

Returns
-------
longitude : array
Longitude coordinates on geodetic coordinate system in degrees. The
longitude coordinates are not modified during this conversion.
latitude : array
Latitude coordinates on geodetic coordinate system in degrees.
height : array
Ellipsoidal heights in meters.
"""
# semimajor axis of the ellipsoid that passes through the input
# coordinates
a_p = np.sqrt(u**2 + self.linear_eccentricity**2)

Check warning on line 609 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L609

Added line #L609 was not covered by tests

# geodetic latitude
latitude = np.arctan(a_p / u * np.tan(np.radians(reduced_latitude)))

Check warning on line 612 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L612

Added line #L612 was not covered by tests

# Compute height as the difference of the prime_vertical_radius of the
# input ellipsoid and reference ellipsoid
height = self.prime_vertical_radius(np.sin(latitude)) * (

Check warning on line 616 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L616

Added line #L616 was not covered by tests
a_p / self.semimajor_axis - 1
)

return longitude, np.degrees(latitude), height

Check warning on line 620 in boule/_ellipsoid.py

View check run for this annotation

Codecov / codecov/patch

boule/_ellipsoid.py#L620

Added line #L620 was not covered by tests

def normal_gravity(self, latitude, height, si_units=False):
r"""
Normal gravity of the ellipsoid at the given latitude and height.
Expand Down
Loading