Repository navigation
ENH: Lagrangian interpolation for UT1-UTC in IERS data - #18036
MaanasArora wants to merge 16 commits into
Conversation
|
Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.
|
There was a problem hiding this comment.
Welcome to Astropy 👋 and congratulations on your first pull request! 🎉
A project member will respond to you as soon as possible; in the meantime, please have a look over the Checklist for Contributed Code and make sure you've addressed as many of the questions there as possible.
If you feel that this pull request has not been responded to in a timely manner, please send a message directly to the development mailing list. If the issue is urgent or sensitive in nature (e.g., a security vulnerability) please send an e-mail directly to the private e-mail [email protected].
|
CI is failing so I think this is too risky to go into v7.1 given how close we are to feature freeze. I have turned this into draft for and milestoned it for v7.2. Thank you for your interest and understanding. |
|
No worries, thanks for looking at this. |
mhvk
left a comment
There was a problem hiding this comment.
Thanks for the PR! Some smaller comments are in-line.
Bigger ones: As @pllim notes, first thing would be to make sure that the code passes tests. Note that the failures may well be because the answer actually changes a little. But we should not simply adjust test, but rather expand them for two choices, of either linear interpolation ignoring tides, or quadratic including them (see also below).
More generally: if we go this route, we will also want to interpolate other columns with higher order, so it may make more sense to try to have one interpolation routine rather than special-case UT1-UTC. The only reason UT1_UTC is different from X and Y is because of the leap seconds, so perhaps one can find some generic way to deal with that, then interpolate either linearly or quadratically, and then take into account the leap second again.
Another general note: I think that without the tides there is not so much point in doing the quadratic interpolation. Also, eventually, since the tides is a relatively heavy computation, we probably want a ScienceState configuration to decide how to do it.
Finally, just a note: we are very close to feature freeze, so I won't have time to help much the coming weeks. I do really like the idea of closing that very old issue, though!
| for j in range(len(x_vals)): | ||
| if i != j: | ||
| diff = x_vals[i] - x_vals[j] | ||
| diff = np.where(diff == 0, 1e-10, diff) |
There was a problem hiding this comment.
Within the IERS table, it is guaranteed that the x values are never the same, so this shouldn't be necessary.
|
|
||
| def _ut1_utc_interp(self, i0, i1, mjd): | ||
| indices = np.array([i0 - 1, i0, i1, i1 + 1]) | ||
| indices = np.clip(indices, 0, len(self) - 1) |
There was a problem hiding this comment.
I think you'll need to set up the clipping of i1 on l.462 (pre-change) in interpolate differently instead of redoing the clipping here. Note that if you look at https://hpiers.obspm.fr/iers/models/interp.f, it is not the indices that are clipped - rather it is made sure that there are always three values.
| vals[1:] += leap_diff | ||
|
|
||
| val = self._lagrange_interp(mjds, vals, mjd) | ||
| val -= leap_diff[0] |
There was a problem hiding this comment.
I think in the general case you cannot be sure index 0 is the right one to subtract. Which one it is depends on how the 3 surrounding points are selected, so this likely is an array.
Probably also need benchmarking then? |
Yes, but only if the tides are actually included (which is not yet the case). |
|
Thank you @mhvk ; these all make sense! I'm starting by generalizing the routine to allow (optionally) interpolation for any column / order, which should clear a lot of the issues, next I'll add the tides logic. |
|
Sorry for the slight delay and thanks again @mhvk, the pointers were really helpful! I have provisioned for allowing Lagrange interpolation over all columns, and the order can be changed from the default (cubic), but it's the same for all columns; I suppose we would want different orders for different columns (higher for X and Y perhaps), but what would they be (at least the defaults)? I think I've addressed the minor points--the leap second handling and index clipping is now more sophisticated, and works with the order. One can select to use linear interpolation and it is enabled by default, so the tests pass as usual. Thinking of adding new tests for the other interpolation methods but perhaps we can clarify the details and add the tides first. If this looks like the right direction I can go ahead and add the tides! |
|
The failing tests are for coverage (which will be added of course), and the changelog -- not sure if anything needs to be done there! |
|
I've made some improvements, including a fix to the leap second offset index, and added some parametrized coverage for interpolation to |
|
Hi @mhvk, I've added adjustment for the luni-solar tides! I'll double check again the constants as there were so many, and then maybe should add a boolean parameter for this? Would appreciate a look at this. Thank you! |
|
Hi humans 👋 - this pull request hasn't had any new commits for approximately 5 months. I plan to close this in a month if the pull request doesn't have any new commits by then. In lieu of a stalled pull request, please consider closing this and open an issue instead if a reminder is needed to revisit in the future. Maintainers may also choose to add keep-open label to keep this PR open but it is discouraged unless absolutely necessary. If this PR still needs to be reviewed, as an author, you can rebase it to reset the clock. If you believe I commented on this pull request incorrectly, please report this here. |
|
@MaanasArora - I'm very sorry that this completely slipped through the cracks... I only got reminded because the bot is trying to close this PR (I've removed the I think the code itself is good, but I wonder about how best to expose it to the user. Generally, someone does not use this code directly, but it gets called when transforming a time or coordinate. Passing up arguments seems a non-starter; instead, I think these belong as configuration items in
I guess in principle one could also have "lagrange" which omits the tides, but it is not obvious to me that is useful: is it actually closer to the truth than linear? It would need testing. I do not think we should expose things like On "the truth", we do need something to compare with! I guess easiest would be to run |
|
@MaanasArora - turned out Interpolation of IERS tablesThe file A draft signature file was made by and then edited to make clear what variables are input and output Compilation to a module is then with, Then, as a trial, |
a840249 to
9466e21
Compare
|
@mhvk - no worries, thank you for looking at this, and the helpful pointers! (Sorry, this comment ended up long.) About exposing the feature: yes, agreed, providing the interpolation method in configuration seems much better than passing arguments. I added a configuration parameter to the IERS configuration class. It accepts I was able to compile
Python script to convert cleaned CSV to NumPy codeimport pandas as pd
import numpy as np
csv = pd.read_csv("interp_pmut1_oceans.csv", index_col=False)
arg = csv.iloc[:, :6].to_numpy()
val = csv.iloc[:, 6:].to_numpy()
# format as Python code to create a numpy array
print("OCEANS_ARG = np.array([")
for row in arg:
print(" [", end="")
print(", ".join(f"{x}" for x in row), end="")
print("],")
print("])")
print("OCEANS_VAL = np.array([")
for row in val:
print(" [", end="")
print(", ".join(f"{x}" for x in row), end="")
print("],")
print("])")
On testing, and whether just a Testing scriptfrom interp_mod import interp
from astropy.time import Time
from astropy.utils import iers as iers_module
from astropy.utils.iers import IERS_Auto
import numpy as np
def get_expected_values(iers, ts):
return np.array(
[
interp(iers["MJD"], iers["PM_x"], iers["PM_y"], iers["UT1_UTC"], t.mjd)
for t in ts
]
).transpose()
def get_values_from_iers(iers, ts, method):
iers_module.conf.ut1_utc_interpolation = method
x, y = iers.pm_xy(ts)
ut1_utc = iers.ut1_utc(ts)
return np.array([x, y, ut1_utc])
def compare_interp_methods(iers, ts):
ts_expected = get_expected_values(iers, ts)[2]
ts_linear = get_values_from_iers(iers, ts, "linear")[2]
ts_tides = get_values_from_iers(iers, ts, "tides")[2]
error_linear = np.abs(ts_linear - ts_expected)
error_tides = np.abs(ts_tides - ts_expected)
return error_linear, error_tides
if __name__ == "__main__":
iers = IERS_Auto.open()
# sample 1000 points between 2024 and 2026
start_mjd = Time("2024-01-01").mjd
end_mjd = Time("2026-01-01").mjd
ts = Time(np.linspace(start_mjd, end_mjd, 1000), format="mjd")
error_linear, error_tides = compare_interp_methods(iers, ts)
print(f"Mean absolute error (linear): {np.mean(error_linear):.3e} seconds")
print(f"Mean absolute error (tides): {np.mean(error_tides):.3e} seconds")
print(f"Max absolute error (linear): {np.max(error_linear):.3e} seconds")
print(f"Max absolute error (tides): {np.max(error_tides):.3e} seconds")With the current state of the branch, the results are very close to the reference: The gains without tidal corrections seem much more marginal. So, I suppose it is not really worth it, so I'm not exposing a |
|
Thanks, that is great! So, it looks like we just have two config options. I agree with your hesitance about large parameter arrays inside the code. Since you already made the .csv, I think we should just include that and load it on demand. After all, we are already loading the (far larger) IERS tables on demand as well, so it is not like this will meaningfully affect performance. However, I think we should use the |
|
p.s. Should have added: since getting it from |
…e leap second handling for UT1-UTC
d0c5bf4 to
f98d2fb
Compare
|
Thanks, yes I just included the |
mhvk
left a comment
There was a problem hiding this comment.
@MaanasArora - thanks, that is looking pretty good. I'll try to have a more in-depth review later, but for now just a tiny irritant that might as well go: please do use np.newaxis instead of None - I know they are the same, but readability matters! (And I for one am completely used to reading np.newaxis, while with None I have to think. This is of course the reason np.newaxis exists...)
I do hope that we can include positions as well...
One thing I'm not sure about still is whether the config item is the right place after all. The alternative I realized exists is the earth_orientation_table ScienceState. That may be slightly more logical, as it is specifically meant to set parameters that can influence the science in giving one different results, while configuration is not meant to change results at all. The one tricky bit is that now the earth_orientation_table would need to be able to deal with multiple arguments. Anyway, will think a bit more myself.
|
Thanks @mhvk! PMUT1_OCEANS: ARG(3) = -0.00001149d0*T**4 + 0.000136d0*T**3
. - 0.5532d0*T**2
. + 129596581.0481d0*T + 1287104.79305d0PM_GRAVI: ARG(3) = -0.00001149d0*T**4 - 0.000136d0*T**3
. - 0.5532d0*T**2
. + 129596581.0481d0*T + 1287104.79305d0The sign of the second term ( |
|
That's a nice catch! Looking at https://hpiers.obspm.fr/eop-pc/models/models.html_nov08, I'm led to https://hpiers.obspm.fr/eop-pc/models/PM/PM_oceanic_hf_tab.html and via So, the term should be negative in I think that more or less settles it, but let me send an e-mail to point out the inconsistency. That also gives me a nice opportunity to verify the procedure, and ask whether there are some reference numbers we can compare with. |
|
Thanks @mhvk for the email, that is likely correct indeed, so I've updated the sign to be negative! |
Description
This PR implements cubic Lagrangian interpolation (instead of linear interpolation) for only UT1-UTC in IERS data as suggested in #1803. Currently does not correct for luni-solar tides (step 2 and 4).
I'm new to this project, so hope this aligns with the feature request! There was some confusion around verifying the procedure in the linked issue it seems, so open to discussing further--thank you for reviewing!
Fixes #1803.