Skip to content

CIRS is not at the ultimate accuracy #10356

Description

@mhvk

Copying @mkbrewer's #10230 (comment):

It is unfortunate that you only implement geocentric position for your CIRS frame. You use apci() and apio() rather than the more rigorous apco() which builds the observer's topocentric position and velocity (if present) right in. This has two side effects. In going from ICRS to CIRS light deflection doesn't take into account a topocentric observer's position and velocity and in going from CIRS to AltAz the less rigorous simple first-order vector expression for diurnal aberration as mentioned in paragraph 4.7 of the SOFA Astrometry Tools document is used.

It sounds like we could improve things fairly simply since GCRS seems OK:

On the other hand, your GCRS frame does implement topocentric position rigorously. Therefore, I find it curious that you don't derive your CIRS frame from GCRS. After all, with GCRS you are just one step of applying the CIO based BPN matrix from true topocentric CIRS intermediate (apparent) place. The call to apcs() in this transform properly sets up the ASTROM data structure for rigorously calculating gravitational light deflection, diurnal aberration and diurnal parallax including the observer's position and velocity (including taking the observer's velocity into account in beta - 1). I particularly like the way that diurnal aberration is naturally included in Ab() this way, so that the transformation from topocentric CIRS to AltAz can be done without resorting to the use of astrom->diurab.

Activity

  1. mkbrewer commented on Aug 23, 2020

    @mkbrewer
    Contributor

    Now that GCRS is pretty much all set, it's time to address the other elephant in the room which are the GCRS to CIRS and CIRS to observed transforms. The problem here is that instead of following the atco chain, you chose to use atci and atio instead. What SOFA fails to mention, is that the later is completely incompatible with solar system bodies where diurnal parallax comes into play (although, if you look closely, the documentation for atci13() does say that it is specifically for star data) This is especially true of the Moon, so that is what I've concentrated on here. There, I can't help but notice a rather large (to my standards) error in the returned Alt/Az coordinates. Here is the error between your Alt/Az and mine in the latest data file that I have from you.
    AzElError
    This is in coordinate space and on this date, the Moon reaches lower meridian transit at 13:05 UT. At that time the elevation is -80.5 degrees, so I also plotted the actual offset on the sky which looks better, but is still pretty bad.
    OnSkyAzElError
    I was able to reproduce this exactly (to 20 uas) by altering my program to follow the steps that you use.

    1. Transform the topocentric GCRS coordinates back to BCRS..
    2. Drop the EarthLocation and transform to geocentric GCRS.
    3. Apply the BPN matrix to transform to geocentric CIRS.
    4. Add the EarthLocation back in to transform to topocentric CIRS.
    5. Use apio() to set up the CIRS to observed transform.
    6. Call atioq() to transform to Alt/Az.

    It turns out that the root of the problem is in the transform to geocentric GCRS. Specifically the geocentric aberration. When observing the Moon, there is a contribution to diurnal aberration from the diurnal parallax. This comes in to the aberration calculated by ab() due to the diurnal offsets in the topocentric direction vector from the observer to the Moon. I was able to confirm this by altering the steps that you use. In the transformation to geocentric GCRS, I retained the topocentric BCRS unit vectors, but called apcg() instead of apco() to tell SOFA that I was using geocentric positions even though I wasn't. This eliminated the velocity based component of the diurnal aberration but retained the position based component. Then comparing the resulting CIRS Ra/Dec to that obtained by using the full topocentric GCRS transform yielded a nice velocity based diurnal aberration. Very sinusoidal with the Declination component dropping to zero at upper and lower meridian transit.
    MKBRADecError
    Then I used apio() as before to set up the velocity based diurnal aberration during the transformation to Alt/Az. The resulting Alt/Az positions were in agreement with my normal data (full topocentric transform using apco()) to within 15 uas.
    On the other hand, the CIRS RA/Dec offsets obtained from following your procedure exactly weren't nearly as pretty.
    AstropyRADecError
    There is a phase shift and an offset in the Declination sinusoid due to the missing position based diurnal aberration.

    Clearly, the way to solve this problem is to merely apply the BPN matrix directly to yield topocentric CIRS coordinates without any folderol of transforming the GCRS coordinates to geocentric first. Then you can still use apio13(), if you'd like, to set up the Alt/Az transformation, but you must be sure to set astrom['diurab'] to zero before calling atioq(). Since this is rather inefficient, it would better to make a modified version of apio() dropping the call to pvtob() and setting astrom->diurab to zero directly.

  2. mkbrewer commented on Aug 24, 2020

    @mkbrewer
    Contributor

    Note that you can also apply the BPN to the gcrs_frame.obsgeoloc attribute to get the appropriate cirs_frame.obsgeoloc attribute to apply to topocentrc CIRS (topocentric intermediate place). Yes, I know that, as currently implemented, CIRS doesn't have an obsgeolocattribute, but it should. Also note that the true equator true equinox (TETE) frame that I requested (issue #10230) can also be realized in the same manner by merely applying the equinox based BPN to either geocentric GCRS (proper place) or topocentric GCRS (local place) to derive geocentric TETE (apparent place) or topocentric TETE (topocentric apparent place)

  3. maxnoe commented on Oct 15, 2020

    @maxnoe
    Member

    @mkbrewer could you maybe summarize what the proposed solution is for the CIRS transform graph?

    So which changes are required to CIRS (I see the addition of an obsgeoloc?) and which erfa functions should be used in the transform graph?

  4. StuartLittlefair commented on Oct 15, 2020

    @StuartLittlefair
    Contributor

    @maxnoe - it may be worth holding your trigger on this for a few days. I'm about to push an implementation of apparent place coordinates (TETE) which, when finished would make a reasonable starting point for how to implement CIRS with obsgeoloc/vel.

    Most of the methods I use could be ported to the corrections in CIRS quite simply, but the ICRS<->CIRS transforms will need fixing, or indeed removing, since in principle one can rely on ICRS->GCRS->CIRS without the direct transformation.

  5. mkbrewer commented on Oct 15, 2020

    @mkbrewer
    Contributor

    I second what @StuartLittlefair has said here. The only difference between CIRS and TETE is the BPN matrix that is used. If topocentric intermediate place inherits its observer location from the GCRS frame, then the observer's geodetic longitude and latitude can easily be extracted for use in conversion to AltAz or HADec.

  6. mkbrewer commented on Oct 15, 2020

    @mkbrewer
    Contributor

    But to answer your question, the idea here would be to start with a GCRS frame (either geocentric or topocentric), then call get_cip() and c2ixys() to build the CIO based BPN matrix for transformation to CIRS. Or equivalently, call gcrs_to_cirs_mat() from intermediate_rotation_transforms to get the BPN matrix directly. Please note that, as currently implemented, gcrs_to_cirs() from intermediate_rotation_transforms won't work for this as it converts from topocentric to geocentric.

  7. mkbrewer commented on Oct 15, 2020

    @mkbrewer
    Contributor

    On the other hand, just like TETE, one can envision an AltAz or HADec frame with it's unique time and observer location as is currently done. But then the CIRS location would need to be converted to GCRS in order to do the transformation back to ICRS/BCRS to get the source position at the given time and then pass back through GCRS to finally arrive at CIRS ready for conversion to AltAz or HADec. .

  8. mkbrewer commented on Oct 15, 2020

    @mkbrewer
    Contributor

    Seems the long way around. Of course, apco() will do that for you. It would only be necessary to extract the GCRS position of the observer that apco() constructs to derive the ICRS/BCRS position of the source, then use the resulting astrom data structure for conversion to observed coordinates. See apco13() for an example of how to do this.

  9. StuartLittlefair commented on Oct 16, 2020

    @StuartLittlefair
    Contributor

    I'm getting somewhere with this now. I've added a topocentric position to CIRS (in GCRS coordinates for consistency with other frames). I think I have the ICRS<->CIRS and GCRS<->CIRS figure out. Just have to try and fix CIRS<->AltAz following @mkbrewer's suggestions

  10. StuartLittlefair commented on Oct 17, 2020

    @StuartLittlefair
    Contributor

    Well, partial success; I have managed to reduce the discrepancies by following the two routes @mkbrewer suggested - either using apio13 and setting astrom['diurab']=0, or using apco to get the astrom context. However, the discrepancies still show some residual structure for @mkbrewer's moon test case.

    moon_azel

    Note: I get identical results using the direct ICRS->AltAz transform sketched out in #10887

    For some reason I am unable to get a good comparison with Horizons, or SkyField's output. One thing that makes this difficult is that I am not sure I have an up-to-date file of the output from @mkbrewer's script. I'm pretty sure the version I have is out-of-date. Do you think you could share this here?

    I'd like the correct Az and El for the Moon on Apr 6 2017 from an observatory at 22.959748 deg S, 67.787260 deg W and 5186m...

  11. mkbrewer commented on Oct 17, 2020

    @mkbrewer
    Contributor

    What version of the output data that I gave you are you using here? If it's moon_topo_4_6_2017_mkb_v5_ap_polar_motion.csv, then I'd like to see the Ra/Dec comparison also. Perhaps the best thing to do is for you to post your output so that I can look into the apparent discrepancy.

  12. StuartLittlefair commented on Oct 17, 2020

    @StuartLittlefair
    Contributor

    It’s a lot older than that - the file name is just moon_topo_4_6_2017_mkb_ap.csv. If I have a copy of the latest data then I know if the things I am doing are working.

    My file from my efforts so far is attached. The fact that I get the same answer from the snippet in #10887 must be telling me something, but I don't know what yet!

    moon_topo_4_6_2017_astropy_10356.txt

  13. mkbrewer commented on Oct 17, 2020

    @mkbrewer
    Contributor

    Here you go.

    AstropyAzAltFixed

  14. 5 remaining items

  15. mkbrewer commented on Oct 23, 2020

    @mkbrewer
    Contributor

    Note that you can also apply the BPN to the gcrs_frame.obsgeoloc attribute to get the appropriate cirs_frame.obsgeoloc attribute to apply to topocentrc CIRS (topocentric intermediate place).

    #10356 (comment). The reason that I suggested using the observer's CIRS location in the CIRS frame rather than the GCRS obsgeoloc is that it avoids the necessity of recomputing the GCRS->CIRS BPN matrix as you already have that available during the transform from GCRS to CIRS.

  16. mkbrewer commented on Oct 23, 2020

    @mkbrewer
    Contributor

    In the above case, this BPN matrix is actually computed twice. Once in EarthLocation.get_gcrs_posvel() to get the observer's obsgeoloc in the GCRS and a second time to convert this to the observer's location in the CIRS. This could be obviated by simply creating a function EarthLocation.get_cirs_pos().

  17. StuartLittlefair commented on Nov 4, 2020

    @StuartLittlefair
    Contributor

    OK - so having now convinced myself that astropy is doing the right thing when converting geocentric CIRS to topocentric CIRS I am almost ready to add some tests to my branch and submit a PR. I have one outstanding question for @mkbrewer. I find excellent agreement with your data (moon_topo_4_6_2017_mkb_ap_v5_10356.txt), but poor agreement (up to 1" out) with JPL Horizons and Skyfield.

    astropy_vs_jpl_polarmotion

    astropy_vs_skyfield_polarmotion

    The agreement gets much better if I turn polar motion off:

    astropy_vs_jpl_nopolarmotion
    astropy_vs_skyfield_nopolarmotion

    Although interestingly there I recover the patterns that I saw compared to an older output from your code (moon_topo_4_6_2017_mkb_ap.csv).

    Comparing HORIZONS to Skyfield reveals a similar pattern so it seems almost everyone disagrees at this level apart from us!

    horizons_vs_skyf

    I am surprised that HORIZONS seems to ignore polar motion by default, but my question is whether you understand the pattern that remains after I turn polar motion off?

  18. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    @StuartLittlefair Sorry to be long in responding. I didn't notice this post for awhile and then I had issues with my installation of Skyfield that turned out to be due to it no longer being able to download EOP data from the USNO. After upgrading to the latest version, it's working again. If I disable polar motion in my program and Skyfield, I get very good agreement.

    az_el_mkb_skyfield_no_polar

    Here is the script that I used:

    skyfield_topo_test.py.txt

  19. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    Regarding JPL Horizons, that's a whole can of worms there. I have never been able to get good agreement in AltAz with them. They do use polar motion, but the EOPs that they use are significantly different than the IERS published data. You can request the EOPs that they use if you wish. I did that once and I still couldn't get good agreement. This led me to compare my output to Skyfield, but unfortunately, there are rather significant issues that Skyfield has with polar motion. I've been trying to to get Brandon Rhodes to address this since May, so far to little avail. In fact, he recently downgraded the issue I opened to a feature request rather than a bug, so I have no idea when he's going to get around to addressing it.

  20. StuartLittlefair commented on Nov 5, 2020

    @StuartLittlefair
    Contributor

    Thanks @mkbrewer - don't worry about the time it takes you to reply. I'm asleep whilst you are working! Upgrading Skyfield to the latest version made a big difference for me, but I'm not quite as close as you still.

    The output I have from your code is moon_topo_4_6_2017_mkb_ap_v5_10356.csv. Is the only difference between the output you compare to Skyfield and the output I have polar motion? In which case I probably haven't disabled it properly in astropy...

    astropy_vs_skyfield_nopolarmotion

    Nevertheless we are looking good to go here - I just need to write some tests. This is why I was trying to compare to HORIZONS - it would be good to have an independent third party!

  21. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    Yes, I simply set xp and yp to zero when I call apco().

    btw, upgrading Skyfield made a difference for me also. I am no longer seeing the oscillations that were previously present. This is most easily seen in the residual for the distance to the Moon.
    moon_dist_v_1 10
    moon_dist_v_1 31

  22. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    I am curious if you still see that level of discrepancy if you use the code in #10887. There it would be quite easy to disable polar motion by simply setting xp and yp to zero.

  23. StuartLittlefair commented on Nov 5, 2020

    @StuartLittlefair
    Contributor

    No, using that code I get the same as Skyfield to better than 0.6 mas.

  24. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    OK. I don't know how you are disabling polar motion in the standard transform. Is there any possibility that you are disabling it in some places, but not others? One that comes to mind is get_gcrs_posvel().

  25. StuartLittlefair commented on Nov 5, 2020

    @StuartLittlefair
    Contributor

    That was my thought as well. I’m not too concerned about chasing it up because I don’t think we’d be interested in turning it on/off.

  26. mkbrewer commented on Nov 5, 2020

    @mkbrewer
    Contributor

    Well, If I can ever get Brandon Rhodes to fix polar motion in Skyfield, this won't be an issue anyway. On that, once this is finished, it will be quite helpful as he can compare his results to yours without having to rely on data that I give him.

  27. mkbrewer commented on Nov 14, 2020

    @mkbrewer
    Contributor

    @StuartLittlefair I am pleased to announce that polar motion is now fixed in Skyfield. Here are the new residual plots between my program and Skyfield.

    ra_dec_both_polar
    az_el_both_polar
    This fix should be available at the next release of Skyfield.

  28. mhvk commented on Nov 15, 2020

    @mhvk
    ContributorAuthor

    @mkbrewer - nice! And super that you now have helped to get this right in two packages!

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions