Engine baseline: Moira 6.1.0
Last verified: 2026-08-13
Primary implementation: moira/planets.py, moira/corrections.py,
moira/coordinates.py, moira/precession.py, and moira/obliquity.py
The planetary reduction pipeline transforms a state read from an admitted JPL SPK kernel into a declared observer-relative position. The caller chooses the physical mode, output centre, output frame, and optional topocentric observer. Those choices are part of the result’s meaning; they are not presentation options.
The public low-level entry point is planet_at(...). Moira.planet_at(...)
binds that computation to the facade’s active reader. The website-facing REST
alias is POST /v1/pipeline/positions/planet.
planet_at(...) accepts a Julian Day in UT1. The engine converts it to the
reader-bound TT coordinate used to evaluate the active kernel. Historical
Delta-T translation is bound to the content-identified DE/LE product rather
than inferred from a filename.
The ordinary planetary path accepts admitted DE430, DE440, and DE441 readers. Coverage is determined by the loaded kernel, not by this document.
The public body name does not always imply a planet-center SPK target. Moira returns the endpoint owned by the active reader’s admitted NAIF route:
| Public body | DE441 route endpoint | Comparison identity |
|---|---|---|
| Sun | 10 |
Sun center |
| Moon | 301 |
Moon center |
| Mercury | 199 |
Mercury center |
| Venus | 299 |
Venus center |
| Mars | 4 |
Mars system barycenter |
| Jupiter | 5 |
Jupiter system barycenter |
| Saturn | 6 |
Saturn system barycenter |
| Uranus | 7 |
Uranus system barycenter |
| Neptune | 8 |
Neptune system barycenter |
| Pluto | 9 |
Pluto system barycenter |
External comparisons must use that exact endpoint. Comparing a Moira system barycenter with a Horizons planet center tests two different physical targets and cannot establish kernel or reduction accuracy.
planet_at(...) remains the public validation and routing wrapper. Its internal
reduction path receives one opaque workspace that binds the reader, resolved TT
epoch, apparent/geometric mode, nutation policy, derived Earth state, and the
workspace-owned vector cache. Injected contexts are accepted only when those
provenance fields match the active call. Reader-bound reusable contexts are
bounded per reader and per thread, so a result computed for one explicit TT
epoch or policy cannot poison another call.
This is internal correctness hardening. No REST route, request model, response
model, or final planetary-position meaning is added or removed. The five
legacy underscored Python workspace hooks remain accepted for the current
compatibility cycle, are validated against the opaque workspace contract, and
emit DeprecationWarning when used.
With the default apparent=True, center="geocentric", and
frame="ecliptic" policy, the reduction proceeds through these named stages:
nutation=True.frame="cartesian".planet_reduction_breakdown_at(...) exposes the named stage list, enabled
flags, per-stage longitude deltas, stage longitudes, and total applied
longitude delta. It is an inspectability product over the same engine
functions; the REST pipeline route serializes this result rather than
re-implementing astronomy in the HTTP layer.
apparent=False omits reception light time, gravitational deflection, and
annual aberration while retaining the declared of-date frame transform.aberration=False and grav_deflection=False independently disable those
corrections only on an apparent observer-centred path.nutation=False selects the mean equator/ecliptic of date and mean
obliquity. It is an output-frame policy in both apparent and geometric
modes.center="barycentric" returns a Solar-System-barycentric position.
Observer-centred aberration and deflection do not apply, while declared
frame rotations still do.The default result is PlanetData. Its longitude and latitude describe the
selected centre, physical mode, observer policy, and ecliptic-of-date frame.
frame="cartesian" returns CartesianPosition in the corresponding
equatorial-of-date frame.
PlanetData.speed remains the astrometric geocentric longitude rate even when
the selected output centre is barycentric. Consumers must not reinterpret that
field as a derivative of every selectable output surface.
Small-body names route through their admitted asteroid or comet readers. Their installed ephemeris availability is a different fact from catalog identity or asteroid-family membership; a metadata-only manifest does not make a body position-capable.
The astronomy validation report records the external-reference suites for frame construction, apparent planetary positions, wide-range vectors, and topocentric positions. The public Mars J2000 reduction trace is a versioned historical receipt, not a claim that one example validates every body, epoch, kernel, observer, or policy combination.
The current major-body Horizons contracts were refreshed on 2026-08-13:
| Product | Matched contract | Enforced envelope | Recorded maximum |
|---|---|---|---|
| Apparent geocentric | Same route endpoint; reader-resolved ephemeris JD sent as discrete Horizons TLIST with TIME_TYPE=TT |
0.35"; 0.1 km |
0.277781" (Saturn barycenter); 0.066846 km (Mercury center) |
| Geometric ICRF vector | Same route endpoint; same numeric ephemeris JD sent as discrete TLIST with TIME_TYPE=TDB; VEC_CORR=NONE |
0.001"; 0.01 km |
0.000021829" (Moon center); 0.002937 km (Mercury center) |
The apparent angular result is a cross-reduction-model envelope, not a direct measure of DE441 interpolation error: Moira uses IAU 2006 precession and IAU 2000A nutation, while Horizons apparent quantity 2 uses its documented EOP-corrected IAU 1976/1980 true-equator/equinox-of-date output. The geometric suite isolates target/vector geometry; because both services receive the same numeric ephemeris JD, it does not independently validate TT-to-TDB conversion. See the Horizons manual, the Horizons API documentation, and the astronomy validation report for the full qualification.
Relevant executable surfaces include:
tests/integration/test_horizons_planet_apparent.pytests/integration/test_horizons_planet_vectors_wide.pytests/integration/test_horizons_sky.pytests/unit/test_planet_position_switches.pytests/server/test_server_website_routes.pySee also: