pg_orrery/test/expected/v016_features.out
Ryan Malloy 22b272fd0c Implement v0.17.0: solar elongation, planet phase, satellite eclipse, observing night quality, lunar libration
162 → 174 SQL objects, 27 → 28 test suites, 3 new C source files.

Features:
- solar_elongation(body_id, ts): Sun-Earth-Planet angle [0,180] degrees
- planet_phase(body_id, ts): illuminated disk fraction [0,1]
- satellite_is_eclipsed/next_eclipse_entry/exit/eclipse_fraction:
  cylindrical shadow model (Vallado §5.3) for Earth shadow prediction
- observing_night_quality(observer, ts): composite PL/pgSQL scoring
  based on astronomical darkness duration and Moon interference
- moon_libration_longitude/latitude/position_angle/libration/subsolar_longitude:
  optical libration from Meeus (1998) Ch. 53

Refactored magnitude_funcs.c to extract shared compute_planet_geometry()
used by magnitude, elongation, and phase — single VSOP87 evaluation per call.

All 28 regression suites pass. Zero compiler warnings.
2026-02-26 18:47:30 -07:00

244 lines
9.0 KiB
Plaintext

-- v016_features.sql -- Tests for v0.16.0: twilight, lunar phase, planet magnitude
--
-- Verifies twilight dawn/dusk, lunar phase calculations,
-- and planet apparent magnitude.
CREATE EXTENSION IF NOT EXISTS pg_orrery;
NOTICE: extension "pg_orrery" already exists, skipping
-- ============================================================
-- Twilight: ordering (astronomical < nautical < civil < sunrise)
-- Eagle, Idaho on the 2024 summer solstice
-- ============================================================
-- Dawn ordering: astronomical dawn < nautical dawn < civil dawn < sunrise
-- Use midnight MDT (07:00 UTC) so all "next" events land on the same morning
SELECT sun_astronomical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
< sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
AS astro_before_nautical;
astro_before_nautical
-----------------------
t
(1 row)
SELECT sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
< sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
AS nautical_before_civil;
nautical_before_civil
-----------------------
t
(1 row)
SELECT sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
< sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
AS civil_before_sunrise;
civil_before_sunrise
----------------------
t
(1 row)
-- Dusk ordering: sunset < civil dusk < nautical dusk < astronomical dusk
-- Noon MDT (18:00 UTC) ensures all dusk events are still ahead
SELECT sun_next_set('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
< sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
AS sunset_before_civil;
sunset_before_civil
---------------------
t
(1 row)
SELECT sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
< sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
AS civil_before_nautical;
civil_before_nautical
-----------------------
t
(1 row)
SELECT sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
< sun_astronomical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz)
AS nautical_before_astro;
nautical_before_astro
-----------------------
t
(1 row)
-- ============================================================
-- Twilight: civil dawn ~30 min before sunrise at mid-latitude
-- ============================================================
SELECT extract(epoch FROM
sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
- sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz)
) BETWEEN 1200 AND 3600
AS civil_dawn_reasonable_offset;
civil_dawn_reasonable_offset
------------------------------
t
(1 row)
-- ============================================================
-- Twilight: high latitude summer -- no astronomical darkness
-- At 60N in June, astronomical dusk should be NULL (never gets dark enough)
-- ============================================================
SELECT sun_astronomical_dusk('(60.0,25.0,0)'::observer, '2024-06-21 00:00:00+00'::timestamptz) IS NULL
AS no_astro_dark_60n_summer;
no_astro_dark_60n_summer
--------------------------
t
(1 row)
-- ============================================================
-- Lunar phase: known full moon (2024-01-25 ~17:54 UTC)
-- Phase angle should be near 180 deg, illumination near 1.0
-- ============================================================
SELECT round(moon_phase_angle('2024-01-25 18:00:00+00'::timestamptz)::numeric, 0)
BETWEEN 170 AND 190
AS full_moon_angle_near_180;
full_moon_angle_near_180
--------------------------
t
(1 row)
SELECT round(moon_illumination('2024-01-25 18:00:00+00'::timestamptz)::numeric, 2)
>= 0.95
AS full_moon_high_illumination;
full_moon_high_illumination
-----------------------------
t
(1 row)
SELECT moon_phase_name('2024-01-25 18:00:00+00'::timestamptz) = 'full_moon'
AS full_moon_named;
full_moon_named
-----------------
t
(1 row)
-- ============================================================
-- Lunar phase: known new moon (2024-01-11 ~11:57 UTC)
-- Phase angle should be near 0 or 360, illumination near 0
-- ============================================================
SELECT moon_illumination('2024-01-11 12:00:00+00'::timestamptz)
< 0.05
AS new_moon_low_illumination;
new_moon_low_illumination
---------------------------
t
(1 row)
SELECT moon_phase_name('2024-01-11 12:00:00+00'::timestamptz) = 'new_moon'
AS new_moon_named;
new_moon_named
----------------
t
(1 row)
-- ============================================================
-- Lunar phase: first quarter (2024-01-18 ~03:53 UTC)
-- Phase angle near 90, illumination near 0.5
-- ============================================================
SELECT round(moon_phase_angle('2024-01-18 04:00:00+00'::timestamptz)::numeric, 0)
BETWEEN 80 AND 100
AS first_quarter_angle_near_90;
first_quarter_angle_near_90
-----------------------------
t
(1 row)
SELECT moon_illumination('2024-01-18 04:00:00+00'::timestamptz)
BETWEEN 0.4 AND 0.6
AS first_quarter_half_illuminated;
first_quarter_half_illuminated
--------------------------------
t
(1 row)
SELECT moon_phase_name('2024-01-18 04:00:00+00'::timestamptz) = 'first_quarter'
AS first_quarter_named;
first_quarter_named
---------------------
t
(1 row)
-- ============================================================
-- Moon age: new moon has age near 0, full moon near 14.7
-- ============================================================
SELECT moon_age('2024-01-11 12:00:00+00'::timestamptz) < 2.0
AS new_moon_young;
new_moon_young
----------------
t
(1 row)
SELECT moon_age('2024-01-25 18:00:00+00'::timestamptz)
BETWEEN 12.0 AND 17.0
AS full_moon_age_midcycle;
full_moon_age_midcycle
------------------------
t
(1 row)
-- ============================================================
-- Illumination range: always [0, 1]
-- ============================================================
SELECT moon_illumination('2024-06-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
AND moon_illumination('2024-09-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
AND moon_illumination('2024-12-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0
AS illumination_always_valid;
illumination_always_valid
---------------------------
t
(1 row)
-- ============================================================
-- Planet magnitude: Jupiter should be bright (negative mag)
-- ============================================================
SELECT planet_magnitude(5, '2024-01-15 00:00:00+00'::timestamptz) < 0.0
AS jupiter_is_bright;
jupiter_is_bright
-------------------
t
(1 row)
-- ============================================================
-- Planet magnitude: Venus is the brightest planet
-- ============================================================
SELECT planet_magnitude(2, '2024-06-01 12:00:00+00'::timestamptz)
< planet_magnitude(4, '2024-06-01 12:00:00+00'::timestamptz)
AS venus_brighter_than_mars;
venus_brighter_than_mars
--------------------------
t
(1 row)
-- ============================================================
-- Planet magnitude: Neptune is faint (~+7-8)
-- ============================================================
SELECT planet_magnitude(8, '2024-01-15 00:00:00+00'::timestamptz) > 7.0
AS neptune_is_faint;
neptune_is_faint
------------------
t
(1 row)
-- ============================================================
-- Planet magnitude: all planets return finite values
-- ============================================================
SELECT bool_and(
planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL
AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) > -30
AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) < 30
) AS all_magnitudes_finite
FROM (VALUES (1),(2),(4),(5),(6),(7),(8)) AS t(body_id);
all_magnitudes_finite
-----------------------
t
(1 row)
-- ============================================================
-- Planet magnitude: error cases
-- ============================================================
DO $$ BEGIN PERFORM planet_magnitude(0, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=0(Sun): %', SQLERRM; END $$;
NOTICE: body_id=0(Sun): planet_magnitude: body_id 0 must be 1-8 (Mercury-Neptune)
DO $$ BEGIN PERFORM planet_magnitude(3, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=3(Earth): %', SQLERRM; END $$;
NOTICE: body_id=3(Earth): planet_magnitude: cannot compute for Earth from Earth
DO $$ BEGIN PERFORM planet_magnitude(9, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=9: %', SQLERRM; END $$;
NOTICE: body_id=9: planet_magnitude: body_id 9 must be 1-8 (Mercury-Neptune)