Code Monkey home page Code Monkey logo

boule's Introduction

Boule

Reference ellipsoids for geodesy and geophysics

Documentation (latest)Documentation (main branch)ContributingContact

Part of the Fatiando a Terra project

Latest version on PyPI Latest version on conda-forge Test coverage status Compatible Python versions. DOI used to cite Boule

About

Boule is Python library for representing reference ellipsoids, calculating their gravity fields, and performing some global coordinate conversions. "Boule" is also French for "ball" as well as a traditional shape of bread resembling a squashed ball.

Some examples of where Boule can be applied:

  • Storing and manipulating ellipsoid parameters for spherical harmonic analysis.
  • Calculating normal gravity for generating gravity anomalies and disturbances.
  • Modelling in spherical coordinates, which requires geodetic to geocentric spherical coordinate conversions.

Project goals

  • Provide a representation of ellipsoid parameters and derived quantities, including units and citations.
  • Convert between geodetic coordinates and geocentric spherical, topocentric, etc.
  • Calculate the gravity, gravitational, and centrifugal potential (and its derivatives) of ellipsoids in closed form.
  • Include a range ellipsoids for the Earth and other planetary bodies.

Project status

Boule is ready for use but still changing. This means that we sometimes break backwards compatibility as we try to improve the software based on user experience, new ideas, better design decisions, etc. Please keep that in mind before you update Boule to a newer version.

We welcome feedback and ideas! This is a great time to bring new ideas on how we can improve the project. Join the conversation or submit issues on GitHub.

Getting involved

🗨️ Contact us: Find out more about how to reach us at fatiando.org/contact.

👩🏾‍💻 Contributing to project development: Please read our Contributing Guide to see how you can help and give feedback.

🧑🏾‍🤝‍🧑🏼 Code of conduct: This project is released with a Code of Conduct. By participating in this project you agree to abide by its terms.

Imposter syndrome disclaimer: We want your help. No, really. There may be a little voice inside your head that is telling you that you're not ready, that you aren't skilled enough to contribute. We assure you that the little voice in your head is wrong. Most importantly, there are many valuable ways to contribute besides writing code.

This disclaimer was adapted from the MetPy project.

License

This is free software: you can redistribute it and/or modify it under the terms of the BSD 3-clause License. A copy of this license is provided in LICENSE.txt.

boule's People

Contributors

aguspesce avatar blazej-bucha avatar dabiged avatar dependabot[bot] avatar fatiando-bot avatar hugovk avatar leouieda avatar ll-geo avatar markwieczorek avatar rowanc1 avatar santisoler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

boule's Issues

Release v0.4.0

Zenodo DOI: 10.5281/zenodo.6779998

Target date: 2022/06/30

Draft a Zenodo archive (to be done by a manager on Zenodo)

  • Go to the Zenodo entry for this project (find the link to the latest Zenodo release on the README.md file)
  • Create a "New version" of it.
  • Delete all existing files
  • Copy the reserved DOI to this issue
  • Update release date
  • Update version number (make sure there is a leading v, like v1.5.7)
  • Add as authors any new contributors who have added themselves to AUTHORS.md in the same order
  • Ensure that the first author is "Fatiando a Terra Project" and others are listed alphabetically by last name
  • Save the release draft

Update the changelog

  • Generate a list of commits between the last release tag and now: git log HEAD...v1.2.3 > changes.rst
  • Edit the list to remove any trivial changes (updates by the bot, CI updates, etc).
  • Organize the list into categories (breaking changes, deprecations, bug fixes, new features, maintenance, documentation).
  • Add a list of people who contributed to the release: git shortlog HEAD...v1.2.3 -sne
  • Add the release date and Zenodo DOI badge to the top
  • Replace the PR numbers with links: sed --in-place "s,#\([0-9]\+\),\`#\1 <https://github.com/fatiando/PROJECT/pull/\1>\`__,g" changes.rst
  • Copy the changes to doc/changes.rst
  • Make a Markdown copy of the changelog: pandoc -s changes.rst -o changes.md --wrap=none
  • Add a link to the new release version documentation in README.rst and doc/versions.rst (if the file exists).
  • Build and serve the docs locally with make -C doc all serve to check if the changelog looks well
  • Open a PR to update the changelog
  • Merge the PR

Make a release

After the changelog PR is merged:

  • Draft a new release on GitHub
  • The tag and release name should be a version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Fill the release description with a Markdown version of the latest changelog entry (including the DOI badge)
  • Publish the release

Publish to Zenodo

  • Upload the zip archive from the GitHub release to Zenodo
  • Double check all information (date, authors, version)
  • Publish the new version on Zenodo

Conda-forge package

A PR should be opened automatically on the project feedstock repository.

  • Add/remove/update any dependencies that have changed in meta.yaml
  • If dropping/adding support for Python/numpy versions, make sure the correct version restrictions are applied in meta.yaml
  • Merge the PR

Release v0.3.1

Info
Version number v0.3.1
Target date 2021/10/19
Zenodo DOI 10.5281/zenodo.5577885

Draft a Zenodo archive (to be done by a manager on Zenodo)

  • Go to the Zenodo entry for this project (find the link to the latest Zenodo release on the README.md file)
  • Create a "New version" of it.
  • Delete all existing files
  • Copy the reserved DOI to this issue
  • Update release date
  • Update version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Add as authors any new contributors who have added themselves to AUTHORS.md
  • Review author order to make sure it follows the guidelines on our Authorship Guide
  • Save the release draft

