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.
244 lines
9.0 KiB
Plaintext
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)
|