pg_orrery/test/sql/de_ephemeris.sql
Ryan Malloy 3915d1784f Rename pg_orbit to pg_orrery
An existing product called PG Orbit (a mobile PostgreSQL client)
creates a naming conflict. pg_orrery — a database orrery built from
Keplerian parameters and SQL instead of brass gears.

Build system: control file, Makefile, Dockerfile, docker init script.
C source: GUC prefix, PG_FUNCTION_INFO_V1 symbol, header guards,
ereport prefixes, comments across ~30 files including vendored SGP4.
SQL: all 5 install/migration scripts, function name pg_orrery_ephemeris_info.
Tests: 9 SQL suites, 8 expected outputs, standalone DE reader test.
Documentation: CLAUDE.md, README.md, DESIGN.md, Starlight site infra,
36 MDX pages, OG renderer, logo SVG, docker-compose, agent threads.

All 13 regression suites pass. Docs site builds (37 pages).
2026-02-17 13:36:22 -07:00

129 lines
7.5 KiB
SQL

-- de_ephemeris regression tests
--
-- Tests the _de() function variants and VSOP87 fallback behavior.
-- Since DE ephemeris files are not available in CI, these tests
-- verify that fallback behavior is correct and produces identical
-- results to the VSOP87 variants.
\set boulder '''40.015N 105.270W 1655m'''::observer
-- ============================================================
-- Test 1: pg_orrery_ephemeris_info() returns VSOP87 when no DE file
-- The provider should be 'VSOP87' since no ephemeris_path is set.
-- ============================================================
SELECT 'eph_info_vsop87' AS test,
(pg_orrery_ephemeris_info()).provider AS provider;
-- ============================================================
-- Test 2: planet_heliocentric_de falls back to VSOP87
-- Should produce identical results to planet_heliocentric()
-- when DE is unavailable.
-- ============================================================
SELECT 'helio_fallback' AS test,
round(helio_x(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
round(helio_x(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS x_match,
round(helio_y(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
round(helio_y(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS y_match,
round(helio_z(planet_heliocentric(3, '2024-06-21 12:00:00+00'))::numeric, 8) =
round(helio_z(planet_heliocentric_de(3, '2024-06-21 12:00:00+00'))::numeric, 8) AS z_match;
-- ============================================================
-- Test 3: planet_heliocentric_de Sun at origin
-- ============================================================
SELECT 'sun_origin_de' AS test,
round(helio_x(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS x,
round(helio_y(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS y,
round(helio_z(planet_heliocentric_de(0, '2024-06-21 12:00:00+00'))::numeric, 10) AS z;
-- ============================================================
-- Test 4: planet_observe_de falls back to VSOP87
-- Elevation and azimuth should match planet_observe().
-- ============================================================
SELECT 'observe_fallback' AS test,
round(topo_azimuth(planet_observe(5, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) =
round(topo_azimuth(planet_observe_de(5, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) AS az_match,
round(topo_elevation(planet_observe(5, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) =
round(topo_elevation(planet_observe_de(5, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 5: sun_observe_de falls back to VSOP87
-- ============================================================
SELECT 'sun_fallback' AS test,
round(topo_azimuth(sun_observe(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) =
round(topo_azimuth(sun_observe_de(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) AS az_match,
round(topo_elevation(sun_observe(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) =
round(topo_elevation(sun_observe_de(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 6: moon_observe_de falls back to ELP2000-82B
-- ============================================================
SELECT 'moon_fallback' AS test,
round(topo_azimuth(moon_observe(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) =
round(topo_azimuth(moon_observe_de(:boulder, '2024-06-21 18:00:00+00'))::numeric, 4) AS az_match,
round(topo_range(moon_observe(:boulder, '2024-06-21 18:00:00+00'))::numeric, 0) =
round(topo_range(moon_observe_de(:boulder, '2024-06-21 18:00:00+00'))::numeric, 0) AS range_match;
-- ============================================================
-- Test 7: lambert_c3_de falls back to VSOP87
-- Earth-Mars 2024 window should match lambert_c3().
-- ============================================================
SELECT 'lambert_fallback' AS test,
round(lambert_c3(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')::numeric, 2) =
round(lambert_c3_de(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')::numeric, 2) AS c3_match;
-- ============================================================
-- Test 8: lambert_transfer_de falls back to VSOP87
-- Should produce identical departure C3.
-- ============================================================
SELECT 'transfer_fallback' AS test,
round((lambert_transfer(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')).c3_departure::numeric, 2) =
round((lambert_transfer_de(3, 4, '2024-05-01 00:00:00+00', '2025-02-01 00:00:00+00')).c3_departure::numeric, 2) AS c3_match;
-- ============================================================
-- Test 9: galilean_observe_de falls back to VSOP87
-- ============================================================
SELECT 'galilean_fallback' AS test,
round(topo_elevation(galilean_observe(0, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) =
round(topo_elevation(galilean_observe_de(0, :boulder, '2024-03-15 03:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 10: saturn_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'saturn_moon_fallback' AS test,
round(topo_elevation(saturn_moon_observe(5, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) =
round(topo_elevation(saturn_moon_observe_de(5, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 11: uranus_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'uranus_moon_fallback' AS test,
round(topo_elevation(uranus_moon_observe(3, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) =
round(topo_elevation(uranus_moon_observe_de(3, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 12: mars_moon_observe_de falls back to VSOP87
-- ============================================================
SELECT 'mars_moon_fallback' AS test,
round(topo_elevation(mars_moon_observe(0, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) =
round(topo_elevation(mars_moon_observe_de(0, :boulder, '2024-06-15 04:00:00+00'))::numeric, 4) AS el_match;
-- ============================================================
-- Test 13: All DE planet functions work (fallback mode)
-- Mercury through Neptune, all should return valid positions
-- matching their VSOP87 counterparts.
-- ============================================================
SELECT 'all_planets_de' AS test,
body_id,
round(helio_distance(planet_heliocentric_de(body_id, '2024-06-21 12:00:00+00'))::numeric, 2) AS dist_au
FROM generate_series(1, 8) AS body_id;
-- ============================================================
-- Test 14: Error handling - invalid body_id
-- ============================================================
SELECT 'invalid_body_de' AS test, planet_heliocentric_de(9, now());
-- ============================================================
-- Test 15: Error handling - cannot observe Earth from Earth
-- ============================================================
SELECT 'earth_error_de' AS test, planet_observe_de(3, :boulder, now());