-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Safer use of jd1/jd2 times when using erfa #4302
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
Conversation
…ws how to handle this case correctly
…en utc is outside IERS table range
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.
@taldcroft - I have on and off wrote sequences like this as well, as it helps speed up the case where the scale is already correct (avoiding the creation of a new instance). But it is also a bit ugly... Often, like here, it is in preparation to get both jd, so maybe a function to get those in a certain scale? (with default, just returning internal jd1, jd2 if no scale given). But perhaps this is overoptimization...
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.
Actually, @eteq - since this seem to happen mostly when you are getting out jd1 and jd2, maybe this would be something for a very small helper function instead:
def jds(time, scale=None):
t = time if scale is None or scale == time.scale else getattr(time, scale)
return t.jd1, t.jd2
which allows you do do:
jd1, jd2 = jds(obstime, scale='utc')
(or for simple functions to put in directly as arguments: erfa.obl06(*jds(obstime, 'tt')))
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.
@mhvk - relevant to the above questions, here is the code:
def __getattr__(self, attr):
"""
Get dynamic attributes to output format or do timescale conversion.
"""
if attr in self.SCALES and self.scale is not None:
tm = self.replicate()
tm._set_scale(attr)
return tm
What about:
- Return
selfifattr == self.scale? - Cache other scales so getting both
jd1andjd2after transforming will be efficient?
Roughly:
def __getattr__(self, attr):
"""
Get dynamic attributes to output format or do timescale conversion.
"""
if attr in self.SCALES and self.scale is not None:
if attr == self.scale:
tm = self
elif attr in self._scale_cache:
tm = self._scale_cache[attr]
else:
tm = self.replicate()
tm._set_scale(attr)
self._scale_cache[attr] = tm
return tm
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 guess we would need to clear the cache if delta_ut1_utc or delta_tdb_tt were set.
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.
@taldcroft - since Time instances are immutable, I think we could at least do the very simple change of just returning self if the scale is already correct. The caching I'm less sure about; maybe adding a bit too much complexity.
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 like @taldcroft's suggestion here. The first thing I thought was "I should be able to do time.tt.jd1, time.tt.jd2, because that's the clearest. But then I checked and realized it's not cached, so I decided it wasn't fast enough given that this is in inner loops. So I naturally assumed there would be a cache and was surprised that there wasn't.
If it helps any, there's precedence in coordinates itself for this. So I'd advocate for instead doing just as @taldcroft says here.
I think that's a "new feature", though, so it probably has to wait for 1.2 . In the meantime, I will create a utility function as @mhvk suggests just for coordinates, which we can later change to just being return getattr(time, scale).jd1, getattr(time, scale).jd2 or just replace all of it with direct conversions once the caching and such is in.
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.
|
Great! Some minor comments inline. |
|
Ok, this is now using a |
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.
By just accessing delta_ut1_utc you'll get an IndexError if the time is outside of the IERS table. I think if the time is OK, it is not a problem for the time instance to change, but if it is outside IERS, it should ideally not be set. I think you would need to do something like:
if scale == time.scale:
newtime = time
else:
try:
newtime = getattr(time, scale)
except IndexError:
# similar warning to that in get_dut1dutc
newtime = time
return newtime.jd1, newtime.jd2
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.
ohh, I didn't realize the accessor triggered the error - will do what you suggest here, then.
|
@eteq - the code does feel quite a bit cleaner with the little helper function! I also think it all looks good, though I cannot say I've looked through the whole code to see whether it is complete. |
|
Replying to your comment: the only way to do the On moving to |
|
Alright, I fixed the issue @mhvk mentioned and in the process decided to convert the This should now be all set, so if the tests pass I'll go ahead and merge and backport it. |
Safer use of jd1/jd2 times when using erfa
|
@eteq - good to see this in, and good idea to have the |
Safer use of jd1/jd2 times when using erfa
|
backported to v1.1.x in db623a2 |
This was inspired by, subsumes, and closes #4290 (and it includes its commit history).
There, @StuartLittlefair pointed out (and fixed) the fact that the intermediate rotation transforms often expect tt, and most obstimes and such are given as utc. This PR extends that further to the whole
coordinatesmodule whereerfais used, doing a transformation to whatever the appropriate scales when needed.Note that in many cases (perhaps all here?) this is a small effect - e.g. the TT vs. TDB difference is unimportant for most coordinates, and just about all of these scale shifts are in the machine noise for secular things like the location of the Earth relative to the Sun (except maybe for some corner cases that I'm not aware of). But this is definitely more "right" than it was before.
Two questions about this, though:
Timeobject? (I think this is a non-issue, but I just wanted to check to be sure...)