Credit the IAU W on the three moons whose orbits take terms from it, guard Tethys's, and say what Mimas's lock ceiling is

Since f8ee3ac, Mimas, Tethys and Phobos move by terms taken from their IAU W in NAIF's pck00011:
Mimas's -44.85 degree S5 term, Tethys's +2.23 on the same angle, and Phobos's tidal quadratic,
which also re-centred its M0 (91.059 to 94.239) and n. Their cards still credited only "JPL SSD
satellite mean elements". They now read, for Mimas, "JPL SSD satellite mean elements, epoch 2000
Jan 1, with the orbital terms of its IAU W (NAIF pck00011), within 7.5 degrees of Horizons from
1950 to 2100"; Tethys and Phobos likewise (0.3 and 1.3). build.ts requires any moon carrying such
terms to name the kernel. Control: the full ETL with the old card fails with "Phobos's orbit
carries terms taken from its IAU W, and its card ... credits only the table."

Tethys's half of the libration had no guard. Without its term it strays 2.09 degrees from Horizons
over 1950-2100 against 0.28 with it, under the general 3-degree ceiling, and its card rewrote
itself as "within 2.1"; no unit test loads bodies.json. Tethys now has its own track ceiling of
0.5 degrees. Control: the full ETL without Tethys's orbitFromW fails with "Tethys's mean elements
put it up to 2.09 degrees from Horizons ... (at most 0.5 expected)".

The lock ceiling's comment said Mimas's 10.15 degrees was "physical libration, which W carries and
Horizons shows as 5 to 9 degrees". Neither holds: Mimas's measured physical libration is 0.84
degrees (Tajeddine et al. 2014), W carries no such term, and Horizons, on the same W against its
integrated orbit, runs from -2.7 to +12.7 degrees over 1950-2100 (the review's scan every 20
days). The drawn face's 2.5 to 10.15 is the IAU's W and JPL's mean longitude disagreeing by about
6.3 degrees, W turning 6.0e-5 degrees a day faster than the row's n (381.9945550 against
381.9944948, 3.3 degrees over the span), and 2e = 2.3 degrees of eccentricity. The ceiling itself
is unchanged.

