-- rise_set.sql -- Tests for v0.13.0: rise/set prediction functions -- -- Verifies solar system body rise/set predictions using the bisection -- algorithm adapted from satellite pass prediction. CREATE EXTENSION IF NOT EXISTS pg_orrery; NOTICE: extension "pg_orrery" already exists, skipping -- ============================================================ -- Test observer: Eagle, Idaho (~43.7N, ~116.4W, 800m) -- Mid-latitude location with normal rise/set behavior. -- ============================================================ -- Use a fixed epoch in northern hemisphere winter (Jan 15, 2024 midnight UTC) -- Sun should rise around ~15:30 UTC (8:30 AM MST) and set around ~00:30 UTC next day -- Sun rise/set (geometric) SELECT sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS sun_rises; sun_rises ----------- t (1 row) SELECT sun_next_set('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS sun_sets; sun_sets ---------- t (1 row) -- Sunrise should be within 24h of the epoch SELECT extract(epoch FROM sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) - '2024-01-15 00:00:00+00'::timestamptz) / 3600.0 BETWEEN 0 AND 24.0 AS sunrise_within_24h; sunrise_within_24h -------------------- t (1 row) -- Sunset should be within 24h of the epoch SELECT extract(epoch FROM sun_next_set('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) - '2024-01-15 00:00:00+00'::timestamptz) / 3600.0 BETWEEN 0 AND 24.0 AS sunset_within_24h; sunset_within_24h ------------------- t (1 row) -- ============================================================ -- Moon rise/set -- ============================================================ SELECT moon_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS moon_rises; moon_rises ------------ t (1 row) SELECT moon_next_set('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS moon_sets; moon_sets ----------- t (1 row) -- ============================================================ -- Planet rise/set (Jupiter -- typically visible in winter evening) -- ============================================================ SELECT planet_next_rise(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS jupiter_rises; jupiter_rises --------------- t (1 row) SELECT planet_next_set(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AS jupiter_sets; jupiter_sets -------------- t (1 row) -- ============================================================ -- Refracted vs geometric: refracted sunrise earlier than geometric -- ============================================================ SELECT sun_next_rise_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) < sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS refracted_sunrise_earlier; refracted_sunrise_earlier --------------------------- t (1 row) SELECT sun_next_set_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) > sun_next_set('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS refracted_sunset_later; refracted_sunset_later ------------------------ t (1 row) -- Refracted-geometric difference should be ~2-5 minutes (120-300 seconds) SELECT abs(extract(epoch FROM sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) - sun_next_rise_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz))) BETWEEN 60 AND 600 AS refraction_offset_reasonable; refraction_offset_reasonable ------------------------------ t (1 row) -- ============================================================ -- Consistency: rise_time of the NEXT rise should be ~24h later -- ============================================================ SELECT extract(epoch FROM sun_next_rise('(43.7,-116.4,800)'::observer, sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) + interval '1 minute') - sun_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz)) / 3600.0 BETWEEN 23.0 AND 25.0 AS next_rise_about_24h_later; next_rise_about_24h_later --------------------------- t (1 row) -- ============================================================ -- Circumpolar check: Sun from 70N in June (midnight sun) -- Sun should NOT set within 7 days -- ============================================================ SELECT sun_next_set('(70.0,25.0,0)'::observer, '2024-06-21 00:00:00+00'::timestamptz) IS NULL AS midnight_sun_no_set; midnight_sun_no_set --------------------- t (1 row) -- ============================================================ -- Never-rises check: Sun from 70N in December (polar night) -- Sun should NOT rise within 7 days -- ============================================================ SELECT sun_next_rise('(70.0,25.0,0)'::observer, '2024-12-21 00:00:00+00'::timestamptz) IS NULL AS polar_night_no_rise; polar_night_no_rise --------------------- t (1 row) -- ============================================================ -- Planet refracted rise/set (v0.14.0) -- ============================================================ -- Planet refracted rise should be earlier than geometric SELECT planet_next_rise_refracted(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) < planet_next_rise(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS planet_refracted_rise_earlier; planet_refracted_rise_earlier ------------------------------- t (1 row) -- Planet refracted set should be later than geometric SELECT planet_next_set_refracted(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) > planet_next_set(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS planet_refracted_set_later; planet_refracted_set_later ---------------------------- t (1 row) -- Planet refraction offset should be reasonable (30-300 seconds) SELECT abs(extract(epoch FROM planet_next_rise(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) - planet_next_rise_refracted(5, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz))) BETWEEN 30 AND 300 AS planet_refraction_offset_reasonable; planet_refraction_offset_reasonable ------------------------------------- t (1 row) -- ============================================================ -- Moon refracted rise/set (v0.14.0) -- ============================================================ -- Moon refracted rise should be earlier than geometric SELECT moon_next_rise_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) < moon_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS moon_refracted_rise_earlier; moon_refracted_rise_earlier ----------------------------- t (1 row) -- Moon refracted set should be later than geometric SELECT moon_next_set_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) > moon_next_set('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) AS moon_refracted_set_later; moon_refracted_set_later -------------------------- t (1 row) -- Moon refraction offset should be reasonable (60-600 seconds) SELECT abs(extract(epoch FROM moon_next_rise('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz) - moon_next_rise_refracted('(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz))) BETWEEN 60 AND 600 AS moon_refraction_offset_reasonable; moon_refraction_offset_reasonable ----------------------------------- t (1 row) -- ============================================================ -- Error cases -- ============================================================ -- Invalid body_id DO $$ BEGIN PERFORM planet_next_rise(0, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=0: %', SQLERRM; END $$; NOTICE: body_id=0: planet_next_rise: body_id 0 must be 1-8 (Mercury-Neptune) DO $$ BEGIN PERFORM planet_next_rise(3, '(43.7,-116.4,800)'::observer, '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): cannot observe Earth from Earth DO $$ BEGIN PERFORM planet_next_rise(9, '(43.7,-116.4,800)'::observer, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=9: %', SQLERRM; END $$; NOTICE: body_id=9: planet_next_rise: body_id 9 must be 1-8 (Mercury-Neptune)