New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow use of JPL ephemerides in coordinate transforms and light travel time corrections #5273
Conversation
It's worth commenting on performance changes; this makes marginal difference to the performance of the transformations using the builtin ephemeris. There's a circa 5 percent slowdown due to additional overhead in preparing astropy objects for The JPL ephemerides are roughly 2x slower than the builtin equivalents. |
Now at the right PR: @StuartLittlefair - I've been travelling quite a bit, so may be a bit slow, but remain very interested! If I still don't get to this by next week, do feel free to ping again. |
Pinging @mhvk as requested... |
# first offset to heliocentric | ||
heliocart = (from_coo.cartesian.xyz).T + delta_bary_to_helio * u.au | ||
# offset to heliocentric | ||
heliocart = CartesianRepresentation(from_coo.cartesian.x + bary_sun_pos.x, from_coo.cartesian.y + bary_sun_pos.y, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move "y" to its own line so the first line is shorter and it is easier to see what happens
(of course, with #5301, this would just be from_coo.cartesian + bary_sun_pos
...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good plug :)
# get barycentric sun coordinate | ||
# this goes here to avoid circular import errors | ||
from ..solar_system import get_body_barycentric, solar_system_ephemeris | ||
ephemeris = solar_system_ephemeris.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting the ephemeris is not needed; the get_body_barycentric
function does this by default.
from ..solar_system import get_body_barycentric, solar_system_ephemeris | ||
|
||
# get barycentric sun coordinate | ||
ephemeris = solar_system_ephemeris.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above: this should not be needed.
ephemeris = solar_system_ephemeris.get() | ||
bary_sun_pos = get_body_barycentric('sun', from_coo.equinox, ephemeris=ephemeris) | ||
|
||
newrepr = CartesianRepresentation(intermed_repr.x - bary_sun_pos.x, intermed_repr.y - bary_sun_pos.y, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above: split "y" to its own line
from ..solar_system import (get_body_barycentric, get_body_barycentric_posvel, | ||
solar_system_ephemeris) | ||
# get barycentric position and velocity of earth | ||
ephemeris = solar_system_ephemeris.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, if you're just using the default ephemeris, this is not necessary.
HCRS, ICRS, GCRS, solar_system_ephemeris) | ||
|
||
# get the ephemeris for later (we don't want to set it to None) | ||
if ephemeris is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This slightly begs the question whether we're not doing the wrong thing for solar_system_ephemeris.set()
. Looking at the ScienceState
code, we could None
stand for "don't change anything" by using
@classmethod
def validate(cls, value):
if value is None:
return cls._value
# Set up Kernel; if the file is not in cache, this will download it.
cls.get_kernel(value)
return value
|
||
@remote_data | ||
@pytest.mark.skipif('not HAS_JPLEPHEM') | ||
def test_ephemerides(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, ideally we'd check against a known-to-be-correct number...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above. This may mean finally biting the bullet and installing and figuring out TEMPO2.
For locations at large distances from the Solar system, using the JPL ephemerides will make a | ||
negligible difference, on the order of micro-arcseconds. For nearby objects, such as the Moon, | ||
the difference can be of the order of milli-arcseconds. For more details about what ephemerides | ||
are available, see :ref:`astropy-coordinates-solarsystem`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would write here "..., including the requirements for using JPL ephemerides, see ..."
With that, you could remove the note below (which I feel is better kept in just one place).
The difference between the builtin ephemerides and the JPL ephemerides is normally | ||
of the order of 1/100th of a millisecond, so the builtin ephemerides should be suitable | ||
for most purposes. For more details about what ephemerides are available, | ||
see :ref:`astropy-coordinates-solarsystem`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
|
||
>>> ltt_bary_jpl = times.light_travel_time(ip_peg, ephemeris='jpl') # doctest: +REMOTE_DATA +IGNORE_OUTPUT | ||
|
||
The difference between the builtin ephemerides and the JPL ephemerides is normally |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be an idea to actually show the various values that have been gotten here and above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to the precision that's output by default, they look identical to the barycentric corrections with the default ephemeris, so I wonder if it will just look confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I see your point. I guess in principle that is interesting on its own, and you could make the fact that the difference is small explicit by displaying
(ltt_bary_jpl - ltt_bary).to(u.us)
(simularly, in the other cases, it may be useful to display ...to(u.min)
after just once showing the normal result (and thus that normally one gets a TimeDelta
out).
Obviously, none of this is very important, but I think it will help users get a sense of when they would need to use the jpl ephemeris.
@StuartLittlefair - now had a good look and like this very much. My comments are mostly cosmetical, so should take little effort to address. @eteq, @taldcroft, @astrofrog - with this PR, |
@@ -901,10 +901,14 @@ calculate light travel times to the barycentre as follows:: | |||
>>> times = time.Time([56325.95833333, 56325.978254], format='mjd', | |||
... scale='utc', location=greenwich) | |||
>>> ltt_bary = times.light_travel_time(ip_peg) | |||
>>> ltt_bary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and in the next output, add # doctest: +FLOAT_CMP
, just so we don't get hit by rounding errors.
Looks good! A few small comments remaining... |
# first offset to heliocentric | ||
heliocart = (from_coo.cartesian.xyz).T + delta_bary_to_helio * u.au | ||
# offset to heliocentric | ||
heliocart = CartesianRepresentation(from_coo.cartesian.x + bary_sun_pos.x, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, now I wonder whether to optimize when really we just want to have #5301 in... The way this is written, cartesian
gets called three times, which each time will calculate all of x
, y
, and z
, so this can be sped up nearly a factor of three by doing
from_coo_cartesian = from_coo.cartesian
heliocart = ... from_coo_cartesian.x + ...
astrom = erfa.apcs13(jd1, jd2, pv) | ||
earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_frame.obstime) | ||
|
||
# get astrometry context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This left-over comment should be deleted, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "get astrometry context"? If so, no, that's a reference to the astrom
object. I've made the comments in this section clearer.
|
||
>>> ltt_bary_jpl = times.light_travel_time(ip_peg, ephemeris='jpl') # doctest: +REMOTE_DATA +IGNORE_OUTPUT | ||
>>> ltt_bary_jpl # doctest: +REMOTE_DATA +FLOAT_CMP | ||
<TimeDelta object: scale='tdb' format='jd' value=[-0.0037715 -0.00377286]> # doctest: +REMOTE_DATA +FLOAT_CMP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to put the # doctest
on the output lines (also the line below).
@StuartLittlefair - yet more comments, all trivial. @taldcroft, @eteq, @astrofrog - unless I hear that you would like to have a look, I'll merge this tomorrow. |
This all looks OK to me, so I'll merge. Thanks very much, @StuartLittlefair!! |
@mhvk - thanks for merging this! However, I noticed the following issue with this pull request:
Would it be possible to fix this? Thanks! This is an experimental bot being written by @astrofrog - let me know if the message above is incorrect! |
@astrofrog - any idea why the bot failed here? there is a changelog entry |
No PR number attached to the change log entry. |
Just out of interest: When should a PR be squashed? I ask this here because I've noticed that it contains 28 commits with ~300 line changes, several of them about formatting, fixing tests, etc. On the other hand I've seen PRs (today one of mine, #5214 with 8 commits and ~400 line changes) with fewer commits and/or more changed lines where someone requested to squash them. Not that I mind, but it would help me decide when to ask someone to squash their PR (or not). As an afterthought: Should I have asked this on astropy-dev? |
@mhvk @StuartLittlefair - this all looks OK to me except for a few minor tweaks - I went ahead and made a separate PR on this, though (#5436), given that I never found the time to review this when it was actually submitted... |
@MSeifert04 - that's a matter of opinion. Personally I never ask for squashing unless there's a substantial file size problem (i.e. adding and then removing of a large data file). I find it useful at times to see the logic in a series of commits. But I know others prefer more coherent commits. So far we haven't had a clear policy other than "whatever the primary reviewer thinks"... |
@MSeifert04 - just to add to @eteq's comment: I think for astropy we normally don't ask for squashing (though I also do if the implementation changed completely), but numpy does always ask it. They're also different on insisting on more than a one-liner for the commit, as they don't want to rely on the github history to be around forever (probably smart, but then, they did move system, so know what it involves...). |
I am guilty for requesting squashing. I like neat commit history. 😅 |
This PR is based upon the changes in #5231, and perhaps should include changes in #5253 and #5254 as well; I will rebase once #5231 is merged and also if #5253 and #5254 are merged before this.
This PR fixes #4942 by allowing the coordinate transformations, and the light travel time corrections which use them to respect the state of the
solar_system_ephemeris
context manager.light_travel_time
takes an explicit ephemeris argument whilst the co-ordinate transformations don't. To set the ephemeris for coordinate transformations, one usessolar_system_ephemeris.set()
. The reason for this decision was that adding an ephemeris argument to the co-ordinate transforms meant adding akwargs
argument to all frame transforms when this was not really needed for most of them.With this PR, one can use: