Skip to content

Add velocity support to coordinate frames and transformations#6219

Merged
eteq merged 66 commits intoastropy:masterfrom
adrn:coordinates/frame-velocity-support
Jun 27, 2017
Merged

Add velocity support to coordinate frames and transformations#6219
eteq merged 66 commits intoastropy:masterfrom
adrn:coordinates/frame-velocity-support

Conversation

@adrn
Copy link
Member

@adrn adrn commented Jun 15, 2017

This is the 3rd of several PR's that add support for velocities in astropy.coordinates.

This PR focuses on the high-level API: passing velocity data in to frames and SkyCoord.

@adrn adrn added this to the v2.0.0 milestone Jun 15, 2017
@adrn adrn requested review from eteq and mhvk June 15, 2017 17:23
@adrn adrn force-pushed the coordinates/frame-velocity-support branch 2 times, most recently from 856e89b to 68457ec Compare June 16, 2017 04:27
@mhvk
Copy link
Contributor

mhvk commented Jun 16, 2017

@adrn - I have some smaller comments in the PR, but overall this looks very nice. Good to see that it all meshes together so well!

I guess the largest comment is worth bringing up here too: should representation_names just give all the names, of representation and differential combined. Maybe not entirely illogical, since the two are in fact stored together.

One other comment, just to be sure: I guess you and @eteq decided that pm_ra will always include the cos(dec) term - I do this myself, so OK on that account, but obviously we have to be sure to document this well. It is also a one-way street: now it will essentially be impossible to have a nicely named ra derivative that does not include the term - you'd have to use d_lon and d_lat. Again, I actually agree with this decision, but just want to be sure that was indeed the plan.

@mhvk
Copy link
Contributor

mhvk commented Jun 18, 2017

Note: Will need minor rebase after #6236 is merged.

@adrn adrn force-pushed the coordinates/frame-velocity-support branch from bc3247b to 472f385 Compare June 18, 2017 19:26
@adrn
Copy link
Member Author

adrn commented Jun 18, 2017

should representation_names just give all the names, of representation and differential combined. Maybe not entirely illogical, since the two are in fact stored together.

Do you mean representation_component_names? My gut reaction is no, I disagree that and think the differential components should not be stored in there. Elsewhere we use elements from this to retrieve attributes from the underlying representation data. We'd have to insert a bunch of checks of whether the attribute exists on the representation data or the differential...But worth discussing more.

I guess you and @eteq decided that pm_ra will always include the cos(dec) term

Yes, that was my (our?) plan -- will make sure we clearly document this!

cc @mhvk

@StuartLittlefair
Copy link
Contributor

An API question here, also relevant for #6226. I'm sure this has been discussed, so forgive me for that.

This PR handles transformations between frames, but what should we do with transformations when the obstime changes, and the frame has velocity data? Should we update the positions for the velocities (i.e update star positions for proper motion, a la erfa.starpv)? As a naive user, I might expect the following to update the stellar positions:

Star = coord.ICRS(ra=130*u.deg, dec=22*u.deg, pm_ra=100*u.mas/u.y, pm_dec=2*u.mas/u.yr, distance=100*u.pc, obstime=Time(57923.430, format='mjd'))
Star.transform_to(coord.ICRS(obstime="J2000"))

@mhvk
Copy link
Contributor

mhvk commented Jun 19, 2017

@StuartLittlefair - I don't think the update currently happens -- one can clearly not assume much! I agree with your expectation, so think we either have to implement it (not difficult in itself, though it will become much more useful once we properly include errors), or raise if the obstime changes.

@mhvk
Copy link
Contributor

mhvk commented Jun 19, 2017

