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 BaseBodycentricRepresentation
#14851
Conversation
Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.
|
d3f53fd
to
a6e30fb
Compare
It seems like I'm still confused about units conversions... :( |
f1a8a58
to
25fb355
Compare
For the sake of completeness, this pull request makes the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cmarmo - Good to have these options, but I do think at least some of them should be subclasses rather than options on the base class. For _ellipsoid
', I ended up agreeing it was not necessary, since having it on the baseclass gives a little overhead only at class creation time, and in the end it is really the same thing as far as the actual calculations are concerned. But here the calculations for conversion to/from cartesian are effectively separated, making the code more complicated and giving overhead for every calculation. Generally, I think each different interpretation of the coordinates should have its own (base) class -- just like PhysicsSpherical
is a different class from Spherical
. I would say the rule should be that the moment from_cartesian
and to_cartesian
depend on any class attribute, it would be better to have a different class.
So, I think we definitely should have a separate base class for the planetocentric latitudes (BasePlanetoCentric
?). I think we also will be better off with a separate class for West longitudes, though given the rarity of its use, perhaps this is best implemented via a mixin class that overrides from_cartesian
and to_cartesian
changing the sign of the longitude appropriately.
Only for _wrap_angle
, I think it is fine to leave that on the base class -- the calculations do not depend on it, one can see it as similar to changing the class of the attributes.
@@ -45,9 +56,16 @@ class BaseGeodeticRepresentation(BaseRepresentation): | |||
to quantities holding correct values (with units of length and dimensionless, | |||
respectively), or alternatively an ``_ellipsoid`` attribute to the relevant ERFA | |||
index (as passed in to `erfa.eform`). | |||
Longitudes are east positive and span from -180 to 180 degrees by default. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have separate classes; see main comment.
25fb355
to
50c29f4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making the change to a different base class. That does feel much better!
But, seeing this again, I wonder about the approach for wrap_angle
. Really, the problem is that we have a Longitude
class that has a default of 360 degrees, while we would like 180 degrees. Would it make sense to just define
class Longitude180(Longitude):
_default_wrap_angle = Angle(180 * u.deg)
and then use that? Then anyone who wants to have a different default, can just choose to use a different Longitude
class. And we don't have to deal with the new _wrap_angle
attribute.
p.s. Need to think a bit about the mixin still... And I haven't looked in detail over the tests.
@@ -62,12 +98,21 @@ def __init_subclass__(cls, **kwargs): | |||
raise AttributeError( | |||
f"{cls.__name__} requires '_ellipsoid' or '_equatorial_radius' and '_flattening'." | |||
) | |||
if not hasattr( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small detail, but could do
if not u.Quantity(cls._wrap_angle).unit.is_equivalent(u.deg):
(but see my larger comment about _wrap_angle
)
Thanks for your review @mhvk ! |
BaseGeodeticRepresentation
BaseBodycentricRepresentation
The tests are failing because the class On the long term, I see the importance of changing Any suggestion? Thanks a lot! |
Simplest right now would seem to not allow |
d17d2dc
to
265e9bb
Compare
Hi @mhvk . I believe I have removed all the unnecessary conversions to degrees, following your comments.
I guess this is also because I don't understand this previous comment |
@cmarmo - thanks for the changes. I'm still not sold on the However, I also think this discussion is actually distracting from the main point of this PR, which is to introduce a Indeed, while I think the |
I guess I'm loosing focus indeed... I need the Bodycentric representation for the frame definition, while west/east and 180/360 are not needed.... and I'm running out of time... ⏲️ |
OK, thanks, ping me when I should look again. And apologies for not realizing this earlier! |
No problem! I'm treasuring all the comments for the follow-up! :) |
317bc2b
to
918a6b3
Compare
@mhvk thanks for your patience! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! There are only nitpicks and suggestions for the docstrings left. But also: do indeed add to the whatsnew entry you already created for other geodetic representations.
lon, lat, height = erfa.gc2gde( | ||
cls._equatorial_radius, cls._flattening, cart.get_xyz(xyz_axis=-1) | ||
) | ||
return cls(lon, lat, height, copy=False) | ||
return cls( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, but could you get this back to the default format? Be sure to delete the final ,
after copy=False
, otherwise black
will break it over several lines again.
@@ -45,6 +46,7 @@ class BaseGeodeticRepresentation(BaseRepresentation): | |||
to quantities holding correct values (with units of length and dimensionless, | |||
respectively), or alternatively an ``_ellipsoid`` attribute to the relevant ERFA | |||
index (as passed in to `erfa.eform`). | |||
Longitudes are east positive and span from 0 to 360 degrees by default. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: might as well leave this out for now.
Instead, I think here is the place to mention how lon, lat, and height are defined relative to the ellipsoid.
Alternatively, you could clarify the definition in geodetic_base_doc
above (and then not use it for bodycentric
)
Subclasses need to set attributes ``_equatorial_radius`` and ``_flattening`` | ||
to quantities holding correct values (with units of length and dimensionless, | ||
respectively). | ||
Longitudes are east positive and span from 0 to 360 degrees by default. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'd remove this for now and instead describe how the parameters are used (and how it is different from geodetic).
Alternatively, do not use geodetic_base_doc
, but instead write a complete docstring here that also describes how lat
is defined.
lon, | ||
lat, | ||
height, | ||
copy=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, could you bring this on a single line?
@@ -0,0 +1,2 @@ | |||
Add ``BaseBodycentricRepresentation``, a new spheroidal representation for bodycentric | |||
latitudes and longitudes spanning from 0 to 360 degrees. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove the "spanning from 0 to 360 degrees" here too.
docs/coordinates/representations.rst
Outdated
`~astropy.coordinates.BaseBodycentricRepresentation` is the coordinate representation | ||
recommended by the Cartographic Coordinates & Rotational Elements Working Group | ||
(see for example its `2019 report <https://rdcu.be/b32WL>`_): the bodicentric latitude | ||
and longitude are spherical latitude and longitude originated at the barycenter of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originated at -> relative to
docs/coordinates/representations.rst
Outdated
@@ -48,6 +50,13 @@ between the vertical to the surface at a specific point of the spheroid and its | |||
projection onto the equatorial plane. | |||
The latitude is a value ranging from -90 to 90 degrees, the longitude from 0 to 360 | |||
degrees. | |||
`~astropy.coordinates.BaseBodycentricRepresentation` is the coordinate representation | |||
recommended by the Cartographic Coordinates & Rotational Elements Working Group | |||
(see for example its `2019 report <https://rdcu.be/b32WL>`_): the bodicentric latitude |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bodicentric -> bodycentric
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm letting @mhvk do the main review, but I do have a few comments.
x_spheroid = self._equatorial_radius * coslat * coslon | ||
y_spheroid = self._equatorial_radius * coslat * sinlon | ||
z_spheroid = self._equatorial_radius * (1 - self._flattening) * sinlat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These variables are unused.
x_spheroid = self._equatorial_radius * coslat * coslon | |
y_spheroid = self._equatorial_radius * coslat * sinlon | |
z_spheroid = self._equatorial_radius * (1 - self._flattening) * sinlat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! They are no longer needed as the calculation is done for r
already.
z_spheroid = self._equatorial_radius * (1 - self._flattening) * sinlat | ||
r = ( | ||
self._equatorial_radius | ||
* np.sqrt(coslat**2 + ((1 - self._flattening) * sinlat) ** 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use np.hypot()
here:
* np.sqrt(coslat**2 + ((1 - self._flattening) * sinlat) ** 2) | |
* np.hypot(coslat, (1 - self._flattening) * sinlat) |
[ | ||
WGS84GeodeticRepresentation, | ||
IAUMARS2000BodycentricRepresentation, | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this fit on one line?
[ | |
WGS84GeodeticRepresentation, | |
IAUMARS2000BodycentricRepresentation, | |
], | |
[WGS84GeodeticRepresentation, IAUMARS2000BodycentricRepresentation], |
If it does then the other similar cases should be updated analogously.
docs/coordinates/representations.rst
Outdated
degrees, the height is the elevation above the surface of the spheroid (measured on the | ||
perpendicular to the surface). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be replaced with the following?
degrees, the height is the elevation above the surface of the spheroid (measured on the | |
perpendicular to the surface). | |
degrees, the height is the elevation above the surface of the spheroid (measured | |
perpendicular to the surface). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cmarmo - only some nitpicks left beyond @eerovaher's comments. With those, I'll be happy to merge!
|
||
Subclasses need to set attributes ``_equatorial_radius`` and ``_flattening`` | ||
to quantities holding correct values (with units of length and dimensionless, | ||
respectively). the bodicentric latitude and longitude are spherical latitude |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the bodicentric" -> "The bodycentric"
x_spheroid = self._equatorial_radius * coslat * coslon | ||
y_spheroid = self._equatorial_radius * coslat * sinlon | ||
z_spheroid = self._equatorial_radius * (1 - self._flattening) * sinlat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! They are no longer needed as the calculation is done for r
already.
d = np.hypot(p, cart.z) | ||
lat = np.arctan2(cart.z, p) | ||
p_spheroid = cls._equatorial_radius * np.cos(lat) | ||
z_spheroid = (cls._equatorial_radius * (1 - cls._flattening)) * np.sin(lat) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Total nitpick, but outer parentheses are not necessary.
docs/coordinates/representations.rst
Outdated
create specific representations on spheroidal bodies. | ||
This is used internally for the standard Earth ellipsoids used in | ||
`~astropy.coordinates.BaseGeodeticRepresentation` is used internally for the standard | ||
Earth ellipsoids used in | ||
`~astropy.coordinates.EarthLocation` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe combine with last line while you are making the last changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I'm not sure to understand this comment....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meant to combine the two lines to give```
Earth ellipsoids used in ~astropy.coordinates.EarthLocation
docs/coordinates/representations.rst
Outdated
recommended by the Cartographic Coordinates & Rotational Elements Working Group | ||
(see for example its `2019 report <https://rdcu.be/b32WL>`_): the bodycentric latitude | ||
and longitude are spherical latitude and longitude relative to the barycenter of the | ||
body, the height is the distance from the spheroid surface on the line of sight. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the height is the distance from the spheroid surface on the line of sight" -> "height is the distance from the surface (measured radially)."
docs/coordinates/representations.rst
Outdated
@@ -706,11 +717,13 @@ In pseudo-code, this means that a class will look like:: | |||
|
|||
.. _astropy-coordinates-create-geodetic: | |||
|
|||
Creating Your Own Geodetic Representation | |||
----------------------------------------- | |||
Creating Your Own Geodetic and Bodycentric Representation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe make plural: "Representations"
@cmarmo - separately from this PR, my sense would be to try to follow this up with adding some of the I/O and WCS system things you have been mentioning rather than worry about west longitude and wrap angles! |
create specific representations on spheroidal bodies. | ||
This is used internally for the standard Earth ellipsoids used in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't mean to have this part about the internal use to be removed!
@@ -110,7 +110,7 @@ class BaseBodycentricRepresentation(BaseRepresentation): | |||
|
|||
Subclasses need to set attributes ``_equatorial_radius`` and ``_flattening`` | |||
to quantities holding correct values (with units of length and dimensionless, | |||
respectively). the bodicentric latitude and longitude are spherical latitude | |||
respectively). the bodycentric latitude and longitude are spherical latitude |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to capitalize "The"
The latitude is a value ranging from -90 to 90 degrees, the longitude from 0 to 360 | ||
degrees. | ||
|
||
`~astropy.coordinates.BaseGeodeticRepresentation` is used internally for the standard |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, sorry, you moved it here! This is better!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks great now. I think I'll just merge, the one uncapitalized "t" can be done at some other time!
Thanks, @cmarmo!! |
Thanks @mhvk for your patience! |
Description
This pull request adds the possibility to create geodetic representations described by [planetocentric latitudes]
(https://en.wikipedia.org/wiki/Latitude#Geodetic_and_geocentric_latitudes), west positive longitudes, longitudes spanning from 0 to 360 degrees.The default behavior is backward compatible.
Suggested in #11170 (comment).
Towards #11170.
This work is funded by the Europlanet 2024 Research Infrastructure (RI) Grant.