N-body internal ephemeris

Current R102 architecture for the unified application boundary, model selection, propagation, light-time, cache, fallback and compatibility surfaces.

R515 structural note: This page preserves feature/release contracts, but any flat-root Python filenames cited as implementation evidence are historical pre-convergence names. Current implementation ownership is canonical under src/kopr/; use the current package/API policy for imports and extension work.

Runtime selection behind the service boundary

Normal widgets and workflows do not call the engine directly. They cross compute_comet_ephemeris(), which delegates to the typed CometEphemerisService. The only permitted application call to engine.compute_application() is inside CometEphemerisService._compute_internal_point().

The application engine requests N-body when a readable de440s.bsp, SciPy solve_ivp, jplephem and a usable osculating epoch are available. Direct low-level APIs retain their explicit/default two_body compatibility contract.

widget / batch workflow
  → compute_comet_ephemeris()
  → CometEphemerisService
  → engine.compute_application()   # one allowlisted call
  → DE440s N-body
    → DE440s two-body fallback
      → legacy analytic fallback

R102 post-cutover architecture

R102 removed private WStack ephemeris wrappers and the production-only ephemeris_shadow_validation.py helper after the R101 global cutover. WStack imports shared designation and observer normalizers directly; astrometry seeds, preview, COMETTRK and stacking trajectories continue through the unified batch service.

The public WStack export normalize_comet_designation remains available as a direct reference to the shared implementation. Historical R96 shadow-comparison utilities live only in tests/ephemeris_shadow_validation_support.py.

Scientific non-regression: R102 changes no propagation, light-time, topocentric correction, frame conversion, force model, element selection or widget result contract.

Intentionally retained compatibility surfaces

  • koprfunc.CometObsInf() — thin adapter over the unified typed service;
  • koprclass.comet.FindElements();
  • alb3.finddt();
  • ephemeris_position.topocentric_engine_radec_icrs();
  • ephemeris_position.internal_comet_position().

The last four are not used by current KOPR production routes but remain available because third-party scripts may depend on them. A zero internal call graph alone is not sufficient evidence for deleting a public API.

Osculating-epoch state

The exact MPC element line, TT epoch, perihelion JD and stable SHA-256 identity are retained. Elliptic, parabolic and hyperbolic elements are converted analytically to heliocentric position and velocity at epoch; TT crosses to TDB before integration.

Near-parabolic osculating-state robustness

The physical N-body force model is unchanged, but osculating-state conversion is hardened very close to e = 1 on both the elliptical and hyperbolic sides. Kepler residuals/derivatives are evaluated in cancellation-safe forms; the hyperbolic branch uses a safeguarded monotonic Newton solve with a bracket.

PARABOLIC_ECCENTRICITY_TOLERANCE is not widened to hide numerical difficulty. If initialization still fails, Planner remains fail-closed: a failed N-body result is not published as a two-body substitute. Cache identity/policy is unchanged by this numerical robustness change.

Force model and frames

Internal dynamics use heliocentric ecliptic J2000. DE440s ICRF states are transformed to that frame. Perturbers are Mercury, Venus, Earth, Moon, Mars and the Jupiter, Saturn, Uranus and Neptune system barycentres. Cowell acceleration includes central solar gravity and direct/indirect heliocentric third-body terms.

DOP853 trajectory

The six-state system is integrated in relative time with DOP853, separate position/velocity absolute tolerances and dense output. Independent forward/backward trajectories are stored in a bounded session LRU.

Light-time geometry

Earth is fixed at reception time during iteration. The comet is evaluated at t − LT; final RA, Dec, heliocentric distance and geocentric distance share the converged emission time. Stellar aberration is not added.

Cache identity and provenance

Cache identity includes exact elements, epoch, kernel, perturbers, gravitational parameters and tolerances. Provenance records requested/used model, fallback chain/reason, trajectory cache hit/miss, integration direction/action, perturbers, light time and iteration count.

[KOPR ephemeris] requested=nbody; used=nbody; source=DE440s N-body (automatic); selection=automatic_runtime_available; trajectory_cache=miss; trajectory_action=integrated_forward

Status command

python3 check_nbody_status.py

The command reports session-level selection. Actual per-calculation provenance remains authoritative.

Current limits

  • No cometary A1/A2/A3.
  • No relativistic corrections.
  • No asteroid perturbers.
  • No universal guarantee against Horizons orbit solutions.

R255 Planner invocation boundary

The N-body kernel itself is unchanged. WPlanner now invokes it only after the legacy two-body phase has frozen accepted rows and exact epochs. Search candidates and rejected rows do not request N-body work. Final fallback to a non-N-body model is not permitted.

Related

Optional validation and service cutover · Algorithm summary · Finder provenance

Documented map physical-track contract

Finding-chart refinement reuses the shared Planner computation context/cache and authoritative N-body service. Missing epochs are deferred until Generate maps. Each final drawable segment is checked at 1/4, 1/2 and 3/4 of its time span against physical topocentric probes; the worst excess is inserted as an unannotated geometry vertex until the measured page-space error is ≤0.25 mm or bounded limits are reached.

Bounds: depth 8, 4096 epochs per operation, chunk 32. Two-body fallback is rejected. Source-reported real DE440s calibration measured a maximum final error of 0.229834 mm.