Skip to content

Functions: Lagrange Points

Functions for computing Lagrange point equilibrium positions in the Circular Restricted Three-Body Problem (CR3BP). Lagrange points are the five positions where a small body can maintain a stable (or quasi-stable) position relative to two larger bodies. L1, L2, and L3 are collinear (unstable), while L4 and L5 form equilateral triangles with the two primaries (stable for mass ratios below the Routh critical value). All functions in this section are IMMUTABLE STRICT PARALLEL SAFE.


Heliocentric ecliptic J2000 position of a Sun-planet Lagrange point. The CR3BP quintic solver finds the equilibrium position in the co-rotating frame, which is then rotated into the inertial ecliptic frame using VSOP87 planetary positions.

lagrange_heliocentric(body_id int4, point_id int4, t timestamptz) → heliocentric
ParameterTypeDescription
body_idint4Planet identifier: 1=Mercury, 2=Venus, 3=Earth, 4=Mars, 5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune
point_idint4Lagrange point: 1=L1, 2=L2, 3=L3, 4=L4, 5=L5
ttimestamptzEvaluation time

A heliocentric position in AU (ecliptic J2000 frame).

-- Sun-Earth L1: SOHO lives here (~0.97 AU from Sun)
SELECT round(helio_distance(lagrange_heliocentric(3, 1, '2000-01-01 12:00:00+00'))::numeric, 2) AS sun_dist_au;
-- -> 0.97
-- All planets' L1 distances from the Sun
SELECT body_id,
round(helio_distance(lagrange_heliocentric(body_id, 1, '2000-01-01 12:00:00+00'))::numeric, 4) AS l1_dist_au
FROM generate_series(1, 8) AS body_id;

Observe a Sun-planet Lagrange point from a ground station. Computes the heliocentric Lagrange position, subtracts Earth’s geocentric position, and transforms to topocentric azimuth/elevation.

