Skip to content

Implement transformation to / from CoordinateFrame from / to related WCS - #14820

Merged
mhvk merged 12 commits into
astropy:mainfrom
oudeis-io:bodyfixed-frame
Sep 24, 2023
Merged

mhvk merged 12 commits into
astropy:mainfrom
oudeis-io:bodyfixed-frame

Conversation

@cmarmo

@cmarmo cmarmo commented May 12, 2023 •

Copy link
Copy Markdown
Member

Description

This pull request Implement transformation to / from CoordinateFrame from / to related WCS.
This new frames are meant to be used for body-fixed reference frames for spheroidal Solar System bodies.
The implementation of the already available related WCS is also added.

Towards #11170.

Thanks for considering it.

This work is funded by the Europlanet 2024 Research Infrastructure (RI) Grant.

@cmarmo
cmarmo requested a review from mcara as a code owner May 12, 2023 21:35
@cmarmo
cmarmo marked this pull request as draft May 12, 2023 21:36
@github-actions

github-actions Bot commented May 12, 2023 •

Copy link
Copy Markdown
Contributor

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.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see "When to rebase and squash commits".
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • Is a milestone set? Milestone must be set but we cannot check for it on Actions; do not let the green checkmark fool you.
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@pllim pllim added this to the v6.0 milestone May 12, 2023
@cmarmo
cmarmo force-pushed the bodyfixed-frame branch from 4eb9f45 to 517efb2 Compare May 15, 2023 21:12
@nstarman

Copy link
Copy Markdown
Member

Hi @cmarmo, the actual PR looks pretty good, but I'm not sure I understand what it's meant to do... Is this a base class for use in custom frames outside of Astropy, or are you intending to refactor some existing frames in Astropy? If the former, I think this needs some examples demonstrating its usage; if the latter, this PR would be a good place to do the refactor 😄.

@nstarman
nstarman requested a review from mhvk May 16, 2023 20:04
@cmarmo

cmarmo commented May 16, 2023 •

Copy link
Copy Markdown
Member Author

I'm not sure I understand what it's meant to do

It is meant to connect planetary WCS with a dedicated frame in astropy.
Still draft because I want to build the GeodeticRepresentation using the FITS keywords defined in the paper and I'm trying to figure out how to do it, as they are not in the WCS structure.
I was also preparing an example.

or are you intending to refactor some existing frames in Astropy

what kind of refactoring do you have in mind?

@nstarman

Copy link
Copy Markdown
Member

what kind of refactoring do you have in mind?

I just saw this was a base class. If it was a base class for any existing frames, then that would be some small refactoring. If it's for new stuff, then carry on :)

@mhvk

mhvk commented May 16, 2023

Copy link
Copy Markdown
Contributor

@nstarman - see #11170 for the larger picture. Thoughts on how to go about it very welcome -- we did the easy bits, which was to set up the option to create geodetic representations for other planets.

@cmarmo

cmarmo commented May 16, 2023 •

Copy link
Copy Markdown
Member Author

@nstarman I find the documentation about creating a custom frame quite detailed and usable with the base class introduced by this PR. I've added an example instead.
No transformations are defined for now, so the example is indeed minimal.

@cmarmo
cmarmo force-pushed the bodyfixed-frame branch from d449428 to 584e073 Compare May 22, 2023 19:11
@cmarmo
cmarmo force-pushed the bodyfixed-frame branch from 584e073 to 8bfca9e Compare June 23, 2023 21:09
@cmarmo
cmarmo marked this pull request as ready for review June 24, 2023 02:20

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cmarmo - good to see the next step! I think we need to be a bit careful here not to mix up the representation (which you did already) with the frame. If I have coordinates on Mars, then the representation can be cartesian, spherical, geodetic or bodycentric, but the frame does not care about that. The only thing it needs to know is that it is of Mars, so that, if needed, it can be transformed to something relative to the solar system barycentre, etc. Basically, the frame should be like ITRS is for Earth, i.e., something suitable to add to the frame transformation graph. Of course, there should be different frames for the different planets, since they have different transformations to barycentric. (In princple, there might also be different frames for, say, different precession or orbital models, but that is definitely for another time!)

This has consequences both for the example plot in the new documentation (so good to add that, it helps focus discussion!) and for WCS.

For the example, there should be only one MarsCoordinateFrame. I don't know what the standard is exactly, but given that there are different spheroids, safest would seem to make the default Cartesian (as it is for Earth, via ITRS). And then one can initialize this with different geodetic and bodycentric representations, i.e.,the following would all work,