Update the changelog

  • Generate a list of commits between the last release tag and now: git log HEAD...v1.2.3 > changes.rst
  • Edit the list to remove any trivial changes (updates by the bot, CI updates, etc).
  • Organize the list into categories (breaking changes, deprecations, bug fixes, new features, maintenance, documentation).
  • Add a list of people who contributed to the release: git shortlog HEAD...v1.2.3 -sne
  • Add the release date and Zenodo DOI badge to the top
  • Replace the PR numbers with links: sed --in-place "s,#\([0-9]\+\),\`#\1 <https://github.com/fatiando/PROJECT/pull/\1>\`__,g" changes.rst
  • Copy the changes to doc/changes.rst
  • Make a Markdown copy of the changelog: pandoc -s changes.rst -o changes.md --wrap=none
  • Add a link to the new release version documentation in README.rst
  • Open a PR to update the changelog
  • Merge the PR

Make a release

After the changelog PR is merged:

  • Draft a new release on GitHub
  • The tag and release name should be a version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Fill the release description with a Markdown version of the latest changelog entry (including the DOI badge)
  • Publish the release

Publish to Zenodo

  • Upload the zip archive from the GitHub release to Zenodo
  • Double check all information (date, authors, version)
  • Publish the new version on Zenodo

Conda-forge package

A PR should be opened automatically on the project feedstock repository.

  • Add/remove/update any dependencies that have changed in meta.yaml
  • If dropping/adding support for Python/numpy versions, make sure the correct version restrictions are applied in meta.yaml
  • Merge the PR

Add geocentric surface radius calculation to TriaxialEllipsoid

Description of the desired feature:

#72 added a TriaxialEllipsoid class defining only the base geometric properties. In #47 @MarkWieczorek mentioned that calculating the surface radius of the ellipsoid would be useful. Seems like a good place to start adding some computations.

https://en.wikipedia.org/wiki/Ellipsoid is a good place to start with equations and references.

Are you willing to help implement and maintain this feature?

Willing to help if anyone wants to give this a shot but probably won't do it myself.

Point to Harmonica's Gravity Disturbances gallery example on Normal Gravity

Description of the desired feature

On the Normal Gravity gallery example, would be nice to point towards the Harmonica's Gravity Disturbances gallery example, just to show how the normal_gravity method could be applied to the computation of the gravity disturbances.

The lack of clearness on how normal_gravity should be used was raised by @craigmillernz on fatiando/harmonica#164.

Are you willing to help implement and maintain this feature? Yes

Drop support for Python 3.6

Now that v0.4.0 is out, we can drop support for Python 3.6. To do so:

  1. Remove it from setup.cfg descriptors
  2. Bump the minimum version in setup.cfg
  3. Bump the minimum version in the test GitHub actions workflow
  4. Update the Install instructions in the documentation

Compatibility with pymap3d

pymap3d implements a bunch of coordinates conversions. They also have an Ellipsoid class that defines similar parameters to ours. There may be only one or two parameters that have slightly different names. I think it would be worth making our ellipsoids compatible with theirs so we can pass them to their coordinate conversion functions.

Will need to have some tests doing so to make sure things keep working.

Calculate the gravity, gravitational, and centrifugal potential

