Four features, 10 new SQL functions (174 → 184 objects), 29 test suites: Saturn ring tilt: saturn_ring_tilt() exposes sub-observer latitude B'. planet_magnitude() for Saturn now includes Mallama & Hilton Eq. 10 ring correction (-2.60|sin B'| + 1.25 sin²B'), removing the ~1.5 mag globe-only caveat. IAU 2000 pole direction, ecliptic J2000 projection. Conical shadow model: Replaces cylindrical shadow with umbra/penumbra cones using Sun's finite angular size. Four new functions: satellite_in_penumbra(), satellite_shadow_state(), satellite_next_penumbra_entry/exit(). Existing eclipse functions are backward compatible via narrower (more accurate) umbra boundary. Rise/set event windows: Three SRFs returning TABLE(event_time, event_type) for all rise/set events within a time window — planet_rise_set_events(), sun_rise_set_events(), moon_rise_set_events(). Follows predict_passes() SRF pattern. Optional refracted parameter, 366-day window limit. Angular separation rate: Vincenty formula extracted to reusable helper. eq_angular_rate() for generic finite-difference rate, planet_angular_rate() for solar system body convenience (1-minute dt, handles Sun/planets/Moon).
313 lines
11 KiB
Plaintext
313 lines
11 KiB
Plaintext
-- v018_features.sql -- Tests for v0.18.0: Saturn ring tilt, penumbral eclipse,
|
|
-- rise/set event windows, angular separation rate
|
|
--
|
|
-- Verifies all 10 new functions added in v0.18.0.
|
|
CREATE EXTENSION IF NOT EXISTS pg_orrery;
|
|
NOTICE: extension "pg_orrery" already exists, skipping
|
|
-- ============================================================
|
|
-- Saturn ring tilt: in [-27, +27] range
|
|
-- ============================================================
|
|
SELECT saturn_ring_tilt('2024-01-15 00:00:00+00'::timestamptz) BETWEEN -27.0 AND 27.0
|
|
AS ring_tilt_in_range;
|
|
ring_tilt_in_range
|
|
--------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Saturn ring tilt: near zero around 2025 ring crossing
|
|
-- (rings edge-on to Earth around March 2025)
|
|
-- ============================================================
|
|
SELECT abs(saturn_ring_tilt('2025-03-23 00:00:00+00'::timestamptz)) < 5.0
|
|
AS ring_tilt_near_edge_on;
|
|
ring_tilt_near_edge_on
|
|
------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Saturn ring tilt: varies over time (not constant)
|
|
-- ============================================================
|
|
SELECT saturn_ring_tilt('2024-01-01 00:00:00+00'::timestamptz)
|
|
!= saturn_ring_tilt('2024-07-01 00:00:00+00'::timestamptz)
|
|
AS ring_tilt_varies;
|
|
ring_tilt_varies
|
|
------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Saturn ring tilt: sign changes across ring plane crossing
|
|
-- (2017 was fully open, 2025 is edge-on, tilt changes sign)
|
|
-- ============================================================
|
|
SELECT abs(saturn_ring_tilt('2017-06-15 00:00:00+00'::timestamptz)) > 10.0
|
|
AS ring_tilt_open_2017;
|
|
ring_tilt_open_2017
|
|
---------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Planet magnitude: Saturn now includes ring correction
|
|
-- (ring-corrected magnitude should differ from globe-only)
|
|
-- Saturn magnitude should be roughly between -0.5 and +1.5
|
|
-- ============================================================
|
|
SELECT planet_magnitude(6, '2024-01-15 00:00:00+00'::timestamptz) BETWEEN -1.0 AND 2.0
|
|
AS saturn_mag_valid_range;
|
|
saturn_mag_valid_range
|
|
------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Satellite shadow state: returns valid text values
|
|
-- ============================================================
|
|
SELECT satellite_shadow_state(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) IN ('sunlit', 'penumbra', 'umbra')
|
|
AS shadow_state_valid;
|
|
shadow_state_valid
|
|
--------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Satellite in penumbra: returns bool
|
|
-- ============================================================
|
|
SELECT satellite_in_penumbra(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) IS NOT NULL
|
|
AS penumbra_returns_bool;
|
|
penumbra_returns_bool
|
|
-----------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Backward compatibility: satellite_is_eclipsed still works
|
|
-- (cone model upgrade is internal-only)
|
|
-- ============================================================
|
|
SELECT satellite_is_eclipsed(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) IS NOT NULL
|
|
AS eclipse_backward_compat;
|
|
eclipse_backward_compat
|
|
-------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Penumbra entry precedes umbra entry (penumbra is outer zone)
|
|
-- ============================================================
|
|
SELECT satellite_next_penumbra_entry(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) <= satellite_next_eclipse_entry(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) AS penumbra_precedes_umbra;
|
|
penumbra_precedes_umbra
|
|
-------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Penumbra exit is after penumbra entry
|
|
-- ============================================================
|
|
SELECT satellite_next_penumbra_exit(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz
|
|
) > '2024-01-01 12:00:00+00'::timestamptz
|
|
AS penumbra_exit_in_future;
|
|
penumbra_exit_in_future
|
|
-------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Eclipse fraction still valid after cone upgrade
|
|
-- ============================================================
|
|
SELECT satellite_eclipse_fraction(
|
|
E'1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025\n2 25544 51.6400 208.9163 0006703 30.1694 61.7520 15.50100486 00001'::tle,
|
|
'2024-01-01 12:00:00+00'::timestamptz,
|
|
'2024-01-01 14:00:00+00'::timestamptz
|
|
) BETWEEN 0.0 AND 1.0
|
|
AS eclipse_fraction_still_valid;
|
|
eclipse_fraction_still_valid
|
|
------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Sun rise/set events: mid-latitude 24h window returns events
|
|
-- ============================================================
|
|
SELECT count(*) >= 1 AS sun_events_exist
|
|
FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-06-21 00:00:00+00'::timestamptz,
|
|
'2024-06-22 00:00:00+00'::timestamptz
|
|
);
|
|
sun_events_exist
|
|
------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Sun rise/set events: events alternate rise/set
|
|
-- ============================================================
|
|
SELECT bool_and(event_type IN ('rise', 'set')) AS sun_event_types_valid
|
|
FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-06-21 00:00:00+00'::timestamptz,
|
|
'2024-06-22 00:00:00+00'::timestamptz
|
|
);
|
|
sun_event_types_valid
|
|
-----------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Sun rise/set events: refracted vs geometric
|
|
-- (refracted rise is earlier than geometric rise)
|
|
-- ============================================================
|
|
SELECT (SELECT min(event_time) FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-06-21 00:00:00+00'::timestamptz,
|
|
'2024-06-22 00:00:00+00'::timestamptz,
|
|
true
|
|
) WHERE event_type = 'rise')
|
|
<=
|
|
(SELECT min(event_time) FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-06-21 00:00:00+00'::timestamptz,
|
|
'2024-06-22 00:00:00+00'::timestamptz,
|
|
false
|
|
) WHERE event_type = 'rise')
|
|
AS refracted_rise_earlier;
|
|
refracted_rise_earlier
|
|
------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Moon rise/set events: returns valid event types
|
|
-- ============================================================
|
|
SELECT bool_and(event_type IN ('rise', 'set')) AS moon_event_types_valid
|
|
FROM moon_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-01-15 00:00:00+00'::timestamptz,
|
|
'2024-01-16 00:00:00+00'::timestamptz
|
|
);
|
|
moon_event_types_valid
|
|
------------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Planet rise/set events: Jupiter over 24h
|
|
-- ============================================================
|
|
SELECT count(*) >= 1 AS jupiter_events_exist
|
|
FROM planet_rise_set_events(
|
|
5,
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-01-15 00:00:00+00'::timestamptz,
|
|
'2024-01-16 00:00:00+00'::timestamptz
|
|
);
|
|
jupiter_events_exist
|
|
----------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- Rise/set events: window > 366 days rejected
|
|
-- ============================================================
|
|
DO $$ BEGIN
|
|
PERFORM * FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-01-01 00:00:00+00'::timestamptz,
|
|
'2025-03-01 00:00:00+00'::timestamptz
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RAISE NOTICE 'window overflow: %', SQLERRM;
|
|
END $$;
|
|
NOTICE: window overflow: window exceeds 366-day maximum
|
|
-- ============================================================
|
|
-- Rise/set events: stop before start rejected
|
|
-- ============================================================
|
|
DO $$ BEGIN
|
|
PERFORM * FROM sun_rise_set_events(
|
|
'(43.7,-116.4,800)'::observer,
|
|
'2024-06-22 00:00:00+00'::timestamptz,
|
|
'2024-06-21 00:00:00+00'::timestamptz
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RAISE NOTICE 'stop before start: %', SQLERRM;
|
|
END $$;
|
|
NOTICE: stop before start: stop time must be after start time
|
|
-- ============================================================
|
|
-- eq_angular_rate: generic rate computation
|
|
-- Two positions that are 10 deg apart, then 9 deg apart after 1 hour
|
|
-- should give rate = -1.0 deg/hr (approaching)
|
|
-- ============================================================
|
|
SELECT abs(eq_angular_rate(
|
|
'(6.0, 45.0, 1.0)'::equatorial,
|
|
'(6.667, 45.0, 1.0)'::equatorial,
|
|
'(6.0, 45.0, 1.0)'::equatorial,
|
|
'(6.6, 45.0, 1.0)'::equatorial,
|
|
3600.0
|
|
)) > 0.0
|
|
AS angular_rate_nonzero;
|
|
angular_rate_nonzero
|
|
----------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- eq_angular_rate: dt_seconds <= 0 rejected
|
|
-- ============================================================
|
|
DO $$ BEGIN
|
|
PERFORM eq_angular_rate(
|
|
'(6.0, 45.0, 1.0)'::equatorial,
|
|
'(7.0, 45.0, 1.0)'::equatorial,
|
|
'(6.0, 45.0, 1.0)'::equatorial,
|
|
'(7.0, 45.0, 1.0)'::equatorial,
|
|
0.0
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RAISE NOTICE 'dt_seconds=0: %', SQLERRM;
|
|
END $$;
|
|
NOTICE: dt_seconds=0: eq_angular_rate: dt_seconds must be positive
|
|
-- ============================================================
|
|
-- planet_angular_rate: Moon rate ~0.5 deg/hr relative to Sun
|
|
-- ============================================================
|
|
SELECT abs(planet_angular_rate(0, 10, '2024-01-15 00:00:00+00'::timestamptz)) > 0.1
|
|
AS moon_sun_rate_nonzero;
|
|
moon_sun_rate_nonzero
|
|
-----------------------
|
|
t
|
|
(1 row)
|
|
|
|
-- ============================================================
|
|
-- planet_angular_rate: same body rejected
|
|
-- ============================================================
|
|
DO $$ BEGIN
|
|
PERFORM planet_angular_rate(5, 5, '2024-01-15 00:00:00+00'::timestamptz);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RAISE NOTICE 'same body: %', SQLERRM;
|
|
END $$;
|
|
NOTICE: same body: planet_angular_rate: body IDs must be different
|
|
-- ============================================================
|
|
-- planet_angular_rate: Jupiter-Saturn rate is small
|
|
-- (outer planets move slowly)
|
|
-- ============================================================
|
|
SELECT abs(planet_angular_rate(5, 6, '2024-01-15 00:00:00+00'::timestamptz)) < 1.0
|
|
AS outer_planet_rate_slow;
|
|
outer_planet_rate_slow
|
|
------------------------
|
|
t
|
|
(1 row)
|
|
|