Add positive-gamma clamp in L1/L2/L3 Newton-Raphson iterations to prevent divergence on extreme mass ratios. Add missing CREATE EXTENSION, tighter L1/L2 precision checks (4 decimal places), lagrange_distance_oe test with Ceres, L1-Earth-L2 ordering verification, and DE fallback tests for planetary moon Lagrange functions.
267 lines
9.8 KiB
SQL
267 lines
9.8 KiB
SQL
-- v020_features: Lagrange point support
|
|
-- Tests Sun-planet, Earth-Moon, planetary moon Lagrange points,
|
|
-- Hill radius, zone radius, DE fallback, and input validation.
|
|
|
|
CREATE EXTENSION IF NOT EXISTS pg_orrery;
|
|
|
|
-- Reference observer: Greenwich, UK
|
|
\set obs '''(51.4769,-0.0005,0)'''
|
|
|
|
-- Reference time: J2000 epoch (2000-01-01 12:00:00 UTC)
|
|
\set t '''2000-01-01 12:00:00+00'''
|
|
|
|
-- ============================================================
|
|
-- Sun-Earth L1/L2: should be ~0.01 AU from Earth (~1.5 million km)
|
|
-- SOHO is at L1, JWST at L2.
|
|
-- ============================================================
|
|
|
|
-- L1 heliocentric: should be close to Earth's heliocentric (~1 AU from Sun)
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(3, 1, :t ::timestamptz))::numeric, 2) AS sun_dist_au;
|
|
|
|
-- L2 heliocentric: also ~1 AU from Sun, slightly further than L1
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(3, 2, :t ::timestamptz))::numeric, 2) AS sun_dist_au;
|
|
|
|
-- L1 between Sun and Earth (closer to Sun than L2)
|
|
SELECT
|
|
helio_distance(lagrange_heliocentric(3, 1, :t ::timestamptz))
|
|
<
|
|
helio_distance(lagrange_heliocentric(3, 2, :t ::timestamptz))
|
|
AS l1_closer_than_l2;
|
|
|
|
-- ============================================================
|
|
-- Sun-Jupiter L4/L5: ~60 degrees from Jupiter, ~5.2 AU from Sun
|
|
-- These are the Trojan asteroid zones.
|
|
-- ============================================================
|
|
|
|
-- L4/L5 should be ~5.2 AU from Sun
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(5, 4, :t ::timestamptz))::numeric, 1) AS l4_sun_dist;
|
|
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(5, 5, :t ::timestamptz))::numeric, 1) AS l5_sun_dist;
|
|
|
|
-- L4 and L5 equidistant from Sun (within 0.001 AU)
|
|
SELECT
|
|
abs(
|
|
helio_distance(lagrange_heliocentric(5, 4, :t ::timestamptz))
|
|
-
|
|
helio_distance(lagrange_heliocentric(5, 5, :t ::timestamptz))
|
|
) < 0.001 AS l4_l5_equidistant;
|
|
|
|
-- ============================================================
|
|
-- Earth-Moon L1: ~326,000 km from Earth
|
|
-- ============================================================
|
|
|
|
-- lunar_lagrange_equatorial returns distance in km
|
|
SELECT
|
|
round(eq_distance(lunar_lagrange_equatorial(1, :t ::timestamptz))::numeric, -3)
|
|
BETWEEN 300000 AND 360000 AS em_l1_in_range;
|
|
|
|
-- ============================================================
|
|
-- lagrange_observe returns valid az/el
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
topo_elevation(lagrange_observe(3, 2, :obs ::observer, :t ::timestamptz))
|
|
BETWEEN -90 AND 90 AS valid_elevation;
|
|
|
|
-- lagrange_equatorial returns valid RA/Dec
|
|
SELECT
|
|
eq_ra(lagrange_equatorial(3, 1, :t ::timestamptz)) BETWEEN 0 AND 24 AS valid_ra,
|
|
eq_dec(lagrange_equatorial(3, 1, :t ::timestamptz)) BETWEEN -90 AND 90 AS valid_dec;
|
|
|
|
-- ============================================================
|
|
-- lagrange_distance self-test: L-point distance to itself ≈ 0
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
round(lagrange_distance(
|
|
5, 4,
|
|
lagrange_heliocentric(5, 4, :t ::timestamptz),
|
|
:t ::timestamptz
|
|
)::numeric, 10) AS self_distance;
|
|
|
|
-- ============================================================
|
|
-- Hill radius
|
|
-- ============================================================
|
|
|
|
-- Jupiter Hill radius ~0.35 AU
|
|
SELECT
|
|
round(hill_radius(5, :t ::timestamptz)::numeric, 2)
|
|
BETWEEN 0.30 AND 0.40 AS jupiter_hill_ok;
|
|
|
|
-- Earth Hill radius ~0.01 AU
|
|
SELECT
|
|
round(hill_radius(3, :t ::timestamptz)::numeric, 3)
|
|
BETWEEN 0.008 AND 0.012 AS earth_hill_ok;
|
|
|
|
-- Lunar Hill radius (much smaller, AU)
|
|
SELECT
|
|
hill_radius_lunar(:t ::timestamptz) > 0 AS lunar_hill_positive;
|
|
|
|
-- ============================================================
|
|
-- Zone radius
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
lagrange_zone_radius(5, 4, :t ::timestamptz) > 0 AS jup_l4_zone_positive;
|
|
|
|
SELECT
|
|
lagrange_zone_radius(5, 1, :t ::timestamptz) > 0 AS jup_l1_zone_positive;
|
|
|
|
-- ============================================================
|
|
-- Convenience functions
|
|
-- ============================================================
|
|
|
|
-- lagrange_mass_ratio returns small positive number
|
|
SELECT
|
|
lagrange_mass_ratio(5) > 0 AND lagrange_mass_ratio(5) < 0.01 AS jupiter_mu_ok;
|
|
|
|
SELECT
|
|
lagrange_mass_ratio(3) > 0 AND lagrange_mass_ratio(3) < 0.001 AS earth_mu_ok;
|
|
|
|
-- lagrange_point_name
|
|
SELECT lagrange_point_name(1) AS l1_name;
|
|
SELECT lagrange_point_name(5) AS l5_name;
|
|
|
|
-- ============================================================
|
|
-- All planets produce valid results
|
|
-- ============================================================
|
|
|
|
SELECT body_id,
|
|
round(helio_distance(lagrange_heliocentric(body_id, 1, :t ::timestamptz))::numeric, 2) AS sun_dist_au
|
|
FROM generate_series(1, 8) AS body_id
|
|
ORDER BY body_id;
|
|
|
|
-- ============================================================
|
|
-- Planetary moon Lagrange points
|
|
-- ============================================================
|
|
|
|
-- Galilean: Io L4 (body=0, point=4)
|
|
SELECT
|
|
eq_ra(galilean_lagrange_equatorial(0, 4, :t ::timestamptz)) BETWEEN 0 AND 24
|
|
AS io_l4_valid_ra;
|
|
|
|
-- Saturn: Titan L1 (body=5, point=1)
|
|
SELECT
|
|
eq_ra(saturn_moon_lagrange_equatorial(5, 1, :t ::timestamptz)) BETWEEN 0 AND 24
|
|
AS titan_l1_valid_ra;
|
|
|
|
-- Uranus: Titania L2 (body=3, point=2)
|
|
SELECT
|
|
eq_ra(uranus_moon_lagrange_equatorial(3, 2, :t ::timestamptz)) BETWEEN 0 AND 24
|
|
AS titania_l2_valid_ra;
|
|
|
|
-- Mars: Phobos L5 (body=0, point=5)
|
|
SELECT
|
|
eq_ra(mars_moon_lagrange_equatorial(0, 5, :t ::timestamptz)) BETWEEN 0 AND 24
|
|
AS phobos_l5_valid_ra;
|
|
|
|
-- Galilean observe returns valid topocentric
|
|
SELECT
|
|
topo_elevation(galilean_lagrange_observe(2, 3, :obs ::observer, :t ::timestamptz))
|
|
BETWEEN -90 AND 90 AS ganymede_l3_valid_el;
|
|
|
|
-- ============================================================
|
|
-- DE fallback (no DE loaded, should produce same results as VSOP87)
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric_de(3, 1, :t ::timestamptz))::numeric, 4) AS de_l1_dist;
|
|
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(3, 1, :t ::timestamptz))::numeric, 4) AS vsop_l1_dist;
|
|
|
|
-- DE hill_radius fallback
|
|
SELECT
|
|
round(hill_radius_de(5, :t ::timestamptz)::numeric, 4) =
|
|
round(hill_radius(5, :t ::timestamptz)::numeric, 4)
|
|
AS hill_de_matches_vsop;
|
|
|
|
-- ============================================================
|
|
-- Tighter L1/L2 precision (4 decimal places)
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(3, 1, :t ::timestamptz))::numeric, 4) AS earth_l1_dist;
|
|
|
|
SELECT
|
|
round(helio_distance(lagrange_heliocentric(3, 2, :t ::timestamptz))::numeric, 4) AS earth_l2_dist;
|
|
|
|
-- L1 and L2 bracket Earth's heliocentric distance
|
|
SELECT
|
|
helio_distance(lagrange_heliocentric(3, 1, :t ::timestamptz))
|
|
<
|
|
helio_distance(planet_heliocentric(3, :t ::timestamptz))
|
|
AND
|
|
helio_distance(planet_heliocentric(3, :t ::timestamptz))
|
|
<
|
|
helio_distance(lagrange_heliocentric(3, 2, :t ::timestamptz))
|
|
AS l1_earth_l2_ordering;
|
|
|
|
-- ============================================================
|
|
-- lagrange_distance_oe — Ceres distance from Jupiter L4
|
|
-- Ceres orbits at ~2.77 AU, Jupiter L4 at ~5.2 AU, so distance > 2 AU
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
round(lagrange_distance_oe(
|
|
5, 4,
|
|
oe_from_mpc('00001 3.33 0.12 K24AM 60.07966 73.42937 80.26860 10.58664 0.0789126 0.21406048 2.7660961 0 MPO838504 8738 115 1801-2024 0.65 M-v 30k MPCLINUX 0000 (1) Ceres 20240825'),
|
|
:t ::timestamptz
|
|
)::numeric, 2) AS ceres_jup_l4_dist;
|
|
|
|
-- Distance should be positive and > 2 AU (main belt vs Trojan zone)
|
|
SELECT
|
|
lagrange_distance_oe(
|
|
5, 4,
|
|
oe_from_mpc('00001 3.33 0.12 K24AM 60.07966 73.42937 80.26860 10.58664 0.0789126 0.21406048 2.7660961 0 MPO838504 8738 115 1801-2024 0.65 M-v 30k MPCLINUX 0000 (1) Ceres 20240825'),
|
|
:t ::timestamptz
|
|
) > 2.0 AS ceres_far_from_trojan;
|
|
|
|
-- ============================================================
|
|
-- DE fallback for planetary moon Lagrange functions
|
|
-- ============================================================
|
|
|
|
SELECT
|
|
round(eq_ra(galilean_lagrange_equatorial_de(0, 4, :t ::timestamptz))::numeric, 4) =
|
|
round(eq_ra(galilean_lagrange_equatorial(0, 4, :t ::timestamptz))::numeric, 4)
|
|
AS galilean_de_fallback_matches;
|
|
|
|
SELECT
|
|
round(eq_ra(saturn_moon_lagrange_equatorial_de(5, 1, :t ::timestamptz))::numeric, 4) =
|
|
round(eq_ra(saturn_moon_lagrange_equatorial(5, 1, :t ::timestamptz))::numeric, 4)
|
|
AS saturn_de_fallback_matches;
|
|
|
|
-- ============================================================
|
|
-- Input validation
|
|
-- ============================================================
|
|
|
|
-- Bad body_id
|
|
SELECT lagrange_heliocentric(0, 1, :t ::timestamptz); -- Sun not valid
|
|
SELECT lagrange_heliocentric(9, 1, :t ::timestamptz); -- body 9 invalid
|
|
|
|
-- Bad point_id
|
|
SELECT lagrange_heliocentric(3, 0, :t ::timestamptz); -- point 0 invalid
|
|
SELECT lagrange_heliocentric(3, 6, :t ::timestamptz); -- point 6 invalid
|
|
|
|
-- Bad lunar point_id
|
|
SELECT lunar_lagrange_equatorial(0, :t ::timestamptz); -- point 0 invalid
|
|
SELECT lunar_lagrange_equatorial(6, :t ::timestamptz); -- point 6 invalid
|
|
|
|
-- Bad planetary moon body_id
|
|
SELECT galilean_lagrange_equatorial(4, 1, :t ::timestamptz); -- Galilean 4 invalid
|
|
SELECT saturn_moon_lagrange_equatorial(8, 1, :t ::timestamptz); -- Saturn 8 invalid
|
|
SELECT uranus_moon_lagrange_equatorial(5, 1, :t ::timestamptz); -- Uranus 5 invalid
|
|
SELECT mars_moon_lagrange_equatorial(2, 1, :t ::timestamptz); -- Mars 2 invalid
|
|
|
|
-- lagrange_mass_ratio bad body
|
|
SELECT lagrange_mass_ratio(0);
|
|
SELECT lagrange_mass_ratio(9);
|
|
|
|
-- lagrange_point_name bad id
|
|
SELECT lagrange_point_name(0);
|
|
SELECT lagrange_point_name(6);
|