pg_orrery/test/expected/moon_observe.out
Ryan Malloy ad7209d0db Phase 3: Planetary moons and Jupiter radio burst prediction
Add observation functions for 19 planetary moons across four systems:
- Galilean moons (Io, Europa, Ganymede, Callisto) via clean-room L1.2 theory
- Saturn moons (Mimas through Hyperion) via TASS 1.7
- Uranus moons (Miranda through Oberon) via GUST86
- Mars moons (Phobos, Deimos) via MarsSat

Add Jupiter decametric radio burst prediction for Radio JOVE operators:
- io_phase_angle() — Io orbital phase from superior conjunction
- jupiter_cml() — System III Central Meridian Longitude with light-time correction
- jupiter_burst_probability() — Carr et al. (1983) source regions A, B, C, D

L1.2 Galilean theory is a clean-room MIT implementation from the published
IMCCE FORTRAN coefficients. All other ephemeris libraries are MIT-licensed
extractions from Stellarium with static caching removed for PARALLEL SAFE.

All 10 regression tests pass. Extension .so grows from 2.4MB to 2.5MB.
2026-02-16 01:55:13 -07:00

227 lines
9.9 KiB
Plaintext

-- moon_observe regression tests
--
-- Tests planetary moon observation (Galilean, Saturn, Uranus, Mars)
-- and Jupiter decametric radio burst prediction functions.
-- Reference distances from JPL/NASA fact sheets.
\set boulder '''40.015N 105.270W 1655m'''::observer
-- ============================================================
-- Test 1: Galilean moon observation - all four from Boulder
-- Io, Europa, Ganymede, Callisto should return valid topocentric.
-- ============================================================
SELECT 'galilean_io' AS test,
round(topo_azimuth(galilean_observe(0, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(galilean_observe(0, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-------------+--------+--------
galilean_io | 270 | 24
(1 row)
SELECT 'galilean_europa' AS test,
round(topo_azimuth(galilean_observe(1, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(galilean_observe(1, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-----------------+--------+--------
galilean_europa | 270 | 24
(1 row)
SELECT 'galilean_ganymede' AS test,
round(topo_azimuth(galilean_observe(2, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(galilean_observe(2, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-------------------+--------+--------
galilean_ganymede | 270 | 24
(1 row)
SELECT 'galilean_callisto' AS test,
round(topo_azimuth(galilean_observe(3, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(galilean_observe(3, :boulder,
'2024-03-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-------------------+--------+--------
galilean_callisto | 270 | 24
(1 row)
-- ============================================================
-- Test 2: Galilean moons should be very close to Jupiter
-- All four should have ranges within ~0.05 AU of Jupiter's range.
-- Jupiter is ~4-6 AU from Earth; moons orbit within 0.013 AU.
-- ============================================================
SELECT 'galilean_near_jupiter' AS test,
round(topo_range(planet_observe(5, :boulder,
'2024-03-15 03:00:00+00'))::numeric, -4) AS jupiter_km,
round(topo_range(galilean_observe(0, :boulder,
'2024-03-15 03:00:00+00'))::numeric, -4) AS io_km,
round(topo_range(galilean_observe(3, :boulder,
'2024-03-15 03:00:00+00'))::numeric, -4) AS callisto_km;
test | jupiter_km | io_km | callisto_km
-----------------------+------------+-----------+-------------
galilean_near_jupiter | 837420000 | 837000000 | 837600000
(1 row)
-- ============================================================
-- Test 3: Saturn moon observation - Titan (body_id=5)
-- Titan is Saturn's largest moon, should be near Saturn.
-- ============================================================
SELECT 'saturn_titan' AS test,
round(topo_azimuth(saturn_moon_observe(5, :boulder,
'2024-06-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(saturn_moon_observe(5, :boulder,
'2024-06-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
--------------+--------+--------
saturn_titan | 50 | -45
(1 row)
-- ============================================================
-- Test 4: Saturn moons - Mimas through Iapetus all return results
-- ============================================================
SELECT 'saturn_moons' AS test,
body_id,
round(topo_range(saturn_moon_observe(body_id, :boulder,
'2024-06-15 03:00:00+00'))::numeric, -4) AS range_km
FROM generate_series(0, 7) AS body_id;
test | body_id | range_km
--------------+---------+------------
saturn_moons | 0 | 1427920000
saturn_moons | 1 | 1427670000
saturn_moons | 2 | 1427910000
saturn_moons | 3 | 1427680000
saturn_moons | 4 | 1427420000
saturn_moons | 5 | 1426520000
saturn_moons | 6 | 1428150000
saturn_moons | 7 | 1429140000
(8 rows)
-- ============================================================
-- Test 5: Uranus moon observation - Titania (body_id=3)
-- ============================================================
SELECT 'uranus_titania' AS test,
round(topo_azimuth(uranus_moon_observe(3, :boulder,
'2024-06-15 03:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(uranus_moon_observe(3, :boulder,
'2024-06-15 03:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
----------------+--------+--------
uranus_titania | 329 | -25
(1 row)
-- ============================================================
-- Test 6: All Uranus moons return valid results
-- ============================================================
SELECT 'uranus_moons' AS test,
body_id,
round(topo_range(uranus_moon_observe(body_id, :boulder,
'2024-06-15 03:00:00+00'))::numeric, -4) AS range_km
FROM generate_series(0, 4) AS body_id;
test | body_id | range_km
--------------+---------+------------
uranus_moons | 0 | 3061280000
uranus_moons | 1 | 3061360000
uranus_moons | 2 | 3061200000
uranus_moons | 3 | 3061310000
uranus_moons | 4 | 3061520000
(5 rows)
-- ============================================================
-- Test 7: Mars moons - Phobos and Deimos
-- ============================================================
SELECT 'mars_phobos' AS test,
round(topo_azimuth(mars_moon_observe(0, :boulder,
'2024-01-15 06:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(mars_moon_observe(0, :boulder,
'2024-01-15 06:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-------------+--------+--------
mars_phobos | 1 | -74
(1 row)
SELECT 'mars_deimos' AS test,
round(topo_azimuth(mars_moon_observe(1, :boulder,
'2024-01-15 06:00:00+00'))::numeric, 0) AS az_deg,
round(topo_elevation(mars_moon_observe(1, :boulder,
'2024-01-15 06:00:00+00'))::numeric, 0) AS el_deg;
test | az_deg | el_deg
-------------+--------+--------
mars_deimos | 1 | -74
(1 row)
-- ============================================================
-- Test 8: Io phase angle - should be [0, 360)
-- ============================================================
SELECT 'io_phase' AS test,
round(io_phase_angle('2024-03-15 03:00:00+00')::numeric, 1) AS phase_deg,
io_phase_angle('2024-03-15 03:00:00+00') >= 0.0
AND io_phase_angle('2024-03-15 03:00:00+00') < 360.0 AS in_range;
test | phase_deg | in_range
----------+-----------+----------
io_phase | 179.7 | t
(1 row)
-- ============================================================
-- Test 9: Jupiter CML (System III) - should be [0, 360)
-- ============================================================
SELECT 'jupiter_cml' AS test,
round(jupiter_cml(:boulder, '2024-03-15 03:00:00+00')::numeric, 1) AS cml_deg,
jupiter_cml(:boulder, '2024-03-15 03:00:00+00') >= 0.0
AND jupiter_cml(:boulder, '2024-03-15 03:00:00+00') < 360.0 AS in_range;
test | cml_deg | in_range
-------------+---------+----------
jupiter_cml | 306.0 | t
(1 row)
-- ============================================================
-- Test 10: Jupiter burst probability - known high probability zone
-- Source A: CML 200-260, Io phase 195-265 => p=0.8
-- ============================================================
SELECT 'burst_source_a' AS test,
jupiter_burst_probability(230.0, 230.0) AS p_source_a;
test | p_source_a
----------------+------------
burst_source_a | 0.8
(1 row)
-- ============================================================
-- Test 11: Jupiter burst probability - known zones
-- ============================================================
SELECT 'burst_zones' AS test,
jupiter_burst_probability(90.0, 150.0) AS p_source_b,
jupiter_burst_probability(240.0, 350.0) AS p_source_c,
jupiter_burst_probability(100.0, 25.0) AS p_source_d,
jupiter_burst_probability(0.0, 130.0) AS p_quiet;
test | p_source_b | p_source_c | p_source_d | p_quiet
-------------+------------+------------+------------+---------
burst_zones | 0.6 | 0.5 | 0.15 | 0
(1 row)
-- ============================================================
-- Test 12: Io phase changes over time (Io orbits in ~1.77 days)
-- Two times 12 hours apart should show significant phase change.
-- ============================================================
SELECT 'io_phase_changes' AS test,
round(io_phase_angle('2024-03-15 00:00:00+00')::numeric, 1) AS phase_0h,
round(io_phase_angle('2024-03-15 12:00:00+00')::numeric, 1) AS phase_12h,
abs(io_phase_angle('2024-03-15 00:00:00+00') -
io_phase_angle('2024-03-15 12:00:00+00')) > 10.0 AS changed;
test | phase_0h | phase_12h | changed
------------------+----------+-----------+---------
io_phase_changes | 205.0 | 103.4 | t
(1 row)
-- ============================================================
-- Test 13: Error handling - invalid Galilean moon body_id
-- ============================================================
SELECT 'invalid_galilean' AS test, galilean_observe(4, :boulder, now());
ERROR: galilean_observe: body_id 4 must be 0-3 (Io, Europa, Ganymede, Callisto)
-- ============================================================
-- Test 14: Error handling - invalid Saturn moon body_id
-- ============================================================
SELECT 'invalid_saturn' AS test, saturn_moon_observe(8, :boulder, now());
ERROR: saturn_moon_observe: body_id 8 must be 0-7 (Mimas-Hyperion)