p.s. The "not difficult in itself" is of course an understatement. It means we need to presume 0 for PM/RV values that are not present. My own sense would be strictness here: raise for missing values, with the exception message saying one can put in 0 if needed (just like I suggested one has to put a nominal distance for transformations that change the observer's perspective).

@StuartLittlefair
Copy link
Contributor

Agreed - this is the approach used inside erfa as well, except that they automatically insert 0 for missing data and return a warning flag. I agree we should be more cautious.

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

I went over this again with a fairly fine comb, and found mostly nitpicks, but also some more serious issues, in particular the test for unequal obstime.


if (getattr(self.data, 'differentials', None) and
hasattr(self, 'obstime') and hasattr(new_frame, 'obstime') and
np.all(self.obstime == new_frame.obstime)):
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, this surely has to be np.any(self.obstime != new_frame.obstime). And that this should be tested!

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, just to be sure, since ICRS does not have an obstime, does this mean transforming to it will always work?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this surely has to be np.any(self.obstime != new_frame.obstime). And that this should be tested!

Good point! I recall writing a test for this, but I don't see it now. It's possible I did not commit it ... (it was ~1am local time, so I will blame that...)

Also, just to be sure, since ICRS does not have an obstime, does this mean transforming to it will always work?

No, because in most (all?) cases, to get to ICRS from something that has an obstime you first have to do a transform into J2000 obstime. Certainly the AltAz (the most important case) works that way.

Copy link
Member

Choose a reason for hiding this comment

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

I take back that last part... I was getting those confused with the FK5 which have a specified equinox. So yes, it does work, and I'm adding a test for that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Possibly, it should be that if obstime is not given on a frame, it is assumed to be J2000 for this purposes. Of course, on SkyCoord, this would just work, since there the obstime is propagated.

data_repr = 'Data:\n' + data_repr

if (getattr(self.data, 'differentials', None) and
's' in self.data.differentials):
Copy link
Contributor

Choose a reason for hiding this comment

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

Alignment off.

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

RepresentationMapping('lat', 'alt')
],
r.SphericalCosLatDifferential: [
RepresentationMapping('d_lon_coslat', 'pm_az', u.mas/u.yr),
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be pm_az_cosalt - and needs a test case...

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

Copy link
Member Author

Choose a reason for hiding this comment

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

Though, what do you mean by a test case? You mean tests for proper motions in AltAz in general?

Copy link
Contributor

Choose a reason for hiding this comment

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

The test case I meant was iniatializing - presumably, as it was, it would fail with AltAz(..., pm_az_cosalt=..., ...).

RepresentationMapping('d_distance', 'radial_velocity', u.km/u.s),
],
r.SphericalDifferential: [
RepresentationMapping('d_lon', 'pm_ra', u.mas/u.yr),
Copy link
Contributor

Choose a reason for hiding this comment

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

Oops, copy & paste mistake: should be pm_lon and pm_lat.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed

A representation object or ``None`` to have no data (or use the other
keywords below).

ra : `Angle`, optional, must be keyword
Copy link
Contributor

Choose a reason for hiding this comment

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

It is not true that this must be a keyword... (and same for all up to radial_velocity)

Copy link
Member Author

Choose a reason for hiding this comment

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

All of these instances of "must be keyword" are from master...would you like me to address them here?
e.g., https://github.com/astropy/astropy/blob/master/astropy/coordinates/builtin_frames/icrs.py#L27

Copy link
Member

Choose a reason for hiding this comment

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

I'd call this either a "bug" or "docfix", so should do it in a separate PR

Copy link
Contributor

Choose a reason for hiding this comment

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

It mostly annoys me, but as long as it gets done, that's fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added a note to #6260 to remind me to do this.

representation : `BaseRepresentation` or None
A representation object or None to have no data (or use the other keywords)

l : `Angle`, optional, must be keyword
Copy link
Contributor

Choose a reason for hiding this comment

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

"must be keyword" is not true.

rmlat = RepresentationMapping('lat', 'lat', 'recommended')
component_list.insert(0, rmlat)

lists_done.append(component_list)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, now see that we don't yet support velocities. Maybe add TODO here?

representation : `BaseRepresentation` or None
A representation object or None to have no data (or use the other keywords)

sgl : `Angle`, optional, must be keyword
Copy link
Contributor

Choose a reason for hiding this comment

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

The "must be keyword" again is not true.

if allowed_classes is not None:
self.allowed_classes = tuple(allowed_classes)
else:
self.allowed_classes = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just set to BaseDifferential? That makes the check below more straightforward.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed


# two classes
rep2 = icrs.represent_as(r.CartesianRepresentation,
r.SphericalCosLatDifferential)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really want a test that checks unwanted behaviour? The reason that this doesn't feel is only because of the work-around for UnitSphericalRepresentation and RadialDifferential! I'd remove this test and write a TODO that things like this should fail in the future (or make them fail already...).

@mhvk
Copy link
Contributor

mhvk commented Jun 26, 2017

On including this in 2.0, I think it is quite close, but am not sure how much gain it is to people if SkyCoord does not support proper motions, and if we specifically do not guarantee that the API is stable. I worry somewhat that soon we'll be quite far ahead with this in master, and it will become a drag to support what we have now for multiple years. Still, perhaps the largest benefit would be to have people who want proper motions become aware of this and start testing master...

Overall, I'm neutral on whether to include this in 2.0 (though if forced to choose, I'd not).

@eteq
Copy link
Member

eteq commented Jun 26, 2017

@mhvk

Still, perhaps the largest benefit would be to have people who want proper motions become aware of this and start testing master...

My thoughts exactly - in particular, the notable time pressure is the Gaia data release in ~April 2018. If no PMs are in until 3.0, then users have at best a few months to learn/experiment, whereas this way, they have a fighting chance of getting code for Gaia in that actually has a stable API (assuming we do that in 3.0).

I agree an LTS is not the best time to do this, but I think the externalities are forcing our hand here...

@eteq
Copy link
Member

eteq commented Jun 26, 2017

(I just pushed up a PR to address the obstime bit, since that was my doing anyway)

@adrn
Copy link
Member Author

adrn commented Jun 26, 2017

I addressed @mhvk 's comments, except for the "must be keyword" comments.

This was in master, so before I change (in all frame classes), I just want to make sure those weren't there for a reason? @eteq

@eteq
Copy link
Member

eteq commented Jun 26, 2017

This was in master, so before I change (in all frame classes), I just want to make sure those weren't there for a reason?

Pretty sure this is a holdover. As I mentioned above I think this is best addressed in a follow-on PR (and is docs so we can do it later, so I'd say not in this PR)

Copy link
Member

@eteq eteq left a comment

Choose a reason for hiding this comment

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

Guess I should have done this before... but I'm happy with it as it stands.

@adrn
Copy link
Member Author

adrn commented Jun 27, 2017

Added tests to check that the frame initializers accept argument names that we expect. Test is passing locally, and previous tests passed. @eteq or @mhvk any last thoughts?

@adrn
Copy link
Member Author

adrn commented Jun 27, 2017

Sorry I missed @mhvk's comments above:

but am not sure how much gain it is to people if SkyCoord does not support proper motions

I agree with @eteq's points above, and about preparing for Gaia.

and if we specifically do not guarantee that the API is stable

I think we can guarantee that the frame-level initialization of coordinates with proper motions will be stable, no? That is, I think it is reasonable to assume that ICRS(ra=.., dec=.., pm_ra_cosdec=..., pm_dec=...) will work in to the future no matter what changes we make to the representation internals.

@eteq
Copy link
Member

eteq commented Jun 27, 2017

Alright, since everything is passing, I think we can go ahead and put this in, as @adrn and I think it's good to get this in for an experimental basis. @mhvk, I took your "neutral" above as being "if you're the deciding vote you vote no". But if you really think we shouldn't, there's still a window where we could back it (and #6226) out between now and release, as it's a straightforward revert commit of the merge.

But I do think this is the best way forward, following from the original implementation of coordinates where we started with an experimental API, kept as much of it as we could (especially the higher-level parts) and used that to build the better system.

Appreciate everyone's help with this, especially @mhvk and @StuartLittlefair ! (and @adrn of course)

@eteq eteq merged commit 2279f1c into astropy:master Jun 27, 2017
eteq added a commit that referenced this pull request Jun 27, 2017
Add velocity support to coordinate frames and transformations
@mhvk
Copy link
Contributor

mhvk commented Jun 27, 2017

🎆 🎆 🎆

(And now on to SkyCoord for 3.0..........)

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.

5 participants