mars = MarsCoordinateFrame(x=1000*u.km, y=2000*u.km, z=3000*u.km)
mars2 = MarsCoordinateFrame(lon=10*u.deg, lat=20*u.deg, representation_type=MarsBestFitAeroid)

Indeed, note that even now, with the changes you have already made and with your definition of MarsBestFitAeroid in your example, one can do

mars = ITRS(x=1000*u.km, y=2000*u.km, z=3000*u.km)
mars.represent_as(MarsBestFitAeroid)  # or .represent_as("marsbestfitaeroid")
# <MarsBestFitAeroid (lon, lat, height) in (rad, rad, m)
#     (1.10714872, 0.93481117, 357668.0311648)>
mars2 = ITRS(lon=10*u.deg, lat=10*u.deg, representation_type=MarsBestFitAeroid)
mars2.cartesian
# <CartesianRepresentation (x, y, z) in m
#     (3293561.1722263, 580743.6972773, 583553.24056641)>

For WCS, this means that one should not instantiate a BodyBaseCoordinateFrame, but rather for each known object make a subclass, probably best on first use (i.e., cache the result), though perhaps it is fine to just define the 8 that we need in a dict (maybe replacing the one you already have).

One thing: if the default becomes Cartesian, there seems to be little point in having BodyBaseCoordinateFrame for now - it doesn't really do anything! One might as well add obstime attribute where needed.

Anyway, after this long comment, how about the following:

  1. Make the documentation plot a separate PR that just subclasses BaseCoordinateFrame (and maybe includes the ITRS test; alternatively, rewrite that test to make a Mars frame as you do in the plot example - since those do not get tested, would be nice to have it!
  2. Here, focus on WCS. I think creating custom classes may be the best way forward for now, but let me ping @mcara and @nden as WCS maintainers too.
  3. Eventually, move class creation to coordinates, but then it would be good to actually link the frames to the transform graph (so, e.g., one could know where to point a telescope to observe Olympus Mons). Since we do have the machinery in place to calculate barycentric coordinates of the planets, this should not be very hard, but perhaps out of scope here.

Note that I'm not really sure whether or not to keep your BodyBaseCoordinateFrame - I mostly think in the end we'd like it to do more and I don't want to preclude that (also, it should probably be BaseBodyCoordinateFrame...). I'm also worried I'm just not thinking this through completely properly - in a way, these coordinates are like EarthLocation, which is very similar but not identical to ITRS. If we can avoid that can of worms...

Comment thread astropy/coordinates/tests/test_frames.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py Outdated
Comment thread astropy/wcs/utils.py
ycoord = "LAT-"
if frame.obstime is not None:
wcs.wcs.dateobs = frame.obstime.utc.isot
if issubclass(frame.representation_type, BaseGeodeticRepresentation):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In principle, these two if statements would also apply to ICRS, so perhaps there is a way to store that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You mean ITRS, right?
I am confused about the ITRS WCS definition, because of the TLON TLAT descriptions which I cannot find in the literature... if someone has some references this will help me a lot... Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Indeed, I meant ITRS. I don't know where TLON, TLAT comes from either... But google gives, e.g., http://tdc-www.harvard.edu/software/wcstools/wcstools.multiwcs.html and https://www.astro.rug.nl/software/kapteyn/allsky.html, so I guess we should just continue to support it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks! I coudn't find those links.

Comment thread astropy/coordinates/builtin_frames/bodyframes.py Outdated
@cmarmo
cmarmo marked this pull request as draft June 29, 2023 22:29
@cmarmo

cmarmo commented Jun 29, 2023

Copy link
Copy Markdown
Member Author

I am converting this PR back to draft as #14990 needs to go in first.

@cmarmo
cmarmo force-pushed the bodyfixed-frame branch 2 times, most recently from 5bfc67c to af7a6e1 Compare July 6, 2023 02:11
@cmarmo

cmarmo commented Jul 6, 2023

Copy link
Copy Markdown
Member Author

Mark Calabretta has just released wcslib8.1, this pr is meant to work when built against wcslib versions >= 8.
May I offer a PR updating the shipped version of wcslib for astropy 6? And then I will find a way to check the wcslib version in this pr....

@cmarmo cmarmo changed the title Implement basic BodyBaseCoordinateFrame and related WCS. Implement transformation to / from CoordinateFrame from / to related WCS Jul 6, 2023
@mcara

mcara commented Jul 6, 2023

Copy link
Copy Markdown
Contributor

I'll make a PR to update bundled WCSLIB first thing in the morning. You can rebase this PR after that.

@mcara

mcara commented Jul 6, 2023

Copy link
Copy Markdown
Contributor

A PR to update WCSLIB was made here: #15035

Once it is approved, please rebase this PR.

Thanks!

@cmarmo
cmarmo force-pushed the bodyfixed-frame branch from af7a6e1 to 462093f Compare July 7, 2023 20:29
@cmarmo
cmarmo marked this pull request as ready for review July 7, 2023 21:14
@cmarmo

cmarmo commented Sep 18, 2023

Copy link
Copy Markdown
Member Author

I have addressed some of the comments ... looking forward to find some time to address the remaing ones... hopefully soon...

@mhvk

mhvk commented Sep 18, 2023

Copy link
Copy Markdown
Contributor

Great! Do ping when all are done, and I'll re-review.

@cmarmo

cmarmo commented Sep 22, 2023

Copy link
Copy Markdown
Member Author

@mhvk I believe I have addressed your comments.
Thanks for your patience!

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks! This seems almost done: the main code now has two unnecessary clauses, and I clarified what I meant with reorganizing the tests.

Comment thread astropy/wcs/utils.py Outdated
equatorial_radius,
flattening,
)
if representation_type is None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This whole clause is no longer needed - the above function call will either create the representation or return the cached function!