Include methods in Ellipsoid to calculate the gravitational and centrifugal potential. These can be used to calculate a gravity potential (the sum of the two). Having these will allow normal earth corrections for the potential (which can't be measure but can be generated by spherical harmonics).

Deprecation: Coordinate conversion methods moved to pymap3d

Boule implements conversion from geodetic to geocentric spherical coordinates. However, pymap3d already implements many of these conversions and with #121 our Ellipsoid class will be fully compatible with their functions.

I opened geospace-code/pymap3d#54 to ask if they'd want to have our functions and we can use pymap3d in our code instead. They are an extremely light dependency so it would be straight forward to add them as a dependency if we need coordinate conversions internally.

Coordinate conversions proposal

I propose that we introduce a new set of unified coordinate conversion routines for translating between geodetic, spherical, ellipsoidal-harmonic and cartesian coordinates. These would partially replace those that exist, and would introduce a more uniform logic for Boule. All coordinate transformations would require knowledge of the ellipsoid parameters and are hence appropriate for this project.

geodetic, spherical, and ellipsoidal-harmonic conversions

These routines would convert between "latitude" and "height" above the ellipsoid. Latitude would be geodetic, spherical or reduced (for ellipsoidal-harmonic coordinates). Height would be geodetic height (ellipsoidal height) or spherical height (height above the ellipsoid along the radius vector direction). Ellipsoidal-harmonic coordinate don't use a height, but instead use "u", which is the ellipsoid semiminor axis that passes through the point.

None of these routines require longitude, as the longitude is the same for all coordinate systems:

spherical_latitude, spherical_height = geodetic_to_spherical(latitude, height)   
latitude, height = spherical_to_geodetic(spherical_latitude, spherical_height) 
reduced_latitude, u = geodetic_to_ellipsoidal_harmonic(latitude, height)   
latitude, height = ellipsoidal_harmonic_to_geodetic(reduced_latitude, u)
reduced_latitude, u = spherical_to_ellipsoidal_harmonic(spherical_latitude, spherical_height)
spherical_latitude, spherical_height = ellipsoidal_harmonic_to_spherical(reduced_latitude, u)

One could potentially simplify these routines by considering the height as an optional parameter with a default of zero, and the parameter u as an optional parameter with a default of semiminor_axis.

Cartesian conversions

Conversion to and from cartesian coordinates require knowledge of the longitude.

x, y, z = geodetic_to_cartesian(longitude, latitude, height)
x, y, z = spherical_to_cartesian(longitude, spherical_latitude, spherical_height)
x, y, z = ellipsoidal_harmonic_to_cartesian(longitude, reduced_latitude, u)
longitude, latitude, height = cartesian_to_geodetic(x, y, z)
longitude, spherical_latitude, spherical_height = cartesian_to_spherical(x, y, z)
longtidue, reduced_latitude, u = cartesian_to_ellipsoidal_harmonic(x, y, z)

To simplify these functions, one could consider the height and u parameters as optional.

Comments

  • There was a discussion earlier about deprecating some coordinate transforms and moving these to pymap3d (#126). What is being proposed here is somewhat different: In that discussion, the spherical coordinates were latitude and radius, which didn't depend on knowledge of the ellipsoid (see als #165). Here they are latitude and spherical height, which do require knowledge of the ellipsoid
  • At the present time, there is no easy way to convert from geodetic to spherical latitude, which is probably the most commonly used conversion. This was because you needed to input the latitude and radius, and radius needed to be computed by another function. What is proposed here rectifies this problem.
  • Even if some of these functions could be implemented in pymap3d instead of here, pymap3d does not have all of the ellipsoids that we have. This would complicate any such conversion. Furthermore, as far as i can tell, pymap3d doesn't really implement the above routines when height above the ellipsoid is non-zero.
  • This would be a breaking change.

Are you willing to help implement and maintain this feature?
Yes, but I am not sure when I will get around to it. Help (even for just 1 of the above) would be appreciated!

Implement TriAxialEllipsoid class

Boule currently supports biaxial ellipsoids (under the classname Ellipsoid) and spheres (which are a subclass of Ellipsoid). However, one major omission, which is important for all of the planetary moons, is the case of triaxial ellipsoids.

Though it may be difficult to implement all the features of the present ellipsoid class, there are several easy functions that would be of immediate use:

  1. radius of the body as a function of (geocentric) latitude and longitude,
  2. Ellipsoid parameters omega, GM, a, b, and c,
  3. Some easily derived quantities, such as ellipticities, flattenings, etc.,
  4. Orbital parameters of the body, such as the eccentricity, inclination, and semimajor axis,
  5. The volume of the body,
  6. The tidal potential raised by the primary (assuming the moon is in synchronous rotation), and the centrifugal potential (non-zero inclinations and eccentricies would be useful as well, but their computation are non-trivial).

Other quantities that geodecists use on Earth (like normal gravity, geodetic coordinates, etc), may take significant effort to implement, but would be of use for only a handful of experts (who might decide to implement these themselves).

At this point, given that Boule would have three types of ellipsoids, it might be useful to make some kind of factory function called Ellipsoid that would automatically instantiate one of the three classes based on the input parameters:

  • Sphere
  • BiAxialEllipsoid
  • TriAxialEllipsoid

Include a reference Sphere class

As shown in #13, flattening of 0 leads to not-a-number in the computations due to division by the first eccentricity (which is 0). In these cases, it would make more sense to have a boule.Sphere class that mirrors the Ellipsoid but is much simpler:

Sphere(radius=..., geocentric_grav_const=..., angular_velocity=...)

All the eccentricities, gravity at the pole and equator, and coordinate conversions aren't needed. The forward modelling equations are also simpler (should be implemented in Sphere.normal_gravity).

"Mean radius" proposal

Description of the desired feature:

In geodesy, there are several definitions of "radius" or "mean radius", and Boule implements some of these. The standard definitions that one finds for WGS84 are

  • R_1 : mean radius of semi-axes, i.e., (a+b+c)/3.
  • R_2 : radius of a sphere with the same area as the ellipsoid.
  • R_3 : radius of a sphere with the same volume as the ellipsoid.

At the present time, we implement "R_1" and call this mean_radius. There is a PR open to add R_3 which is called volume_equivalent_radius.

The problem is that R_1 is not the mean radius of the ellipsoid. I was surprised to learn this when comparing the degree 0 spherical harmonic coefficient of an ellipsoid with R_1, but perhaps I shoudn't have been surprised...

My proposal is the following:

  1. Rename mean_radius (R_1) to semiaxes_mean_radius (R_1)
  2. Add a new definition of the true mean radius called mean_radius with the symbol R_0.
  3. This would leave us with R_0, R_1, R_2, R_3, with names of mean_radius, semiaxes_mean_radius, area_equivalent_radius and volume_equivalent_radius.

As far as I can tell, there is not an analytic equation for the mean radius of an ellipsoid. Therefore I propose that we compute this numerically using Gauss-Legendre quadrature. This shouldn't take up more than about 5 lines of code, and there are two routines that we could use out of the box. The first is scipy.integrate.fixed_quad and the second is numpy.polynomial.legendre.leggauss.

The scipy method is probably one line of code (for the integration), whereas for the numpy version, you first need to compute the points where the function is evaluated and then do a sum (so two lines of code). We already use numpy, so we wouldn't need to import another module. However, we don't use scipy, so we would need to import this for this for one line of code. Since the radius is very close to being a degree-2 polynomial, using 50 integration points is probably sufficient to get machine precision accuracy (of course I will verify this): numpy claims that their routine is tested to degree 100, so that is probably good enough.

If we do this, we could probably also compute the area of the ellipsoid numerically using a similar approach.

Lastly, I note that these issues are really not important for Earth. However, for Vesta, we have the following:

a = 286.300
b = 278.600
c = 223.200

R_0 = 259.813
R_1 = 262.700
R_3 = 261.115

So there are differences of more than a km. And there are bodies that are even more triaxial than Vesta...

Are you willing to help implement and maintain this feature?
Yes.

Check if normal gravity is computed on internal point

Description of the desired feature

The normal gravity formulas used on boule.Ellipsoid.normal_gravity() and boule.Sphere.normal_gravity() are valid only for points outside the ellipsoid.
Would be nice to add a warning in case the given point falls inside it.
To do so we just need to check if the height is positive or equal to zero.

Are you willing to help implement and maintain this feature? Yes, but would be glad to help anyone who wants to implement it.

Add optional argument geodetic to Ellipsoid.normal_gravity

The Ellipsoid.normal_gravity() method takes as input the geodetic latitude. I propose to add an optional argument geodetic=True/False that would allow the user to specify if the input latitudes are geodetic or geo/planetocentric. The default option would be to use geodetic. Though this could easily be accomplished using the spherical_to_geodetic method, this would make things easier for many applications where the geocentric latitude is the more appropriate value to use.

I note that that option is already implemented in the method Ellipsoid.geocentric_radius()

Release v0.3.0

Info
Version number v0.3.0
Target date 2021/10/18
Zenodo DOI 10.5281/zenodo.5575827

Draft a Zenodo archive (to be done by a manager on Zenodo)

  • Go to the Zenodo entry for this project (find the link to the latest Zenodo release on the README.md file)
  • Create a "New version" of it.
  • Delete all existing files
  • Copy the reserved DOI to this issue
  • Update release date
  • Update version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Add as authors any new contributors who have added themselves to AUTHORS.md
  • Review author order to make sure it follows the guidelines on our Authorship Guide
  • Save the release draft

Update the changelog

  • Generate a list of commits between the last release tag and now: git log HEAD...v1.2.3 > changes.rst
  • Edit the list to remove any trivial changes (updates by the bot, CI updates, etc).
  • Organize the list into categories (breaking changes, deprecations, bug fixes, new features, maintenance, documentation).
  • Add a list of people who contributed to the release: git shortlog HEAD...v1.2.3 -sne
  • Add the release date and Zenodo DOI badge to the top
  • Replace the PR numbers with links: sed --in-place "s,#\([0-9]\+\),\`#\1 <https://github.com/fatiando/PROJECT/pull/\1>\`__,g" changes.rst
  • Copy the changes to doc/changes.rst
  • Make a Markdown copy of the changelog: pandoc -s changes.rst -o changes.md --wrap=none
  • Add a link to the new release version documentation in README.rst
  • Open a PR to update the changelog
  • Merge the PR

Make a release

After the changelog PR is merged:

  • Draft a new release on GitHub
  • The tag and release name should be a version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Fill the release description with a Markdown version of the latest changelog entry (including the DOI badge)
  • Publish the release

Publish to Zenodo

  • Upload the zip archive from the GitHub release to Zenodo
  • Double check all information (date, authors, version)
  • Publish the new version on Zenodo

Conda-forge package

A PR should be opened automatically on the project feedstock repository.

  • Add/remove/update any dependencies that have changed in meta.yaml
  • If dropping/adding support for Python/numpy versions, make sure the correct version restrictions are applied in meta.yaml
  • Merge the PR

Better __repr__ or .info() method

Description of the desired feature:
Printing the contents of a boule ellipsoid gives the following:

In [1]: print(boule.WGS84)
Ellipsoid(name='WGS84', semimajor_axis=6378137, flattening=0.0033528106647474805, geocentric_grav_const=398600441800000.0, angular_velocity=7.292115e-05, long_name='World Geodetic System (1984)', reference='Hofmann-Wellenhof, B., & Moritz, H. (2006). Physical Geodesy (2nd, corr. ed. 2006 edition ed.). Wien\u202f; New York: Springer.')

As this is a really long string, it is somewhat difficult to read if you a looking for a particular element. I propose that we provide an easier way to print the entirety of the ellipsoid contents for human readibility. This could either be by explicitly defining __repr__ for each ellispoid class or by providing a simple method such as Ellipsoid.info(). The output would look something like this:

In [1]: print(boule.WGS84)
Class: Ellipsoid
name = 'WGS84'
long_name = 'World Geodetic System (1984)'
semimajor_axis = 6378137
flattening = 0.0033528106647474805
geocentric_grav_const = 398600441800000.0
angular_velocity = 7.292115e-05
reference = 'Hofmann-Wellenhof, B., & Moritz, H. (2006). Physical Geodesy (2nd, corr. ed. 2006 edition ed.). Wien\u202f; New York: Springer.'

If desired, we could also append the units, but if we did this, we should probably define the units for each attribute in the class.

Are you willing to help implement and maintain this feature?
After we decide on how to do this, the changes would be trivial to make...

Use a unit package

Tracking units through these computations is hard. For now, we settled on using SI for all inputs and most outputs. It would be better to use a unit package like Pint.

Check if Ellipsoid parameters are valid

Description of the desired feature

On #42 @leouieda proposed to add methods to the Ellipsoid class that checks whether the passed ellipsoid parameters are valid. This means that the values must fall under certain intervals to be able to create a valid ellipsoid, for example, the flattening should be a positive number.
Because these parameters are not defined through a regular constructor, like __init__, but rather defined using the attrs library, these methods should be decorated following attrs documentation.

We should check that (and raise errors if false):

  • flattening >= 0 and flattening < 1
  • semimajor_axis > 0

We can also check that geocentric_grav_const >= 0, but for this I'll only raise a warning.

Are you willing to help implement and maintain this feature? Yes, but I can also help anyone that wants to implement it.

New ellipsoids : Proposal

I would like to add a large number of ellipsoids to Boule. These would include: Mercury, Venus, Moon, Mars, Ceres, Vesta, Eros, Io, Europa, Ganymede, Callisto, Enceladus and Titan. Some of these would update the ones already present in Boule. The number of ellipsoids will likely increase over time, and many of the ellipsoids will be updated by future measurements. The current manner that Boule deals with ellipsoid realizations in not adapted to this large increase in number.

There are two issues: How do we store and organize these in Boule, and what do we call them?

Organization

In order to make it easy to find the raw ellipsoid declarations, I propose that we convert the file _realizations.py into several: one for each planet, the Moon, and asteroids

  • _mercury.py
  • _venus.py
  • _earth.py
  • _moon.py (this could maybe incorporated into earth)
  • _mars.py
  • _asteroids.py
  • _jupiter.py (all moons of Jupiter)
  • _saturn.py (all moons of Saturn)

(more to be added as necessary...)

The realizations in these files would then be imported into a module called "ellipsoids" (i.e., boule.ellipsoids). Initially, I think that we can just import them all into one space. However, if we start adding a large number of small moons of the outer planets, or if we start getting a lot of versions for a single body, we might want to consider organizing them into submodules, like ellipsoids.Jupiter.Ganymede.

A question is whether we should put all these files in the top level directory, or put them in a subdirectory.

Naming scheme

It is important to have some kind of "version control" for the ellipsoids that we propose. The parameters might change slightly over the years with improved ephemerides, or we might get new data from spacecraft. It is imortant that we don't change the values in an ellipsoids without telling people!

I propose a simple naming scheme that is just the body name, and the year that we defined the ellipsoid. If two ellipsoids are generated in the same year, we could add "a", "b, "c", For example Mercury2015, Mercury2024, Mercury2024b.

For the case where there are well defined previously published ellispoids, we could break with this convention: WGS84, EGM2008, etc. The only other body where there was an ellipsoid published was Mars: Ardalan et al. 2010. For this case, I would probably just call it Mars2010.

Referencing

The new ellipsoids require several parameters (GM, a, f, omega), and thus we might have separate references for each of these values. I propose to just put them all into a long reference string like

"a, f: some reference 2010; GM: another reference 2009; omega: and yet another reference 2000"

Are you willing to help implement and maintain this feature?

Add meaning of "co-located"

As an absolute beginner working with xarray and non-native English, the word "co-located" in this sentence was unclear:
"Now we can download and open co-located topography and geoid grids."
I had to read Ensaio documentation to understand both data sets have node spacing of 10 arc-minutes, the horizontal datum is WGS84 and there are 1081 x 2161 grid points in total. I conclude this is the meaning of "co-located".
Can we explicitly say what co-located means and guide people working with different geoids/data sets on the requirements of the grids? I mean, direct people to some external tutorial where they learn how to "co-locate" grids.
Thanks!

Add volume property to Sphere

The proposed Triaxial Ellipsoid class has a volume method.
For consistency a similar method should be created for the Sphere and (biaxial) ellipsoid classes too.

Mentioned by @santisoler in #72 .

Are you willing to help implement and maintain this feature? Yes/No

Add reference ellipsoids for the Moon, Venus and Mercury

Description of the desired feature

With the new Sphere class introduced in #42 for representing reference ellipsoids with zero flattening, now we are in position to add ellipsoids for planetary bodies that are usually treated as spheres, such as the Moon, Venus and Mercury.

@leouieda started adding the reference ellipsoid for the Moon on #13 before we had the Sphere class for that purpose, encountering the known problems of singularities due to division by zero (see #18).

The idea is to add new MOON, VENUS and MERCURY instances of the Sphere class with the correct parameters for the each body (they can be taken from Wieczorek (2015)). These three variables should be defined in the boule/realizations.py file.

Are you willing to help implement and maintain this feature?
Yes, I'm willing to help anyone that wants to implement it (yes, I'm talking to you)! 🚀

If you want to add just one of these bodies, it's ok: we can add each one of them on separated PRs.

Add normal_gravitation method to Sphere

Description of the desired feature

After #52 we decided that the Sphere.normal_gravity method should return the norm of the gradient of the gravity potential (gravitational + centrifugal). Nevertheless, as @MarkWieczorek pointed out, we might also want a normal_gravitation method that returns the norm of the gradient of the gravitational potential (without the centrifugal term), a.k.a the norm of the gravitational acceleration.

The norm of the gravitational acceleration of a sphere can easily be computed as:

image

where r is the distance between the observation point and the center of the sphere.

The new method should be able to return the norm of the gravitational acceleration for any given latitude and height (even though the gravitational acceleration of the sphere does not depend on latitude, we might want to keep the same notation for a future Ellipsoid.normal_gravitation):

def normal_gravitation(self, latitude, height):
    ...
    return normal_gravitation

This issue is inspired on #19 , which may require some more work and discussion, so it's better to start with this part which seems easier.

Are you willing to help implement and maintain this feature?
Yes, I'm willing to help anyone that wants to implement it (yes, I'm talking to you)! :rocket

Normal gravity of a sphere and the small flattening limit of an ellipsoid

We previously had a discussion about how to define normal gravity on a sphere. At the time, I think that I was probably a little confused, but now that I see how Boule works and defines things, and after have looked through Chapter 2 of Physical Geodesy again, I think that the way we treat the Sphere class is not entirely consistent with the Ellipsoid class.

Start with the properties of a reference ellipsoid, as found in the boule documentation:

  • The gravity potential (gravitation + centrifugal) is constant on the surface.
  • The internal density structure is unspecified but must lead to a constant potential at the surface.

However, for a sphere, the assumptions are different:

  • The internal density structure is unspecified but must be either homogeneous or vary radially (e.g., in concentric layers).
  • A constant gravity potential on the surface of a rotating sphere is not possible (when the internal density structure varies only as a function of radius).

Because of this, if you take an Ellipsoid, and gradually decrease the flattening to zero, you will not asymptotically approach the results of a sphere. This is because the gravity potential is not constant on the surface of the sphere, but it is on an ellipsoid.

Now, I agree that the assumptions for the Sphere class are correct if we assume that the body is a fluid in hydrostatic equilibrium. However, we can add arbitrary density anomalies in the mantle in order to generate a gravity potential (gravitation+centrifugal) at the surface that is constant, just like in the case for Ellipsoid. The mathematical problem is that if you put flattening=0 in the Ellipsoid equations, you will get divide by zero errors, but as I will show below, these can be avoided by taking the limit where the semiminor axis approaches the semimajor axis.

