Skip to content

Positional astronomy and astrophysics (pinneapple_physics.astro)

An independent NumPy implementation of the apparent sky, validated against USNO NOVAS, JPL Horizons, the USNO almanac, NASA eclipse predictions and skyfield. It powers the Observatory app.

pip install "pinneapple[sky]"     # sgp4 + skyfield-data (bundles the public-domain JPL DE421 kernel)
from pinneapple_physics.astro import Observer, Time, apparent, rise_transit_set, moon_phase

here = Observer(-23.5505, -46.6333, 760)                  # latitude, longitude (east +), metres
t = Time.from_iso("2026-10-13T23:30:00Z")
p = apparent("saturn", t, here)
p.alt_apparent, p.az, p.ra, p.dec, p.distance_km, p.light_time_s, p.range_rate_km_s
rise_transit_set("moon", here, t.utc)                      # UTC Julian dates
moon_phase(t)["illuminated_fraction"]
Module What
timescales UTC, TAI (leap seconds), TT, TDB, UT1 (IERS table when available, else held / 0), ERA, GMST (IAU 2006), GAST
spk JPL SPK reader (DAF, segment types 2 and 3), no SPICE dependency
frames frame bias, IAU 2006 precession, IAU 1980 nutation (terms > 5 mas; < 0.02″ from IAU 2000A), WGS84, horizon, ecliptic, separations
astrometry apparent places: light time, solar deflection, relativistic aberration; refraction (Saemundsson), airmass (Kasten & Young), extinction; catalogue stars with proper motion and parallax
phenomena rise / transit / set, twilight, Moon phase and bright limb, magnitudes, oppositions / conjunctions / greatest elongations, phases, seasons, lunar and solar eclipses (with local circumstances), transits
satellites TLE parsing and CelesTrak fetch with cache, SGP4 → TEME → ITRS, look angles, Earth shadow, magnitudes, visible passes
stars Yale BSC5 (9,096 stars), constellation figures, T_eff from B−V, black-body bolometric correction, luminosity, radius, HR diagram, Planck spectra
orbits Kepler's equation, elements ↔ state, planet elements from DE421, light time and relativistic Doppler
nbody leapfrog, Yoshida-4, RK4, DOP853 on Sun + planets + Moon with energy / angular-momentum diagnostics
surrogate physics-informed orbit surrogate (Kepler + τ² × network, full N-body residual) with conformal bands, physics checks and a verdict
lensing the real sky lensed by a Schwarzschild black hole (geodesics from pinneapple_physics.blackhole.raytrace), Einstein radius, shadow size vs EHT
validation every accuracy check as data; run_all()

Accuracy

Check Reference Result
Apparent places, Sun and planets (36 cases) USNO NOVAS C 3.1 ≤ 0.41″ (≤ 0.13″ without Pluto)
Moon USNO NOVAS C 3.1 ≤ 0.022″
Sun, Mars, topocentric Moon JPL Horizons ≤ 0.065″
Topocentric alt/az, 216 random cases 1972–2049 skyfield ≤ 0.011″
Sunrise/sunset, phases, seasons USNO tables (minute) ≤ 25 s
Eclipses and transits NASA ≤ 9 s
ISS passes (69 events) independent pass finder ≤ 0.18 s
Yoshida-4, 2 years energy, angular momentum 1.4e-10, 3e-15

The reference values are in pinneapple_physics/astro/data/reference/ with their sources.

The orbit surrogate

from pinneapple_physics.astro.surrogate import train_orbit_pinn
rep = train_orbit_pinn("mars", jd_tdb=2461327.0, days=365, iters=800)   # ~30 s on one CPU core
rep["verdict"], rep["summary"]["max_angle_arcsec_test"], rep["checks"]

The network only learns the perturbation of the exact two-body solution, r = r_Kepler + s τ² g_θ(τ), so the initial position and velocity are hard constraints. Its loss is the residual of r'' = −μ r/|r|³ + Σ_j μ_j [(r_j − r)/|r_j − r|³ − r_j/|r_j|³] at collocation points (perturbers from the reference integration) plus a few anchor states. It is then scored on held-out integrator states: angular error, split-conformal coverage (pinneapple_analysis.uncertainty.conformal), the error in two-body energy and angular momentum relative to their perturbation-driven variation, the equation-of-motion residual and the gain over Kepler. Mars passes every check (0.09″ over a year); the Earth fails them, because of the Moon, and the verdict says so.

PINNs and machine learning in the observatory

Each model is shown with a trust card in the app (verdict, checks against an independent reference, "how this was computed, how much to trust it") and tested in tests/test_astro_ai.py.

Module Model Independent reference Result
decay PINN for drag decay of a LEO orbit, NRLMSIS 2.0 density (pymsis), Monte-Carlo input envelope RK integration; SGP4's own drag model from a TLE PINN within metres of the integrator over weeks; decay rate within 6 % of SGP4 for an ISS TLE (B = 0.005 m²/kg, F10.7 = 70)
smallbodies test-particle propagator (DE421 Sun + planets + Moon, solar 1PN term) from JPL SBDB elements JPL Horizons (Ceres), JPL close-approach table (Apophis 2029) Ceres 3.9 km after 4.2 yr; Apophis 2029-04-13: 38,356 km vs JPL 37,725 ± 697 km (3σ), 11 s
surrogate.train_orbit_pinn(SmallBody) per-body PINN: Kepler orbit + τ² network trained on the N-body residual (planets from DE421) the integrator above, held-out times Apophis, 1 year: 64 km max (0.11″ from the Sun) vs 16,835 km for Kepler alone, 88 % coverage of the 90 % band; trustworthy
neural_propagator one network for many NEOs: elements + time → deviation from Kepler (R/T/N frame) the full integrator on 150 unseen bodies median max error 53,326 km vs 61,896 km for Kepler: fails its gate (≥ 5× better than Kepler), not trustworthy; trust_report() says so and the app uses the per-body PINN instead
spaceweather Kp quantile network (residual on persistence), conformal intervals; aurora probability from the IGRF dipole and the NOAA oval rule observed Kp (GFZ) on held-out months; persistence 24 h: MAE 1.15 vs persistence 1.18, 84 % coverage of the 80 % interval; storm onsets mostly missed (verdict: use with caution)
stars_ml Gaussian-mixture clustering of the HR diagram; k-NN luminosity and spectral class BSC5 MK spectral types, 5-fold CV luminosity class 70 % (baseline 40 %), spectral class from B−V 79 % (baseline 25 %), cluster purity 71 %
conditions Open-Meteo ensemble → P(clear), cloud quantiles, transparency, seeing proxy; reliability calibration none yet (needs a forecast/observation history) labelled not verified
lensing.trace_thin_disc, disc_image, accretion_view thin disc (ISCO, Novikov-Thorne flux, Keplerian gas, Doppler beaming and gravitational redshift, g⁴ intensity) lensed in front of the real sky; exact null geodesics u'' + u = 3u² Schwarzschild closed forms: shadow edge at b = 3√3 GM/c², face-on g = √(1 − 3/r) both to 1 % in the tests