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.
|
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
bdeb9ae to
1184e7a
Compare
|
Thanks! When you think you are ready for the next step, might wanna add "Extra CI" label to make sure the tests won't fail in a more exotic setting, just in case. |
There was a problem hiding this comment.
LGTM!
I did ask Claude to do an adversarial analysis to find bugs and it found:
- negative scaling leaves a negative distance
b = SphericalRepresentation(10*u.deg, 20*u.deg, 1*u.kpc)
(-b).lon # 190 deg
(-b.with_differentials(SphericalDifferential(...))).lon # 190 deg
(-b.with_differentials(SphericalPhysicalDifferential(...))).lon # 10 deg, distance = -1 kpc
SkyCoord(-b.with_differentials(phys)) # ValueError: Distance must be >= 0- Coordinates without a distance return an angular rate labelled as a velocity
f = ICRS(ra=1*u.deg, dec=2*u.deg, pm_ra_cosdec=1*u.mas/u.yr, pm_dec=2*u.mas/u.yr)
f.represent_as("spherical", s="sphericalphysical", in_frame_units=True).differentials["s"]
# SphericalPhysicalDifferential ... in mas / (rad yr)
f.set_representation_cls(s="sphericalphysical"); f.v_ra # 1 mas / (rad yr)- Adding a RadialDifferential crashes. SphericalPhysicalDifferential + RadialDifferential raises AttributeError: 'RadialDifferential' object has no attribute '_compatible_differentials'.
- Cartesian round-trip for the common case. SphericalCosLat to SphericalPhysical is just "multiply by distance", but it goes through Cartesian and back, which is where the ~1e-17 residuals come from. A shortcut in from_representation would be cheaper and exact.
EDIT: Resolved in comment above. |
|
Oooh, this is nice to have. From just messing around I notice the output units can get slightly unusual when some components of the differentials are missing, e.g this looks great: In [38]: f = ICRS(ra=1*u.deg, dec=2*u.deg, pm_ra_cosdec=1*u.mas/u.yr, pm_dec=2*u.mas/u.yr, distance=1*u.pc, radial_velocity=
⋮ 0*u.km/u.s)
In [39]: f.represent_as("spherical", s="sphericalphysical", in_frame_units=True).differentials["s"]
Out[39]:
<SphericalPhysicalDifferential (d_lon, d_lat, d_distance) in km / s
(0.00474047, 0.00948094, -2.05095566e-20)>whereas this reports the same physical velocities along all the unit vectors, but with unusual units for some, but not all... In [40]: f = ICRS(ra=1*u.deg, dec=2*u.deg, pm_ra_cosdec=1*u.mas/u.yr, pm_dec=2*u.mas/u.yr, distance=1*u.pc)
In [41]: f.represent_as("spherical", s="sphericalphysical", in_frame_units=True).differentials["s"]
Out[41]:
<SphericalPhysicalDifferential (d_lon, d_lat, d_distance) in (mas pc / (rad yr), km / s, mas pc / (rad yr))
(1., 0.00948094, -4.32648126e-18)> |
Thanks @StuartLittlefair - yes that's related to @nstarman 's point 2 above. So then the question is whether to error or warn in that situation. Thoughts? |
|
Related but subtly different. In the missing distance case I’d expect it to error, but in the case of missing RVs the d_lon and d_lat attributes don’t depend on the RV and the values are right, so throwing an error seems wrong - I just expect different units. I guess we could check if the missing attributes affect the scales and error if so? |
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
Addressing the comments now. While I was fixing @nstarman's comment 2. above, I found another bug: import astropy.units as u
import astropy.coordinates as coord
c = coord.SkyCoord(
ra=1 * u.deg, dec=2 * u.deg, pm_ra_cosdec=1 * u.mas / u.yr, pm_dec=2 * u.mas / u.yr
)
c.set_representation_cls(s="spherical")
print(repr(c))returns Note the "pm_ra_coslat" instead of "pm_ra_cosdec"! I think this is a separate issue on main, but also affects this. I'll put a commit in here to fix it but fine if you think I should move it to a separate PR. |
@nstarman - that's not unique to these classes. For example, this fails with that error on main: import astropy.units as u
from astropy.coordinates import CylindricalDifferential, RadialDifferential
CylindricalDifferential(1 * u.km / u.s, 1 * u.mas / u.yr, 1 * u.km / u.s) + RadialDifferential(1 * u.km / u.s)I guess we'd rather raise a more informative error, or maybe |
@nstarman I think the small 1e-17 is unfortunate but consistent with other re-representations in coordinates. Adding a shortcut, I think, would also mean special-casing the physical differentials in |
|
Those 1e-17 residuals cause issues elsewhere as well, particularly for differentials attached to representations near the poles, e.g the non-physical motion in ra_cosdec here: b = SphericalRepresentation(0*u.deg, -90*u.deg, 1*u.kpc)
bd = b.with_differentials(SphericalDifferential(1*u.deg/u.s, 0*u.deg/u.s, 0*u.km/u.s))
ic = ICRS(bd)which (I think) arises as: In [19]: bd.differentials['s']._get_base_vectors(b)
Out[19]:
({'lon': <CartesianRepresentation (x, y, z) [dimensionless]
(-0., 1., 0.)>,
'lat': <CartesianRepresentation (x, y, z) [dimensionless]
(1., 0., 6.123234e-17)>,
'distance': <CartesianRepresentation (x, y, z) [dimensionless]
(6.123234e-17, 0., -1.)>},
{'lon': <Quantity 6.123234e-17 kpc / rad>,
'lat': <Quantity 1. kpc / rad>,
'distance': <Quantity 1.>})So I'd prefer raising this as a separate issue where we potentially special case a number of transforms |
|
Thanks, yes I agree. I think other fixes have been implemented btw. |
Description
This PR adds some long, long awaited functionality to enable
astropy.coordinatesto work with angular velocities in physical units (e.g., km/s) instaed of angular velocity units (e.g., rad/yr). This works here by adding newDifferentialclasses that scale the velocity components by the base representation unit vectors. This was @mhvk's suggestion in #7655 (only 8 years ago 💀). I'm pleased that this ended up being a fairly minor set of changes!With this PR, we can now do things like:
or
Fixes #7655
AI Disclosure
If AI tools were used to develop this pull request, describe the tools including specific model and version, how they were used, and what content is AI generated. Otherwise enter "N/A".
Claude Opus 5.5 was used to help plan these changes, but code was implemented by me. Tests were implemented by Claude Opus 5.5
Merge method