What I propose is the following: use the same assumptions for Sphere as for Ellipsoid, and then with the equations in Ellipsoid, find the asymptotic limits as the flattening goes to zero. I note that the following equations could probably have been more easily derived starting with spherical harmonics instead of ellipsoidal harmonics, but I will follow the geodesy tradition of doing things the hard way!

reference normal gravity potential

Start with eq. 2-123,

$$ U_0 = \frac{GM}{E} \arctan{\frac{E}{b}}+ \frac{1}{3} \omega^2 a^2 $$

and use the small-angle approximation (only the first two terms are necessary here)

$$ \arctan{x}\simeq x -\frac{x^3}{3} + \frac{x^5}{5} + O(7) $$

When $b$ approaches $a$ and $E$ goes towards zero, we have

$$ U_0 \simeq GM \left(\frac{1}{b} - \frac{E^2}{3 b^3}\right) + \frac{1}{3} \omega^2 a^2 $$

For the case of a sphere with $b=a$, the reference potential is

$$ U_0 = \frac{GM}{a} + \frac{1}{3} \omega^2 a^2 $$

normal gravitation potential

Eq. 2-124 for the normal gravitation potential (where $\beta$ is the reduced latitude)

$$ V(u, \beta) = \frac{GM}{E} \arctan{\frac{E}{u}} + \frac{1}{3} \omega^2 a^2 \frac{q}{q_0} \left[\frac{3}{2} \sin^2 \beta - \frac{1}{2} \right] $$