lagrange_observe(body_id int4, point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Where is the Sun-Earth L2 (JWST's home) from Greenwich?
SELECT round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el
FROM lagrange_observe(3, 2, '51.4769N 0.0005W 0m'::observer, now()) AS t;

Geocentric RA/Dec of a Sun-planet Lagrange point. Converts the heliocentric ecliptic position to geocentric equatorial coordinates, precessed to the date of observation.

lagrange_equatorial(body_id int4, point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Sun-Earth L2 sky position (near the anti-solar point)
SELECT round(eq_ra(lagrange_equatorial(3, 2, now()))::numeric, 4) AS ra_hours,
round(eq_dec(lagrange_equatorial(3, 2, now()))::numeric, 4) AS dec_deg;

Distance (AU) from a heliocentric position to a Sun-planet Lagrange point. Computes the Lagrange point position at the given time and returns the Euclidean distance.

lagrange_distance(body_id int4, point_id int4, pos heliocentric, t timestamptz) → float8
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
point_idint4Lagrange point: 1-5 (L1-L5)
posheliocentricHeliocentric position to measure from
ttimestamptzEvaluation time (determines the Lagrange point position)

Distance in AU from the given position to the Lagrange point.

-- Self-test: distance from Jupiter L4 to itself
SELECT round(lagrange_distance(
5, 4,
lagrange_heliocentric(5, 4, '2000-01-01 12:00:00+00'),
'2000-01-01 12:00:00+00'
)::numeric, 10) AS self_distance;
-- -> 0.0000000000

Distance (AU) from an asteroid or comet (specified by orbital_elements) to a Sun-planet Lagrange point. Propagates the small body’s orbit to the given time via Keplerian mechanics, then measures the distance to the computed Lagrange position.

lagrange_distance_oe(body_id int4, point_id int4, oe orbital_elements, t timestamptz) → float8
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
point_idint4Lagrange point: 1-5 (L1-L5)
oeorbital_elementsOrbital elements for the asteroid or comet
ttimestamptzEvaluation time

Distance in AU.

-- Check if (588) Achilles is near Jupiter's L4 (Trojan territory)
SELECT round(lagrange_distance_oe(
5, 4,
oe_from_mpc('00588 14.39 0.15 K249V 41.50128 169.10254 334.19917 13.04512 0.0760428 0.22963720 5.1763803 0 MPO752723 4285 88 1992-2024 0.49 M-v 30h MPCW 0000 (588) Achilles 20240913'),
'2024-06-21 12:00:00+00'
)::numeric, 4) AS dist_au;

Observe an Earth-Moon Lagrange point from a ground station. The Earth-Moon system is implied --- no body_id is needed. The Moon’s position is computed via ELP2000-82B.

lunar_lagrange_observe(point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Earth-Moon L1 from Boulder (Artemis Gateway territory)
SELECT round(topo_elevation(lunar_lagrange_observe(1, '40.0N 105.3W 1655m'::observer, now()))::numeric, 2) AS el_deg;

Geocentric RA/Dec of an Earth-Moon Lagrange point. The L1 point lies between Earth and Moon at roughly 84% of the Earth-Moon distance.

lunar_lagrange_equatorial(point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Earth-Moon L1 distance (~326,000 km from Earth)
SELECT round(eq_distance(lunar_lagrange_equatorial(1, '2000-01-01 12:00:00+00'))::numeric, 0) AS dist_km;

Observe a Jupiter-Galilean moon Lagrange point from a ground station. Uses L1.2 theory (Lieske 1998) for the Galilean moon position and VSOP87 for Jupiter’s heliocentric position.

galilean_lagrange_observe(body_id int4, point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Galilean moon: 0=Io, 1=Europa, 2=Ganymede, 3=Callisto
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Jupiter-Ganymede L3 from Greenwich
SELECT round(topo_elevation(galilean_lagrange_observe(2, 3, '51.4769N 0.0005W 0m'::observer, now()))::numeric, 2) AS el_deg;

Geocentric RA/Dec of a Jupiter-Galilean moon Lagrange point.

galilean_lagrange_equatorial(body_id int4, point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
body_idint4Galilean moon: 0=Io, 1=Europa, 2=Ganymede, 3=Callisto
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Jupiter-Io L4 sky position
SELECT round(eq_ra(galilean_lagrange_equatorial(0, 4, now()))::numeric, 4) AS ra_hours,
round(eq_dec(galilean_lagrange_equatorial(0, 4, now()))::numeric, 4) AS dec_deg;

Observe a Saturn moon Lagrange point from a ground station. Uses TASS17 theory (Vienne & Duriez 1995) for the moon position and VSOP87 for Saturn’s heliocentric position.

saturn_moon_lagrange_observe(body_id int4, point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Saturn moon: 0=Mimas, 1=Enceladus, 2=Tethys, 3=Dione, 4=Rhea, 5=Titan, 6=Iapetus, 7=Hyperion
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Saturn-Titan L1 from Boulder
SELECT round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el
FROM saturn_moon_lagrange_observe(5, 1, '40.0N 105.3W 1655m'::observer, now()) AS t;

Geocentric RA/Dec of a Saturn moon Lagrange point.

saturn_moon_lagrange_equatorial(body_id int4, point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
body_idint4Saturn moon: 0=Mimas, 1=Enceladus, 2=Tethys, 3=Dione, 4=Rhea, 5=Titan, 6=Iapetus, 7=Hyperion
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Saturn-Titan L1 sky position
SELECT round(eq_ra(saturn_moon_lagrange_equatorial(5, 1, now()))::numeric, 4) AS ra_hours;

Observe a Uranus moon Lagrange point from a ground station. Uses GUST86 theory (Laskar & Jacobson 1987) for the moon position and VSOP87 for Uranus’s heliocentric position.

uranus_moon_lagrange_observe(body_id int4, point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Uranus moon: 0=Miranda, 1=Ariel, 2=Umbriel, 3=Titania, 4=Oberon
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Uranus-Titania L2 from Greenwich
SELECT round(topo_elevation(uranus_moon_lagrange_observe(3, 2, '51.4769N 0.0005W 0m'::observer, now()))::numeric, 2) AS el_deg;

Geocentric RA/Dec of a Uranus moon Lagrange point.

uranus_moon_lagrange_equatorial(body_id int4, point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
body_idint4Uranus moon: 0=Miranda, 1=Ariel, 2=Umbriel, 3=Titania, 4=Oberon
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Uranus-Oberon L4 sky position
SELECT round(eq_ra(uranus_moon_lagrange_equatorial(4, 4, now()))::numeric, 4) AS ra_hours,
round(eq_dec(uranus_moon_lagrange_equatorial(4, 4, now()))::numeric, 4) AS dec_deg;

Observe a Mars moon Lagrange point from a ground station. Uses MarsSat theory (Jacobson 2014) for the moon position and VSOP87 for Mars’s heliocentric position.

mars_moon_lagrange_observe(body_id int4, point_id int4, obs observer, t timestamptz) → topocentric
ParameterTypeDescription
body_idint4Mars moon: 0=Phobos, 1=Deimos
point_idint4Lagrange point: 1-5 (L1-L5)
obsobserverObserver location on Earth
ttimestamptzObservation time

A topocentric with azimuth, elevation (degrees), range (km), and range rate (km/s).

-- Mars-Phobos L1 from Boulder
SELECT round(topo_azimuth(t)::numeric, 2) AS az,
round(topo_elevation(t)::numeric, 2) AS el
FROM mars_moon_lagrange_observe(0, 1, '40.0N 105.3W 1655m'::observer, now()) AS t;

Geocentric RA/Dec of a Mars moon Lagrange point.

mars_moon_lagrange_equatorial(body_id int4, point_id int4, t timestamptz) → equatorial
ParameterTypeDescription
body_idint4Mars moon: 0=Phobos, 1=Deimos
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

An equatorial with RA (hours), Dec (degrees), and distance (km).

-- Mars-Deimos L5 sky position
SELECT round(eq_ra(mars_moon_lagrange_equatorial(1, 5, now()))::numeric, 4) AS ra_hours,
round(eq_dec(mars_moon_lagrange_equatorial(1, 5, now()))::numeric, 4) AS dec_deg;

Hill sphere radius (AU) for a Sun-planet system. The Hill sphere is the region where a planet’s gravity dominates over the Sun’s --- objects beyond this radius are more strongly influenced by the Sun. Computed as r_H = a * (m_p / (3 * m_sun))^(1/3), where a is the instantaneous Sun-planet distance from VSOP87.

hill_radius(body_id int4, t timestamptz) → float8
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
ttimestamptzEvaluation time

Hill sphere radius in AU.

-- Jupiter's Hill sphere (~0.35 AU)
SELECT round(hill_radius(5, '2000-01-01 12:00:00+00')::numeric, 3) AS jupiter_hill_au;
-- All planets
SELECT body_id,
round(hill_radius(body_id, '2000-01-01 12:00:00+00')::numeric, 4) AS hill_au
FROM generate_series(1, 8) AS body_id;

Hill sphere radius (AU) for the Earth-Moon system. Much smaller than planetary Hill spheres since the Moon is far less massive relative to Earth than planets are relative to the Sun.

hill_radius_lunar(t timestamptz) → float8
ParameterTypeDescription
ttimestamptzEvaluation time

Hill sphere radius in AU.

SELECT hill_radius_lunar('2000-01-01 12:00:00+00') AS lunar_hill_au;

Approximate libration zone radius (AU) around a Sun-planet Lagrange point. For L4/L5, this is related to the tadpole/horseshoe orbit domain where Trojan asteroids can remain trapped. For collinear points (L1/L2/L3), it is the linearized stability boundary.

lagrange_zone_radius(body_id int4, point_id int4, t timestamptz) → float8
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)
point_idint4Lagrange point: 1-5 (L1-L5)
ttimestamptzEvaluation time

Zone radius in AU.

-- Jupiter L4 libration zone (Trojan swarm extent)
SELECT round(lagrange_zone_radius(5, 4, '2000-01-01 12:00:00+00')::numeric, 4) AS zone_au;

CR3BP mass parameter mu = M_planet / (M_sun + M_planet). A diagnostic function useful for verifying the CR3BP solver or understanding the relative gravitational influence of a planet in its system.

lagrange_mass_ratio(body_id int4) → float8
ParameterTypeDescription
body_idint4Planet identifier: 1-8 (Mercury-Neptune)

Dimensionless mass ratio (small positive number; Jupiter is ~0.001, Earth is ~0.000003).

SELECT lagrange_mass_ratio(5) AS jupiter_mu,
lagrange_mass_ratio(3) AS earth_mu;

Human-readable name for a Lagrange point ID. A simple lookup that converts integer IDs to their standard labels.

lagrange_point_name(point_id int4) → text
ParameterTypeDescription
point_idint4Lagrange point: 1-5

Text label: 'L1', 'L2', 'L3', 'L4', or 'L5'.

SELECT lagrange_point_name(1) AS name;
-- -> 'L1'
-- Use in a query for readable output
SELECT lagrange_point_name(p) AS point,
round(helio_distance(lagrange_heliocentric(3, p, now()))::numeric, 4) AS sun_dist_au
FROM generate_series(1, 5) AS p;