Skip to content

Requesting local earth rotation angle and one additional built-in frame #10239

Closed

Description

@mkbrewer

Just as I find it frustrating that the Time package provides local sidereal time, but the coordinate package doesn't currently include a built-in frame providing topocentric position with respect to the true equator and equinox of date (issue #10230), I find it equally frustrating that the Time package doesn't provide the local earth rotation angle to complement the coordinate package's built-in CIRS frame. When working with an equatorial mounted telescope both a set of equatorial coordinates and its complementary time or angle are required in order to calculate the hour angle necessary to point the telescope. The Time package should be enhanced to provide the local earth rotation angle.

In this regard, it would also be nice to provide a built-in frame to transform CIRS coordinates to observed equatorial coordinates to complement the AltAz built-in frame. This should provide both declination and hour angle (or right ascension if the local earth rotation angle is available) adjusted for refraction and polar motion. This would be very simple as the same function that is used by AltAz (atioq()) provides these also.

Activity

  1. mkbrewer commented on Apr 30, 2020

    @mkbrewer
    ContributorAuthor

    Observed declination and hour angle would probably be best here. These are the direct analog to azimuth and altitude and are independent of the origin of right ascension in use. It is quite easy to derive the observed right ascension in either frame from these. Subtracting the hour angle from the local sidereal time yields the observed right ascension referenced to the true equinox of date, while subtracting the hour angle from the local earth rotation angle yields the observed right ascension referenced to the CIO.

  2. mhvk commented on May 20, 2020

    @mhvk
    Contributor

    @mkbrewer - rephrasing your request just so that I'm sure I understand them correctly.

    1. Is the request to have a method, say, Time.earth_rotation_angle(longitude) that uses SOFA's era00 and adds the longitude? I guess, like sidereal_time, it would return the result as a Longitude with units of hour-angle. This would be easy to do (and after sidereal_time, which I implemented, there will hopefully be less discussion on whether this belongs on EarthLocation or on Time!). Should there be any arguments beyond longitude (which would default to the location stored on the time)?

    2. And for the coordinate frame, you are thinking of an "HADec" exactly analogous to "AltAz", but for polar mount? As you note, all that would seem to take is replicating cirs_to_altaz but catching different outputs in

      az, zen, _, _, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)

      The most difficult part here may be the name...

    A more general comment on (2) is that between the various requests, it may be that quite a number of those frames in Fig.1 of the sofa tools docs might be useful on their own...

  3. maxnoe commented on May 27, 2020

    @maxnoe
    Member

    I also just stumbled on this for our simulated gamma-ray events, which don't have a proper observation time and it was wished that the coordinates be not only expressed in AltAz but also in the local equatorial frame.

    Having the earth_rotation_angle at astropy.Time seems indeed necessary, especially considering that this is "the way to go" now instead of using sidereal_time.

  4. mkbrewer commented on May 27, 2020

    @mkbrewer
    ContributorAuthor

    @mhvk Sorry, I somehow missed the notification of your comment. There is one additional element to this, but it is very small. That's the TIO locator given by SOFA's Sp00(). The local earth rotation angle is then:

    Era00() + geodetic longitude + Sp00()
    

    For reference see Apco13(), Apco(), Aper13() and Aper().

  5. mhvk commented on May 27, 2020

    @mhvk
    Contributor

    @mkbrewer - thanks! Just to be absolutely sure, there are no different "kinds" of earth rotation angle (like kind='mean' or kind='apparent' for sidereal time), nor is there a need for a possibly different model? I ask since if there are such differences, I'd rather mimic the argument structure of sidereal_time(kind, longitude=None, model=None) (though fine if there is a default for all arguments).

    I realize this all mostly comes from the fact that I have seen (and used) sidereal time a lot but have not encountered earth rotation angle before, and it is leaving me a bit confused that apco takes an earth rotation angle argument as well as an sp, i.e., with your equation, the earth rotation angle we would produce here for longitude=0 would not be what one would put as input in apco.

    p.s. Checking wikipedia (what else...), https://en.wikipedia.org/wiki/Sidereal_time#Earth_Rotation_Angle gives a definition just like era00, without the sp00 term, so if nothing else there will be others who will be confused as well... It also shows that my education well predates 2003...

  6. maxnoe commented on May 27, 2020

    @maxnoe
    Member

    I'd have to check with the explanatory supplements again, which are currently in my office and I am in the home office.

    But ERA00 should be Earth Rotation Angle at longitude 0, so I'm also a little confused that TIO comes into play here.

  7. mkbrewer commented on May 27, 2020

    @mkbrewer
    ContributorAuthor

    Since the CIO is a non-rotating origin, it isn't subject to precession or nutation so there is no "mean" or "apparent" earth rotation angle. The models you refer to regarding sidereal time are just different precession/nutation models, so that isn't applicable. (see how much simpler things are when you use the ERA). The local earth rotation angle that SOFA uses is ITRS, so it is referenced to the TIO. That's why the TIO locator is included. The SOFA "observed" coordinates are also ITRS, so this is the local earth rotation angle can be used to derive the "observed" right ascension from the "observed" hour angle or vice versa, see Atioq().

    I realize this all mostly comes from the fact that I have seen (and used) sidereal time a lot but have not encountered earth rotation angle before, and it is leaving me a bit confused that apco takes an earth rotation angle argument as well as an sp, i.e., with your equation, the earth rotation angle we would produce here for longitude=0 would not be what one would put as input in apco.

    See Apco13() for the arguments that SOFA uses for Apco(). For longitude=0 or 'greenwich' if you will, the ITRS local earth rotation angle is just: Era00() + Sp00(). See astrom->along.

    Of course, one could define a TIRS local earth rotation angle for use with CIRS coordinates to derive the intermediate place hour angle also. This would need to add the offset described in equation (6.20) of USNO Circular 179. Or more appropriately:

    lambda_tirs = arctan((sin(lambda_itrs + s') + y_p * tan(phi_itrs)) / (cos(lambda_itrs + s') - x_p * tan(phi_itrs)))
    

    which works all the way to the pole. But SOFA doesn't deal with this definition at all.

  8. mkbrewer commented on May 28, 2020

    @mkbrewer
    ContributorAuthor

    By the way, in case you are interested, the way that SOFA handles polar motion is rather non-transparent. What they are doing is:

    r_obs = R_z(lambda_itrs) W R_z(ERA) r_cirs
    

    Where r_obs is the local ITRS observed minus hour angle and declination, W is the wobble matrix and r_cirs is the CIRS right ascension and declination. This makes sense as the final rotation by geodetic longitude is applied after using the wobble matrix to transform to ITRS.

    However, with their definition of local earth rotation angle, what they actually do is:

    r_obs = R_z(lambda_itrs) W R_z(-lambda_itrs - s') R_z(ERAL) r_cirs
    

    Where s' is the TIO locator. The expression R_z(lambda_itrs) W R_z(-lambda_itrs - s') is evaluated by Apco() combined withAtioq() as "Polar motion, rotated onto the local meridian".

    It took me awhile to figure that one out.

  9. mhvk commented on May 28, 2020

    @mhvk
    Contributor

    @mkbrewer - I think I am starting to understand (having had to wrap my head around a few other problems hasn't helped). The confusion I had certainly stems from the SOFA implementation, where in apco13, an "earth rotation angle" is defined as

    /* Earth rotation angle. */
    theta = eraEra00(ut11, ut12);

    and this angle is passed straight on to apco, where it is also called "earth rotation angle" and used in a call to aper to set eral or "local earth rotation angle" in
    astrom->eral = theta + astrom->along;

    So, yes, I can see that that takes figuring out! But that gets to the practical side, would it be useful to be able get the local earth rotation angle also in this form (which perhaps is nameless?). This especially since you mention that "TIRS" version which we could have to complement the "ITRS" one your request is really about. In any case, since our earth locations are all ITRS, that seems definitely the sensible default, so even if expand the options, I think longitude should always be the first argument, i.e., one would get a method earth_rotation_angle(longitute=None, frame='itrs').

    Finally, any preference for default units? era00 itself is radians, but degrees may make more sense - at least the wikipedia article suggests that is used (rather than hours, a bit sadly, but probably wisely to avoid confusion).

  10. mkbrewer commented on May 28, 2020

    @mkbrewer
    ContributorAuthor

    So, yes, I can see that that takes figuring out! But that gets to the practical side, would it be useful to be able get the local earth rotation angle also in this form (which perhaps is nameless?).

    I'm afraid that I don't understand the question here. What form are you talking about?

    I think longitude should always be the first argument, i.e., one would get a method earth_rotation_angle(longitute=None, frame='itrs')

    If your intention is to also support the TIRS local earth rotation angle, it will be necessary to have an option to pass the latitude also. Of course, this is the ITRS geocentric latitude rather than the geodetic latitude which adds further complication. The reason that you can use the geodetic longitude is that in the WGS84 model the geodetic longitude is the same as the geocentric longitude. This is not the case for latitude however.

    Finally, any preference for default units?

    This should definitely be the same as sidereal time (u.hourangle).

  11. mkbrewer commented on May 28, 2020

    @mkbrewer
    ContributorAuthor

    One option is to only support TIRS local earth rotation angle if an EarthLocation is present, which I suspect would be true 99% of the time anyway. The SOFA function Pvtob() returns the TIRS local earth rotation angle directly, albeit as a Cartesian vector giving the observer's postion wrt the CIO. The longitudinal component of that vector is, in fact, the TIRS local earth rotation angle.

  12. mkbrewer commented on Aug 27, 2020

    @mkbrewer
    ContributorAuthor

    I thought we were on the way here, but we seem to have stalled. In case that is over confusion between ITRS (observed) and TIRS (topocentic apparent or intermediate place), here is a function that returns the TIRS longitude and an example of one way to use it in the sidereal time function. It will work exactly the same way with the local earth rotation angle. I tried to do this in Python rather than my usual C. Please forgive any errors as I am not an expert at Python.
    tirs_longitude.py.txt

  13. 12 remaining items

  14. mkbrewer commented on Nov 22, 2020

    @mkbrewer
    ContributorAuthor

    This is why I said it would be best to use longitude=None for returning ERA, GAST or GMST. The local apparent and mean sidereal times at 'greenwich' are actually GAST + 0 + s' and GMST + 0 + s'.

  15. mkbrewer commented on Nov 22, 2020

    @mkbrewer
    ContributorAuthor

    I understand that this is a bit confusing. As a matter of tradition, the IAU still uses the terms Greenwich Apparent and Mean Sidereal Time even though they are no longer referenced to the Greenwich meridian.

  16. mhvk commented on Nov 22, 2020

    @mhvk
    Contributor

    It is that last point that indeed is very confusing!! But with your explanations I at least understand a bit better why.... It would have been nice if this were pointed out in the comments of the ERFA functions.

  17. mkbrewer commented on Nov 22, 2020

    @mkbrewer
    ContributorAuthor

    First line in erfa.apco():

    /* Longitude with adjustment for TIO locator s'. */
       astrom->along = elong + sp;
    
  18. mkbrewer commented on Nov 22, 2020

    @mkbrewer
    ContributorAuthor

    If course, if the intended purpose of sidereal_time('apparent', 'greenwich') is to return GAST, then it should stay that way. One can always use sidereal_time('apparent', 0) to get the local apparent sidereal time at the Greenwich meridian.

  19. mhvk commented on Nov 23, 2020

    @mhvk
    Contributor

    No, definitely not. It is just that I took the name "Greenwich Apparent Sidereal Time" literally - it never occurred to me that "Greenwich" would not refer simply to the meridian... Now that you explained it is otherwise, I think your suggested solution of having None return the output of gst06 directly (without offset) makes a lot of sense.

  20. mkbrewer commented on Jan 28, 2021

    @mkbrewer
    ContributorAuthor

    @mhvk , @StuartLittlefair In version 1.36, Skyfield has added an apparent.hadec() method that can be directly compared to the Ha/Dec output of erfa.atioq(). This comparison is good to less than 1 mas:

    ha_dec

    and so can be used to test Astropy's hadec built-in frame (if it ever gets implemented).

  21. mhvk commented on Jan 28, 2021

    @mhvk
    Contributor

    Nice! (And, yes, we should have the HADec built-in frame... It is always a matter of someone getting around to it...)

  22. mkbrewer commented on Feb 27, 2021

    @mkbrewer
    ContributorAuthor

    @mhvk The new polar motion algorithm introduced in pyerfa 1.7.2 will affect the calculation of the local earth rotation angle and local sidereal time here. The change is minuscule as it is second order in the polar motion quantities.

  23. mkbrewer commented on Apr 30, 2021

    @mkbrewer
    ContributorAuthor

    I can implement the local earth rotation angle also, but I'd need some guidance on how to retrieve TT and UT1 from the Time object in order to do so.

  24. maxnoe commented on Apr 30, 2021

    @maxnoe
    Member

    def get_jd12(time, scale):

  25. mhvk commented on Apr 30, 2021

    @mhvk
    Contributor

    Fantastic! In principle, as simple as time.tt and time.ut1, and the implementation of sidereal_time should give some ideas, but perhaps best to deal with that after #11676? I'll request my own review on that one - hopefully some time next week...

  26. mkbrewer commented on Apr 30, 2021

    @mkbrewer
    ContributorAuthor

    I'm guessing that this would be something along the lines of:

    jd1 = getattr(getattr(self, 'tt')._time, 'jd1')
    jd2 = getattr(getattr(self, 'tt')._time, 'jd2_filled')
    

    Is that correct?

  27. mkbrewer commented on Apr 30, 2021

    @mkbrewer
    ContributorAuthor

    My plan is to do this as a separate PR from #11676 as that will be cleaner.

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