has the offending term

$$ \frac{q}{q_0} = \frac{ \frac{1}{2}\left[\left(1+3\frac{u^2}{E^2} \right) \arctan{\frac{E}{u}} - 3 \frac{u}{E}\right]}{\frac{1}{2}\left[\left(1+3\frac{b^2}{E^2} \right) \arctan{\frac{E}{b}} - 3 \frac{b}{E}\right]} $$

Using the higher-order small angle approximation of the arctan function above (all three terms are necessary), we find that

$$ q \simeq \frac{2}{15} \frac{E^3}{u^3} $$

and

$$ \frac{q}{q_0} \simeq \frac{b^3}{u^3} $$

As $b$ approaches $a$ the normal gravity potential approaches

$$ V(u, \beta) \simeq GM \left(\frac{1}{u} - \frac{E^2}{3 u^3}\right)+ \frac{1}{3} \omega^2 a^2 \frac{b^3}{u^3} \left[\frac{3}{2} \sin^2 \beta - \frac{1}{2} \right] $$

For the case of a sphere, with $a=b$, $u=r$ and $\beta =\phi$ we have

$$ \frac{q}{q_0} \simeq \frac{a^3}{r^3} $$

the normal gravity potential 2-124 is

$$ V(r, \phi) = \frac{GM}{r} + \frac{1}{3} \omega^2 a^2 \frac{a^3}{r^3} \left[\frac{3}{2} \sin^2 \phi - \frac{1}{2} \right] $$

where $\phi$ is the spherical geocentric latitude and $r$ is geocentric spherical radius.

normal gravity potential

The normal gravity potential

$$ U(u, \beta) = \frac{GM}{E} \arctan{\frac{E}{u}} + \frac{1}{2} \omega^2 a^2 \frac{q}{q_0} \left[\sin^2 \beta - \frac{1}{3} \right] + \frac{1}{2} \omega^2 \left(u^2 + E^2\right) \cos^2 \beta $$

also has the offending $q/q_0$ term. Substituting the above approximation into 2-126, as $b$ approaches $a$, the normal gravity potential goes to

$$ U(u, \beta) \simeq GM \left(\frac{1}{u} - \frac{E^2}{3 u^3}\right) + \frac{1}{2} \omega^2 a^2 \frac{b^3}{u^3} \left[\sin^2 \beta - \frac{1}{3} \right] + \frac{1}{2} \omega^2 \left(u^2 + E^2\right) \cos^2 \beta $$

For the case of a sphere with $a=b$, $u=r$, and $\beta=\phi$, the normal gravity potential is

$$ U(r, \phi) = \frac{GM}{r} + \frac{1}{2} \omega^2 a^2 \frac{a^3}{r^3} \left[\sin^2 \phi - \frac{1}{3} \right] + \frac{1}{2} \omega^2 r^2 \cos^2 \phi $$

normal gravity

The normal gravity on the ellipsoid is given by 2-146, which is Somilgiana's formula. For this we need the normal gravity at the pole and equator. Each of these terms has the offending ratio

$$ \frac{E q^{\prime}_0}{b q_0} $$

where

$$q^{\prime}_0 = 3 \left(1 + \frac{b^2}{E^2}\right) \left(1 - \frac{b}{E} \arctan \frac{E}{b} \right) -1 $$

Using the small-angle approximation (all three terms are necessary), we find that

$$ q^{\prime}_0 \simeq \frac{2}{5} \frac{E^2}{b^2} $$

and that

$$ \frac{E q^{\prime}_0}{b q_0} \simeq 3 $$

The gravity at the equator, eq 2-141, is

$$ \gamma_a \simeq \frac{GM}{a b} \left( 1 - \frac{3}{2} m \right) $$

and the gravity at the pole, eq 2-142, is

$$ \gamma_b \simeq \frac{GM}{a^2} \left( 1 + m \right) $$

For the case of a sphere with $a=b$, the above two equations reduce to

$$ \gamma_a = \frac{GM}{a^2} \left( 1 - \frac{3}{2} m \right) $$

and

$$ \gamma_b = \frac{GM}{a^2} \left( 1 + m \right) $$

which yields for the normal gravity

$$\gamma = \gamma_a \cos^2 \phi + \gamma_b \sin^2 \phi$$

When computing the normal gravity above the ellipsoid, we use the equations in the appendix of Li and Götze (2001). These equations have two offending terms when the flattening goes to zero. One is nearly the same as computed above:

$$ \frac{E q^{\prime}}{q_0} = 3 \frac{b^3}{\left(b^{\prime}\right)^2} $$

The second involves the term concerning $\cos \beta'$, which can be rewritten as

$$ \cos \beta' = \left[\frac{1}{2} + \frac{R}{2} - \frac{R}{2}\left(1 + \frac{1}{R^2} - 2 \frac{D}{R^2} \right) \right]^{1/2} $$

where $R=r^{\prime \prime 2} / E^2$ and $D=d^{\prime \prime 2} / E^2$. Using the approximation

$$(1+x)^{1/2} = 1 + \frac{x}{2} - \frac{x^2}{8} $$

for the inner square root in the above expression, in the limit where $E$ approaches zero, we find

$$ \cos \beta' = \left[ \frac{1}{2} + \frac{1}{2} \frac{d^{\prime\prime 2}}{ r^{\prime\prime 2}} + \frac{E^2}{4} \left( \frac{d^{\prime\prime 4}}{r^{\prime\prime 6}} - \frac{1}{r^{\prime\prime 2}} \right) \right]^{1/2} $$

Implement the normal gravity potential of the Ellipsoid

Description of the desired feature:

If we want to calculate the disturbing potential for geophysical studies, we need a way to calculate the normal gravity and gravitational potentials. Tools like ICGEM can provide grids of the gravitational potential.

Equation 2–124 in Hofmann-Wellenhof & Moritz (2006) is the normal gravitational potential in ellipsoidal harmonic coordinates. The centrifugal term is not hard and can be found earlier in the same book. The challenge is converting the geodetic to ellipsoidal harmonic coordinates. The conversion can be found in Lakshmanan (1991). The final equation can be obtained by substitution.

The idea is to add 3 new methods to Ellipsoid:

  1. centrifugal_potential(self, latitude, height): Calculate the centrifugal potential.
  2. normal_gravitational_potential(self, latitude, height): Calculate the gravitational potential using the equations described above.
  3. normal_gravity_potential(self, latitude, height): Returns the sum of the previous 2.

Are you willing to help implement and maintain this feature?

Yes but it will take some time. Having some help would be much appreciated!

Unify the Ellipsoids into a single class

Description of the desired feature

#47 talks about implementing a factory function to instantiate ellipsoids. Recently, #73 got me thinking that we do some strange things to make sure that the Sphere and Ellipsoid classes are compatible, like asking for arguments to methods that are not used.

So how about we merge everything into a single Ellipsoid class? It would take 3 axis arguments (semimajor, semimedium, semiminor) with only the semimajor being mandatory. It can then dispatch the computations appropriately depending on the number of axis given (1 goes to sphere calculations, 2 goes to ellipsoid, 3 to triaxial). The calculations themselves can be moved to functions or private methods of this class. The public facing methods would all be the same method in reality so we wouldn't have to artificially make them compatible (or forget to do so).

This would make the process of creating a new ellipsoid simpler: just use Ellipsoid and give it the appropriate amount of axis. It would also remove a lot of duplicate code and documentation.

Are you willing to help implement and maintain this feature? Yes

Comments regarding the InSight lander coordinates example

In the "Coordinate conversion" section of the documentation, there is an example of some simple coordinate transformations that make use of the InSight lander coordinates. However, the documentation assumes that the coordinates are geodetic with respect to an ellipsoid, when they are in fact planetocentric with respect to the geoid. The cited LPSC abstract states the following:

On Nov. 26, 2018 at 11:52:59 a.m. PST, the InSight lander touched down on Mars at 4.502384°N, 135.623447°E (planetocentric, IAU 2000) with an elevation of -2613.426 m with respect to the Mars Orbiter Laser Altimeter (MOLA) geoid.

This is a bit messy, because the geoid is somewhat arbitrary, and the "MOLA geoid" is just some file on the PDS...

I suggest that we instead demonstrate the coordinate conversions using the Cartesian (x, y, z) coordinates of the RISE experiment that is on the lander from

Le Maistre, S., Rivoldini, A., Caldiero, A., Yseboodt, M., Baland, R.-M., Beuthe, M., Van Hoolst, T., Dehant, V., Folkner, W. M., Buccino, D., Kahan, D., Marty, J.-C., Antonangeli, D., Badro, J., Drilleau, M., Konopliv, A., Péters, M.-J., Plesa, A.-C., Samuel, H., … Banerdt, W. B. (2023). Spin state and deep interior structure of Mars from InSight radio tracking. Nature, 1–5. https://doi.org/10.1038/s41586-023-06150-0

If you look in the Supplement Table S1, you will see that there are coordinates for each of the two antennas, as well as using two different methods. I propose (arbitrarily) to just take the GINS solution for the entire mission for the "west" antenna. The coordinates are:

[-2417504.5, 2365954.5, 266266.7]

From these, we could demonstrate how to compute both the planetocentric and geodetic coordinates.

Remove inhertiance between Ellipsoid, Sphere, TriaxialEllipsoid

All three classes need to implement fundamentally different things. While the parameters could be retained somewhat (spheres can have 0 flattening but what about triaxial ellipsoids?), the gravity inputs are different and they can calculate fundamentally different things. Coordinate conversions also don't make much sense when transitioning.

So while geometrically both Ellipsoid and Sphere are special cases of TriaxialEllipsoid, in practice they have very little in common. So it's better to leave the classes as stand-alone and only implement the parameters/methods that make sense for that class.