Indeed, this is why there is no coverage of these lines.

Comment thread astropy/wcs/utils.py Outdated
frame = solar_system_body_frame(
SOLAR_SYSTEM_OBJ_DICT.get(xcoord[:2]), representation_type
)
if frame is None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same, this is no longer needed - the function call will do it.

Comment thread astropy/wcs/tests/test_utils.py Outdated
name = "Mars"
representation_type = SphericalRepresentation

frame = IAUMARSSphereFrame()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No, that is not what I meant: I just meant that in this function I feel it is better first to test things as they are supposed to work, and then at the end test that the right errors are raised. I.e., move this pytest.raises to the very end of the test function.

Comment thread astropy/wcs/tests/test_utils.py Outdated


def test_wcs_to_body_frame():
unknown_wcs = WCS(naxis=2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Like for the other direction, I would move the tests for failures to the very end of the test function. I think it is more helpful if a test function first shows how things are supposed to work, and then checks that you get an appropriate error if you do something incorrectly.

):
frame = wcs_to_celestial_frame(triaxial_wcs)

mywcs = WCS(naxis=2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So, I would start the test function with this part.

Comment thread astropy/wcs/tests/test_utils.py
Comment thread astropy/wcs/tests/test_utils.py Outdated
mywcs.wcs.aux.a_radius = 3396190.0
mywcs.wcs.aux.b_radius = 3396190.0
mywcs.wcs.aux.c_radius = 3376190.0
frame = wcs_to_celestial_frame(mywcs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe call this frame3, so that one has

frame3 = wcs_to_celestial_frame(mywcs)
assert frame3.representation_type is not frame.representation_type
assert frame3 is not frame

@cmarmo

cmarmo commented Sep 23, 2023

Copy link
Copy Markdown
Member Author

Better now? 😁

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks all great now! Let's get it in!

@mhvk
mhvk merged commit 4c160a0 into astropy:main Sep 24, 2023
@mhvk

mhvk commented Sep 24, 2023

Copy link
Copy Markdown
Contributor

@cmarmo - there's a bit of a what's-new already, but I realize now (after merging, of course, sigh) that it may be good to add a little to it, noting that WCS can also be written (with perhaps a link to the article describing the new standard). Perhaps add to the documentation too, if you think that is already useful.

@cmarmo

cmarmo commented Sep 24, 2023

Copy link
Copy Markdown
Member Author

@cmarmo - there's a bit of a what's-new already, but I realize now (after merging, of course, sigh) that it may be good to add a little to it, noting that WCS can also be written (with perhaps a link to the article describing the new standard). Perhaps add to the documentation too, if you think that is already useful.

PR coming soon.
Thanks a lot for your time and your patience @mhvk !

@pllim

pllim commented Sep 25, 2023

Copy link
Copy Markdown
Member

Does this have anything to do with this pyinstaller failure I started seeing?

https://github.com/astropy/astropy/actions/runs/6294343966/job/17086053141

@mhvk

mhvk commented Sep 25, 2023

Copy link
Copy Markdown
Contributor

@pllim - I fear so. I think the combination of importing and setup/teardown just become too much for pytest to handle. Since really it does not matter exactly what is used in the tests, I just duplicated some definitions in #15381. Hopefully, with that, things will run (I used extra CI since I assume that's why we didn't notice the failures before).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants