astropy: Cannot directly transform output from GCRS to AltAz / need ITRS location?
EDIT: put a milestone of 4.3 for the feature request part of this issue, which is to normalize they arguments used to indicate an observer location. EDIT 2: update to include more recent behaviour (#11069)
Following discussion in #10994, I thought the example below should work, where I use get_body() to get a SkyCoord with a GCRS position for Mars at a given time and location, and try to transform it to AltAz just using body.altaz.
However, it fails, because the temporary AltAz frame that was created does not have a .location attribute. This is unexpected, since the SkyCoord made by get_body does have that information - it is just stored in attributes with a different name, obsgeoloc and obsgeovel (which are CartesianRepresentation instead of EarthLocation for .location). Indeed, if I explicitly set my body.location to the relevant value, body.altaz does work.
So I guess one question is whether we can just translate between these attributes. In principle, the simplest route might be to just let AltAz understand obsgeopos as an alias for location (and maybe eventually deprecate AltAz.location in favour of it).
But perhaps a larger question is why AltAz and, e.g., GCRS are using different attributes in the first place for storing the observer location.
I should add that I’m not 100% sure either is ideal - for general use, I’d want to have the velocity stored on the position as a derivative (i.e., at least obsgeovel as a .derivatives['s'] on obsgeopos – of course, the derivatives did not exist when obsgeovel was first introduced!). Also, it would seem better to have something that is explicit in what frame the position and velocity are defined. I think the information needed matches exactly what would be an ITRS or GCRS frame instance. So, perhaps one should have a single attribute that replaces location, obsgeoloc and obsgeovel? (and deprecate those three?) Reuse location? New obs_itrs?
cc @StuartLittlefair, @mkbrewer, @eteq, @adrn, @astrojuanlu
from astropy.coordinates import get_body, ITRS
from astropy.time import Time
from astropy import units as u
body = get_body('mars', Time(['J2010'], location=(10.*u.deg, 20*u.deg)))
# The following fails:
body.altaz
AttributeError Traceback (most recent call last)
<ipython-input-4-d1487e3dca10> in <module>
----> 1 body.altaz
~/data/mhvk/packages/astropy/astropy/coordinates/sky_coordinate.py in __getattr__(self, attr)
784 frame_cls = frame_transform_graph.lookup_name(attr)
785 if frame_cls is not None and self.frame.is_transformable_to(frame_cls):
--> 786 return self.transform_to(attr)
787
788 # Fail
~/data/mhvk/packages/astropy/astropy/coordinates/sky_coordinate.py in transform_to(self, frame, merge_attributes)
617 # Do the transformation, returning a coordinate frame of the desired
618 # final type (not generic).
--> 619 new_coord = trans(self.frame, generic_frame)
620
621 # Finally make the new SkyCoord object from the `new_coord` and
~/data/mhvk/packages/astropy/astropy/coordinates/transformations.py in __call__(self, fromcoord, toframe)
1420
1421 curr_toframe = t.tosys(**frattrs)
-> 1422 curr_coord = t(curr_coord, curr_toframe)
1423
1424 # this is safe even in the case where self.transforms is empty, because
~/data/mhvk/packages/astropy/astropy/coordinates/transformations.py in __call__(self, fromcoord, toframe)
1023 return reprwithoutdiff.realize_frame(reprwithdiff)
1024 else:
-> 1025 return supcall(fromcoord, toframe)
1026
1027
~/data/mhvk/packages/astropy/astropy/coordinates/builtin_frames/cirs_observed_transforms.py in cirs_to_altaz(cirs_coo, altaz_frame)
39
40 # first set up the astrometry context for CIRS<->AltAz
---> 41 astrom = erfa_astrom.get().apio(altaz_frame)
42 az, zen, _, _, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)
43
~/data/mhvk/packages/astropy/astropy/coordinates/erfa_astrom.py in apio(frame_or_coord)
109 For this function, an AltAz frame is expected.
110 '''
--> 111 lon, lat, height = frame_or_coord.location.to_geodetic('WGS84')
112 jd1_tt, jd2_tt = get_jd12(frame_or_coord.obstime, 'tt')
113
AttributeError: 'NoneType' object has no attribute 'to_geodetic'
# but this works
body.location = ITRS(body.obsgeoloc).earth_location
body.altaz
<SkyCoord (AltAz: obstime=['J2010.000'], location=[(-2061640.62248365, 5629477.088513, 2169697.89603318)] m, pressure=0.0 hPa, temperature=0.0 deg_C, relative_humidity=0.0, obswl=1.0 micron): (az, alt, distance) in (deg, deg, m)
[(281.60515631, 26.39730811, 1.10516762e+11)]>
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 1
- Comments: 25 (25 by maintainers)
@pllim - yes, milestone removed. Just goes to show that having a milestone on an issue is rarely useful - wish I had gotten to this though!
sunpy has also done some hacks to retain the name of an observer once it is converted to a real coordinate (via a call to get body), so something along those lines would also be useful.
I think you’d need a
MarsLocationsubclass for that and the theory for that hasn’t been invented yet. Not to mention precession and nutation.Do CIRS, TETE and AltAz have an application for a non-terrestrial observer? It seems to me that earth rotation, precession and nutation wouldn’t be applicable there. If a non-terrestrial observer needs to use an Earth centered coordinate system, GCRS would be more appropriate and all that’s needed there is to specify the observer’s position and velocity wrt the geocenter.