My proposal for Sphere is:

  1. Only define the flattenings, semi-axis, and eccentricities for pymap3d compatibility.
  2. No coordinate conversion methods.
  3. No surface radius or mean radius (it's just the radius).
  4. No gravity at pole and equator (only used for Somigliana which is not valid for the sphere).
  5. Include normal gravity and normal gravitation

The triaxial ellipsoid is already not inheriting so there is nothing to be done there right now.

Add Ellipsoid.normal_gravitation() method

The Sphere class has the option of computing either the normal gravity or normal gravitation. In contrast, the Ellipsoid class only gives the option to compute the normal gravity. I propose that we allow the computation of the normal gravitation of an ellipsoid by creating the method Ellipsoid.normal_gravitation. This would help make the two classes consistent. Furthermore, there are cases (such as when you are not attached to the Earth) when the normal gravitation would be more appropriate.

Tutorial about coordinate conversions

We need a tutorial page explaining the differences between geodetic and geocentric coordinates and how to convert between them using Boule. Tutorials are rendered by sphinx-gallery from python scripts in tutorials/. See the existing ones for the format.

Option to return gravity in SI units

Description of the desired feature

In #42, a point was raised that it would be convenient to have an option the gravity calculation methods return values in SI units. This would be a temporary fix until we have proper unit support (#23) but it would be useful to have. We can always remove/deprecate it once units are added.

It would mean adding the argument si_units=False to the normal_gravity method of Ellipsoid and Sphere.

Are you willing to help implement and maintain this feature? Yes but welcome anyone who would like to do it

Release v0.4.1

Zenodo DOI: 10.5281/zenodo.7258175

Target date: 2022/10/27

Draft a Zenodo archive (to be done by a manager on Zenodo)

  • Go to the Zenodo entry for this project (find the link to the latest Zenodo release on the README.md file)
  • Create a "New version" of it.
  • Delete all existing files
  • Copy the reserved DOI to this issue
  • Update release date
  • Update version number (make sure there is a leading v, like v1.5.7)
  • Add as authors any new contributors who have added themselves to AUTHORS.md in the same order
  • Ensure that the first author is "Fatiando a Terra Project" and others are listed alphabetically by last name
  • Save the release draft

Update the changelog

  • Generate a list of commits between the last release tag and now: git log HEAD...v1.2.3 > changes.rst
  • Edit the list to remove any trivial changes (updates by the bot, CI updates, etc).
  • Organize the list into categories (breaking changes, deprecations, bug fixes, new features, maintenance, documentation).
  • Add a list of people who contributed to the release: git shortlog HEAD...v1.2.3 -sne
  • Add the release date and Zenodo DOI badge to the top
  • Replace the PR numbers with links: sed --in-place "s,#\([0-9]\+\),\`#\1 <https://github.com/fatiando/PROJECT/pull/\1>\`__,g" changes.rst
  • Check that you changed the PROJECT placeholder when running the last command.
  • Copy the changes to doc/changes.rst
  • Make a Markdown copy of the changelog: pandoc -s changes.rst -o changes.md --wrap=none
  • Add a link to the new release version documentation in README.rst and doc/versions.rst (if the file exists).
  • Build and serve the docs locally with make -C doc all serve to check if the changelog looks well
  • Open a PR to update the changelog
  • Merge the PR

Make a release

After the changelog PR is merged:

  • Draft a new release on GitHub
  • The tag and release name should be a version number (following Semantic Versioning) with a leading v (v1.5.7)
  • Fill the release description with a Markdown version of the latest changelog entry (including the DOI badge)
  • Publish the release

Publish to Zenodo

  • Upload the zip archive from the GitHub release to Zenodo
  • Double check all information (date, authors, version)
  • Publish the new version on Zenodo

Conda-forge package

A PR should be opened automatically on the project feedstock repository.

  • Add/remove/update any dependencies that have changed in meta.yaml
  • If dropping/adding support for Python/numpy versions, make sure the correct version restrictions are applied in meta.yaml
  • Merge the PR

Provide function that returns the radius as a function of latitude

It would be very useful to be able to compute the radius of the reference ellipsoid as a function of latitude (geocentric or geodetic).

The use case I am thinking of is the following. Most spherical harmonic models of planetary topography provide the absolute radius of the surface. In many cases, it makes more sense to remove either a reference ellipse (which could be a sphere), or to remove the geoid. In pyshtools, I would like to create a grid of the radius of the reference ellipsoid like grid = pysh.SHGrid.from_ellipsoid(), and for this it would be most easy to input a boule ellipsoid and to use a boule function to compute the radius as function of latitude.

"notes" (or "additional_information") attribute for ellipsoid classes

Description of the desired feature:
For some ellipsoids, providing a reference might not be enough information to understand the origin of the data in the ellipsoid classes and how to use them. For example:

  • Some manuscripts present several ellipsoids: some are constrained to have a geocentric origin whereas others are not. Some coincide with the rotational axis and others not.
  • Some manuscripts present ellipsoid shapes, and/or best fitting ellipsoids with respect to the geoid.
  • In some cases additional information might be required. For example, many Vesta ellipsoids are not aligned with the coordinate axes.

I propose that we simply add an optional attribute to the 3 ellipsoid classes called "notes" (or perhaps "additional_information") that allows one to add an arbitrary text string with additional information.

edit: Maybe comments would be better.

Are you willing to help implement and maintain this feature?

Fix normal gravity of Sphere

Is the centrifugal acceleration for the sphere we have implemented correct? Shouldn't it be projected to the normal of the sphere? This is where it gets a bit confusing. The "gravity" we want is the gradient of the combined potential. But how does that translate to the combined acceleration vector? Do we need to do a vector sum and then take the norm? I would imagine so but that doesn't seem to be what we do. Or am I missing something?

Add separate gravitational and centrifugal acceleration

The Ellipsoid.normal_gravity methods calculates the combined gravitational and centrifugal acceleration. It would be nice to have these two components in separate methods (then normal_gravity can add them). When synthesizing data from spherical harmonics, there is no point in including the centrifugal component only to remove it afterwards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.