The baseline ETL from the cache passes and changes bodies.json on those three cards only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 21:50:21 +02:00
co-authored by Claude Opus 5.5
parent 48fd6fd0e5
commit 4cd08ee324
3 changed files with 24 additions and 8 deletions
+3 -3
View File
@@ -707,7 +707,7 @@
"raDeg": 317.671, "raDeg": 317.671,
"decDeg": 52.893 "decDeg": 52.893
}, },
"orbitSource": "JPL SSD satellite mean elements, epoch 1950 Jan 1, within 1.3 degrees of Horizons from 1950 to 2100", "orbitSource": "JPL SSD satellite mean elements, epoch 1950 Jan 1, with the orbital terms of its IAU W (NAIF pck00011), within 1.3 degrees of Horizons from 1950 to 2100",
"parentBodyId": "mars", "parentBodyId": "mars",
"rotationPeriodHours": 7.653844882637157, "rotationPeriodHours": 7.653844882637157,
"rotationalElements": { "rotationalElements": {
@@ -1184,7 +1184,7 @@
"raDeg": 40.589, "raDeg": 40.589,
"decDeg": 83.536 "decDeg": 83.536
}, },
"orbitSource": "JPL SSD satellite mean elements, epoch 2000 Jan 1, within 7.5 degrees of Horizons from 1950 to 2100", "orbitSource": "JPL SSD satellite mean elements, epoch 2000 Jan 1, with the orbital terms of its IAU W (NAIF pck00011), within 7.5 degrees of Horizons from 1950 to 2100",
"parentBodyId": "saturn", "parentBodyId": "saturn",
"rotationPeriodHours": 22.618127008672275, "rotationPeriodHours": 22.618127008672275,
"rotationalElements": { "rotationalElements": {
@@ -1300,7 +1300,7 @@
"raDeg": 40.578, "raDeg": 40.578,
"decDeg": 83.537 "decDeg": 83.537
}, },
"orbitSource": "JPL SSD satellite mean elements, epoch 2000 Jan 1, within 0.3 degrees of Horizons from 1950 to 2100", "orbitSource": "JPL SSD satellite mean elements, epoch 2000 Jan 1, with the orbital terms of its IAU W (NAIF pck00011), within 0.3 degrees of Horizons from 1950 to 2100",
"parentBodyId": "saturn", "parentBodyId": "saturn",
"rotationPeriodHours": 45.30726088829954, "rotationPeriodHours": 45.30726088829954,
"rotationalElements": { "rotationalElements": {
+18 -3
View File
@@ -181,9 +181,13 @@ const MOON_OFFSET_CEILINGS_DEG: Record<string, number> = { hyperion: 21, iapetus
* `orbitFromW` in `fetchSolarSystem.ts`), but not the rest of what Horizons integrates. * `orbitFromW` in `fetchSolarSystem.ts`), but not the rest of what Horizons integrates.
* - Ceres, 7.12 (1953): the SBDB's elements are osculating, exact at 2026 Jun 9 and drifting * - Ceres, 7.12 (1953): the SBDB's elements are osculating, exact at 2026 Jun 9 and drifting
* either side; 1.9 by 2050, 5.3 by 2100, and 39 at 1600 on Horizons' own figures. * either side; 1.9 by 2050, 5.3 by 2100, and 39 at 1600 on Horizons' own figures.
*
* And one is held tighter than the rest: Tethys, 0.28, which takes the other half of that
* libration, 2.23 degrees, from its W. Without it Tethys strays 2.09 degrees, under the general
* ceiling, and its card would quietly restate itself as "within 2.1".
*/ */
const MAX_TRACK_OFFSET_DEG = 3; const MAX_TRACK_OFFSET_DEG = 3;
const TRACK_OFFSET_CEILINGS_DEG: Record<string, number> = { hyperion: 23, nereid: 12, iapetus: 11, mimas: 8, ceres: 8 }; const TRACK_OFFSET_CEILINGS_DEG: Record<string, number> = { hyperion: 23, nereid: 12, iapetus: 11, mimas: 8, ceres: 8, tethys: 0.5 };
/** /**
* The bodies the IAU WGCCRE 2015 report gives no rotational elements for: Hyperion tumbles, and * The bodies the IAU WGCCRE 2015 report gives no rotational elements for: Hyperion tumbles, and
@@ -222,8 +226,13 @@ const MAX_OBLIQUITY_OFFSET_DEG = 0.1;
* sampled every 135 days from 1950 to 2100, where both the tables and the IAU's elements hold. * sampled every 135 days from 1950 to 2100, where both the tables and the IAU's elements hold.
* *
* Measured on this catalogue: at most 6.70 degrees (the Moon, whose longitude swings 6.3 either * Measured on this catalogue: at most 6.70 degrees (the Moon, whose longitude swings 6.3 either
* way with its eccentricity; Horizons has the same). Three need their own: Mimas 10.15, whose * way with its eccentricity; Horizons has the same). Three need their own. Mimas 10.15: its drawn
* physical libration W carries and Horizons shows as 5 to 9 degrees at its true place; Iapetus * face runs from 2.5 to 10.15 degrees, about 6.3 off on average because the IAU's W and JPL's mean
* longitude disagree, drifting 3.3 over the span because W turns 6.0e-5 degrees a day faster than
* the row's n, and swung 2.3 either way (2e) by its eccentricity. None of that is Mimas: its
* measured physical libration is 0.84 degrees (Tajeddine et al. 2014, Science 346, 322), and W
* carries none; Horizons, on the same W against its integrated orbit, runs from -2.7 to 12.7
* degrees over 1950-2100 with the 71-year S5 term the orbit here cancels. Iapetus
* 18.33, whose row sits 9.4 degrees behind Horizons; and Proteus 8.18, whose W turns 6.3e-7 of * 18.33, whose row sits 9.4 degrees behind Horizons; and Proteus 8.18, whose W turns 6.3e-7 of
* its rate slower than its orbit, a drift of 74 degrees by AD 3000. What this catches is an orbit * its rate slower than its orbit, a drift of 74 degrees by AD 3000. What this catches is an orbit
* and a W that go round at different rates: the tidal acceleration W carried and the orbit did not * and a W that go round at different rates: the tidal acceleration W carried and the orbit did not
@@ -283,6 +292,12 @@ function validateBodies(bodies: BodyRecord[], horizonsOrbits: Map<string, Orbita
(track !== undefined) === !body.orbitSource.startsWith('JPL approximate mean elements (Standish)'), (track !== undefined) === !body.orbitSource.startsWith('JPL approximate mean elements (Standish)'),
`${body.name}'s orbit, "${body.orbitSource}", ${track ? 'names its own span' : 'names no span it holds over'}.` `${body.name}'s orbit, "${body.orbitSource}", ${track ? 'names its own span' : 'names no span it holds over'}.`
); );
// JPL's satellite table carries no periodic terms: a moon's are from its IAU W, and its card
// names the kernel they come from as well as the table.
assertCondition(
!body.parentBodyId || !body.rates.meanAnomalyTerms || body.orbitSource.includes('NAIF pck00011'),
`${body.name}'s orbit carries terms taken from its IAU W, and its card, "${body.orbitSource}", credits only the table.`
);
if (track) { if (track) {
const worst = Math.max(...track.map((point) => offsetFromTrackDeg(body, point))); const worst = Math.max(...track.map((point) => offsetFromTrackDeg(body, point)));
const trackCeiling = TRACK_OFFSET_CEILINGS_DEG[body.id] ?? MAX_TRACK_OFFSET_DEG; const trackCeiling = TRACK_OFFSET_CEILINGS_DEG[body.id] ?? MAX_TRACK_OFFSET_DEG;
+3 -2
View File
@@ -221,8 +221,9 @@ export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizo
// Standish's fit states its own span, 3000 BC to AD 3000. The moons' table and the SBDB state // Standish's fit states its own span, 3000 BC to AD 3000. The moons' table and the SBDB state
// none, and hold for far less: each card says how far its orbit stays from Horizons over the // none, and hold for far less: each card says how far its orbit stays from Horizons over the
// span it was measured, where the clock reaches AD 1 to AD 3000. // span it was measured, where the clock reaches AD 1 to AD 3000. An orbit that took terms from
let orbitSource = mean.orbitSource; // its IAU W says so first: they move Mimas by up to 44.85 degrees, and are none of JPL's table.
let orbitSource = fromW ? `${mean.orbitSource}, with the orbital terms of its IAU W (NAIF pck00011)` : mean.orbitSource;
if (parentName || smallBody) { if (parentName || smallBody) {
const stepDays = spec.trackStepDays ?? 2; const stepDays = spec.trackStepDays ?? 2;
const track = await fetchHorizonsTrack(spec.horizonsCommand, spec.center, stepDays, `horizons-track-${spec.id}-${stepDays}d.txt`); const track = await fetchHorizonsTrack(spec.horizonsCommand, spec.center, stepDays, `horizons-track-${spec.id}-${stepDays}d.txt`);