Carry every body's IAU rotational elements, read from NAIF's kernel of the 2015 report
bodies.json now holds, for 33 of the 38 bodies, the pole right ascension and declination and the prime meridian W of the IAU WGCCRE 2015 report (Archinal et al. 2018), with their rates and the periodic terms. They are read from NAIF's pck00011.tpc, which carries the report in a form a program can read, periodic terms and their angles included. Hyperion (chaotic), Nereid, Eris, Haumea and Makemake have no model in the report. The parser, src/app/shared/astro/rotational-elements.ts, sits beside the other source readers so the unit suite covers it. It reads data blocks only where \begindata stands alone on a line, as the kernel's own prose mentions the token mid-sentence. It reads the Fortran exponent (the Moon's -1.4D-12 d² term) and the degree-2 angles of the Mars system, where Phobos's tidal acceleration lives. NAIF numbers a small body 2 000 000 past its catalogue number, so Ceres is 2000001. Periodic terms under 0.01 degrees are left out. 0.01 degrees moves a point by 0.11 px on the largest body ever drawn (Jupiter at 641 px of radius). That drops 32 terms: - Mercury: 4 (0.0011 degrees and less) - the Moon: 8 of 13 (0.0072 and less) - Mars: 13 (0.00024 and less); its three 0.42-1.59 degree long-period terms stay - Phobos: 1 (0.0063) - Jupiter: 5 (0.0022 and less) - Europa: 1 (0.009) Kept, among others: Mimas's 44.85-degree libration, Triton's 32-degree precession, Miranda's 4.4 and Phobos's 1.14-degree libration. build.ts now checks the elements against Horizons on the real catalogue: - Every body but those five carries elements, and they do not. - The IAU day, 360 over W's rate, is within 1e-4 of Horizons' period. Measured: at most 1.8e-5 (Jupiter). Neptune gets a 0.01 ceiling: 0.89 per cent, because the report takes Karkoschka's 15.9663 h where Horizons keeps Voyager's 16.11. - The spin axis, the pole turned end for end where W runs backwards, is within 0.1 degrees of Horizons' obliquity. Measured: at most 0.058 (Venus, 177.358 against 177.3); Uranus 97.771, Pluto 119.610, Earth 23.435. Full npm run etl passes. Three mutants each fail it on the named check: - W's sign dropped: "Venus's IAU spin axis is 2.642 degrees". - Ceres looked up by catalogue number: "Body ceres has no IAU rotational elements". - W's rate read per century: "Mercury's IAU day ... 3.65e+4". Nothing is drawn from these yet. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@ import { SUN_STAR_ID } from '../../src/app/shared/models/star.model';
|
||||
import { fetchHorizonsBody } from './lib/horizons';
|
||||
import { MeanOrbit, parsePlanetMeanElements, parseSatelliteMeanElements, parseSmallBodyElements } from '../../src/app/shared/astro/mean-elements';
|
||||
import { fetchPlanetMeanElementsText, fetchSatelliteMeanElementsHtml, fetchSmallBodyAnswer } from './lib/mean-elements';
|
||||
import { MIN_PERIODIC_TERM_DEG, parsePckRotationalElements } from '../../src/app/shared/astro/rotational-elements';
|
||||
import { fetchPckText } from './lib/pck';
|
||||
import { dataPath, ensureDataDir } from './lib/paths';
|
||||
|
||||
const HOURS_PER_DAY = 24;
|
||||
@@ -123,15 +125,17 @@ export const FREELY_SPINNING_MOONS = new Set(BODY_SPECS.filter((spec) => spec.sp
|
||||
* Writes `bodies.json` for the major planets, the five dwarf planets, and every moon in JPL's
|
||||
* mean-element table more than 100 km in mean radius — Phoebe, at 106.6, the smallest: JPL's
|
||||
* mean orbital elements for where they go, or the SBDB's osculating ones where there are none,
|
||||
* and JPL Horizons for their size and spin. Horizons' osculating elements for the same date come
|
||||
* back alongside, for `build.ts` to check the mean ones against.
|
||||
* JPL Horizons for their size and spin, and the IAU's rotational elements for where their poles
|
||||
* point and which face is where. Horizons' osculating elements for the same date come back
|
||||
* alongside, for `build.ts` to check the mean ones against.
|
||||
*/
|
||||
export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizonsOrbits: Map<string, OrbitalElements> }> {
|
||||
console.log(`Fetching ${BODY_SPECS.length} solar-system bodies from JPL (mean elements, Horizons)...`);
|
||||
console.log(`Fetching ${BODY_SPECS.length} solar-system bodies from JPL (mean elements, Horizons, NAIF's PCK)...`);
|
||||
const bodies: BodyRecord[] = [];
|
||||
const horizonsOrbits = new Map<string, OrbitalElements>();
|
||||
const planetElements = await fetchPlanetMeanElementsText();
|
||||
const satelliteElements = await fetchSatelliteMeanElementsHtml();
|
||||
const pck = await fetchPckText();
|
||||
const gmById = new Map<string, number | undefined>();
|
||||
|
||||
for (const spec of BODY_SPECS) {
|
||||
@@ -183,6 +187,14 @@ export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizo
|
||||
if (rotationPeriodHours === undefined) {
|
||||
console.warn(` no rotation period found for ${spec.name}; it will not turn.`);
|
||||
}
|
||||
// NAIF numbers a small body 2 000 000 past its catalogue number: Ceres, "1;" to Horizons, is 2000001.
|
||||
const naifId = spec.horizonsCommand.endsWith(';') ? 2_000_000 + Number.parseInt(spec.horizonsCommand, 10) : Number(spec.horizonsCommand);
|
||||
const rotation = parsePckRotationalElements(pck, naifId);
|
||||
if (!rotation) {
|
||||
console.warn(` no IAU rotational elements for ${spec.name}; its pole and meridian are not known.`);
|
||||
} else if (rotation.skippedDeg.length > 0) {
|
||||
console.log(` ${spec.name}: ${rotation.skippedDeg.length} periodic terms under ${MIN_PERIODIC_TERM_DEG} degrees left out, the largest ${Math.max(...rotation.skippedDeg)}.`);
|
||||
}
|
||||
|
||||
bodies.push({
|
||||
id: spec.id,
|
||||
@@ -197,7 +209,8 @@ export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizo
|
||||
...(spec.parentBodyId ? { parentBodyId: spec.parentBodyId } : {}),
|
||||
...(parentGm !== undefined ? { massRatio: result.gmKm3PerS2! / parentGm } : {}),
|
||||
...(rotationPeriodHours !== undefined ? { rotationPeriodHours } : {}),
|
||||
...((result.obliquityDeg ?? spec.obliquityDeg) !== undefined ? { obliquityDeg: result.obliquityDeg ?? spec.obliquityDeg } : {})
|
||||
...((result.obliquityDeg ?? spec.obliquityDeg) !== undefined ? { obliquityDeg: result.obliquityDeg ?? spec.obliquityDeg } : {}),
|
||||
...(rotation ? { rotationalElements: rotation.elements } : {})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user