pg_orrery/docs/public/llms-full.txt
Ryan Malloy b79f6948c6 Add llms.txt and llms-full.txt for LLM-friendly project reference
Per the llms.txt spec — standard index at /llms.txt linking all 44 doc
pages, plus /llms-full.txt with all 82 function signatures, 8 types,
body ID tables, operators, and runnable query patterns inline (~18KB).
2026-02-21 11:33:13 -07:00

488 lines
18 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# pg_orrery — Complete LLM Reference
> Celestial mechanics types and functions for PostgreSQL. Native C extension (v0.8.0) with 82 SQL functions, 8 custom types + 1 composite, GiST/SP-GiST indexing. All functions PARALLEL SAFE.
- Source: https://git.supported.systems/warehack.ing/pg_orrery
- Docs: https://pg-orrery.warehack.ing
- Requires: PostgreSQL 1418
- Install: `CREATE EXTENSION pg_orrery;`
## Types
All base types are fixed-size, STORAGE = plain, ALIGNMENT = double. No TOAST.
### tle (112 bytes)
Parsed Two-Line Element set for SGP4/SDP4 propagation. Text I/O is the standard two-line format.
```sql
-- Input: standard TLE two-line format (line1 + newline + line2)
SELECT '1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9002
2 25544 51.6400 208.5000 0007417 35.0000 325.0000 15.49000000000000'::tle;
-- Or from separate line columns:
SELECT tle_from_lines(line1, line2) FROM raw_tles;
```
Accessors: `tle_epoch(tle) → float8` (Julian date), `tle_norad_id(tle) → int4`, `tle_inclination(tle) → float8` (degrees), `tle_eccentricity(tle) → float8`, `tle_raan(tle) → float8` (degrees), `tle_arg_perigee(tle) → float8` (degrees), `tle_mean_anomaly(tle) → float8` (degrees), `tle_mean_motion(tle) → float8` (rev/day), `tle_bstar(tle) → float8` (1/earth-radii), `tle_period(tle) → float8` (minutes), `tle_age(tle, timestamptz) → float8` (days), `tle_perigee(tle) → float8` (km), `tle_apogee(tle) → float8` (km), `tle_intl_desig(tle) → text` (COSPAR ID).
### eci_position (48 bytes)
Earth-Centered Inertial position and velocity in TEME frame.
```sql
-- Output format: (x, y, z, vx, vy, vz) in km and km/s
-- Example: (4283.007,-2459.213,4717.924,3.837,5.662,-2.969)
```
Accessors: `eci_x`, `eci_y`, `eci_z` (km), `eci_vx`, `eci_vy`, `eci_vz` (km/s), `eci_speed(eci_position) → float8` (km/s), `eci_altitude(eci_position) → float8` (km, approximate geocentric).
### geodetic (24 bytes)
WGS-84 latitude, longitude, altitude.
```sql
-- Output format: (lat_deg, lon_deg, alt_km)
-- Example: (42.3601,-71.0589,408.123)
```
Accessors: `geodetic_lat`, `geodetic_lon` (degrees), `geodetic_alt` (km).
### topocentric (32 bytes)
Observer-relative azimuth, elevation, range, range rate.
```sql
-- Output format: (azimuth_deg, elevation_deg, range_km, range_rate_km_s)
-- Example: (185.234,45.678,1234.56,-2.345)
```
Accessors: `topo_azimuth` (degrees, 0=N 90=E 180=S 270=W), `topo_elevation` (degrees, 0=horizon 90=zenith), `topo_range` (km), `topo_range_rate` (km/s, positive=receding).
### observer (24 bytes)
Ground station location. Flexible text input.
```sql
-- Multiple input formats:
SELECT '40.0N 105.3W 1655m'::observer; -- DMS with cardinal directions
SELECT '40.0 -105.3 1655m'::observer; -- Decimal degrees (negative=W/S)
SELECT '40.0N 105.3W'::observer; -- Altitude defaults to 0m
-- Programmatic construction:
SELECT observer_from_geodetic(40.0, -105.3, 1655.0); -- (lat_deg, lon_deg, alt_m)
```
Accessors: `observer_lat` (degrees, +N), `observer_lon` (degrees, +E), `observer_alt` (meters).
### pass_event (48 bytes)
Satellite pass visibility window with AOS/MAX/LOS.
```sql
-- Output format: (aos_time, max_el_time, los_time, max_el_deg, aos_az_deg, los_az_deg)
```
Accessors: `pass_aos_time`, `pass_max_el_time`, `pass_los_time` (timestamptz), `pass_max_elevation` (degrees), `pass_aos_azimuth`, `pass_los_azimuth` (degrees), `pass_duration(pass_event) → interval`.
### heliocentric (24 bytes)
Ecliptic J2000 position in AU.
```sql
-- Output format: (x_au, y_au, z_au)
-- Example: (0.983271,-0.182724,0.000021)
```
Accessors: `helio_x`, `helio_y`, `helio_z` (AU), `helio_distance(heliocentric) → float8` (AU).
### orbital_elements (72 bytes)
Classical Keplerian elements for comets and asteroids.
```sql
-- Text I/O format: (epoch_jd, q_au, e, inc_deg, omega_deg, Omega_deg, tp_jd, H, G)
-- Example: (2460200.5,1.0123,0.2156,10.587,72.891,80.329,2460180.5,15.2,0.15)
-- From MPC MPCORB.DAT:
SELECT oe_from_mpc('00001 3.52 0.15 K249V 14.81198 ...fixed-width MPC line...');
```
Accessors: `oe_epoch` (JD), `oe_perihelion` (AU), `oe_eccentricity`, `oe_inclination` (degrees), `oe_arg_perihelion` (degrees), `oe_raan` (degrees), `oe_tp` (JD), `oe_h_mag` (NaN if unknown), `oe_g_slope` (NaN if unknown), `oe_semi_major_axis` (AU, NULL if e≥1), `oe_period_years` (NULL if e≥1).
### observer_window (composite)
Query parameter bundle for SP-GiST visibility cone operator.
```sql
-- Constructed inline as a ROW:
SELECT * FROM satellites WHERE elements &? ROW(
'40.0N 105.3W 1655m'::observer,
'2024-01-01'::timestamptz,
'2024-01-02'::timestamptz,
10.0 -- min_elevation_degrees
)::observer_window;
```
Fields: `obs` (observer), `t_start` (timestamptz), `t_end` (timestamptz), `min_el` (float8, degrees).
## Body IDs
### Planets (VSOP87 convention)
| ID | Body | ID | Body |
|----|---------|----|---------|
| 0 | Sun | 5 | Jupiter |
| 1 | Mercury | 6 | Saturn |
| 2 | Venus | 7 | Uranus |
| 3 | Earth | 8 | Neptune |
| 4 | Mars | 10 | Moon |
### Galilean moons (03)
0=Io, 1=Europa, 2=Ganymede, 3=Callisto
### Saturn moons (07)
0=Mimas, 1=Enceladus, 2=Tethys, 3=Dione, 4=Rhea, 5=Titan, 6=Iapetus, 7=Hyperion
### Uranus moons (04)
0=Miranda, 1=Ariel, 2=Umbriel, 3=Titania, 4=Oberon
### Mars moons (01)
0=Phobos, 1=Deimos
## Functions by Domain
### Satellite — SGP4/SDP4 Propagation (22 functions)
```
sgp4_propagate(tle, timestamptz) → eci_position IMMUTABLE
sgp4_propagate_safe(tle, timestamptz) → eci_position IMMUTABLE -- NULL on error
sgp4_propagate_series(tle, start, end, step) → SETOF (t, x,y,z, vx,vy,vz) IMMUTABLE
tle_distance(tle, tle, timestamptz) → float8 IMMUTABLE -- km between two TLEs
eci_to_geodetic(eci_position, timestamptz) → geodetic IMMUTABLE
eci_to_topocentric(eci_position, observer, timestamptz) → topocentric IMMUTABLE
subsatellite_point(tle, timestamptz) → geodetic IMMUTABLE
ground_track(tle, start, end, step) → SETOF (t, lat, lon, alt) IMMUTABLE
observe(tle, observer, timestamptz) → topocentric IMMUTABLE -- propagate + observe in one call
observe_safe(tle, observer, timestamptz) → topocentric IMMUTABLE -- NULL on error
next_pass(tle, observer, timestamptz) → pass_event STABLE -- searches up to 7 days
predict_passes(tle, observer, start, end, min_el DEFAULT 0.0) → SETOF pass_event STABLE
pass_visible(tle, observer, start, end) → boolean STABLE
tle_from_lines(text, text) → tle IMMUTABLE
observer_from_geodetic(lat_deg, lon_deg, alt_m DEFAULT 0.0) → observer IMMUTABLE
```
TLE accessors (15): `tle_epoch`, `tle_norad_id`, `tle_inclination`, `tle_eccentricity`, `tle_raan`, `tle_arg_perigee`, `tle_mean_anomaly`, `tle_mean_motion`, `tle_bstar`, `tle_period`, `tle_age`, `tle_perigee`, `tle_apogee`, `tle_intl_desig`, `tle_from_lines`.
### Solar System — VSOP87 + ELP2000-82B (5 functions)
```
planet_heliocentric(body_id int4, timestamptz) → heliocentric IMMUTABLE -- IDs 0-8
planet_observe(body_id int4, observer, timestamptz) → topocentric IMMUTABLE -- IDs 1-8
sun_observe(observer, timestamptz) → topocentric IMMUTABLE
moon_observe(observer, timestamptz) → topocentric IMMUTABLE
```
### Planetary Moons (4 functions)
```
galilean_observe(moon_id int4, observer, timestamptz) → topocentric IMMUTABLE -- L1.2 theory, IDs 0-3
saturn_moon_observe(moon_id int4, observer, timestamptz) → topocentric IMMUTABLE -- TASS 1.7, IDs 0-7
uranus_moon_observe(moon_id int4, observer, timestamptz) → topocentric IMMUTABLE -- GUST86, IDs 0-4
mars_moon_observe(moon_id int4, observer, timestamptz) → topocentric IMMUTABLE -- MarsSat, IDs 0-1
```
### Stars (2 functions)
```
star_observe(ra_hours float8, dec_degrees float8, observer, timestamptz) → topocentric IMMUTABLE
star_observe_safe(ra_hours float8, dec_degrees float8, observer, timestamptz) → topocentric IMMUTABLE -- NULL on error
```
RA in hours [0,24), Dec in degrees [-90,90]. Range returned as 0 (infinite distance).
### Comets & Asteroids — Keplerian + MPC (5 functions)
```
kepler_propagate(q_au, eccentricity, inc_deg, arg_peri_deg, raan_deg, perihelion_jd, timestamptz) → heliocentric IMMUTABLE
comet_observe(q_au, e, inc, omega, Omega, tp_jd, earth_x, earth_y, earth_z, observer, timestamptz) → topocentric IMMUTABLE
oe_from_mpc(text) → orbital_elements IMMUTABLE -- parse MPC MPCORB.DAT line
small_body_heliocentric(orbital_elements, timestamptz) → heliocentric IMMUTABLE
small_body_observe(orbital_elements, observer, timestamptz) → topocentric IMMUTABLE -- auto-fetches Earth via VSOP87
```
orbital_elements accessors (11): `oe_epoch`, `oe_perihelion`, `oe_eccentricity`, `oe_inclination`, `oe_arg_perihelion`, `oe_raan`, `oe_tp`, `oe_h_mag`, `oe_g_slope`, `oe_semi_major_axis`, `oe_period_years`.
### Jupiter Radio (3 functions)
```
io_phase_angle(timestamptz) → float8 IMMUTABLE -- degrees [0,360)
jupiter_cml(observer, timestamptz) → float8 IMMUTABLE -- CML III degrees [0,360)
jupiter_burst_probability(io_phase_deg, cml_deg) → float8 IMMUTABLE -- 0-1 probability
```
### Interplanetary Transfers — Lambert Solver (2 functions)
```
lambert_transfer(dep_body int4, arr_body int4, dep_time, arr_time)
→ (c3_departure, c3_arrival, v_inf_departure, v_inf_arrival, tof_days, transfer_sma) IMMUTABLE
lambert_c3(dep_body int4, arr_body int4, dep_time, arr_time) → float8 IMMUTABLE -- departure C3 only, for pork chop plots
```
Body IDs 18 (MercuryNeptune). C3 in km²/s², v_inf in km/s, TOF in days, SMA in AU.
### DE Ephemeris — Optional High-Precision (11 functions)
All _de() functions fall back to VSOP87/ELP2000-82B when DE is unavailable. All STABLE (external file dependency).
```
planet_heliocentric_de(body_id int4, timestamptz) → heliocentric STABLE
planet_observe_de(body_id int4, observer, timestamptz) → topocentric STABLE
sun_observe_de(observer, timestamptz) → topocentric STABLE
moon_observe_de(observer, timestamptz) → topocentric STABLE
lambert_transfer_de(dep_body, arr_body, dep_time, arr_time) → RECORD STABLE
lambert_c3_de(dep_body, arr_body, dep_time, arr_time) → float8 STABLE
galilean_observe_de(moon_id, observer, timestamptz) → topocentric STABLE
saturn_moon_observe_de(moon_id, observer, timestamptz) → topocentric STABLE
uranus_moon_observe_de(moon_id, observer, timestamptz) → topocentric STABLE
mars_moon_observe_de(moon_id, observer, timestamptz) → topocentric STABLE
pg_orrery_ephemeris_info() → (provider, file_path, start_jd, end_jd, version, au_km) STABLE
```
Configure: `ALTER SYSTEM SET pg_orrery.ephemeris_path = '/path/to/de441.bin'; SELECT pg_reload_conf();`
### Orbit Determination (5 functions)
All return: `(fitted_tle, iterations, rms_final, rms_initial, status, condition_number, covariance, nstate)`. All STABLE.
```
tle_from_eci(positions eci_position[], times timestamptz[], seed tle DEFAULT NULL,
fit_bstar bool DEFAULT false, max_iter int4 DEFAULT 15, weights float8[] DEFAULT NULL) → RECORD
tle_from_topocentric(observations topocentric[], times timestamptz[], obs observer,
seed DEFAULT NULL, fit_bstar DEFAULT false, max_iter DEFAULT 15,
fit_range_rate DEFAULT false, weights DEFAULT NULL) → RECORD
tle_from_topocentric(observations topocentric[], times timestamptz[],
observers observer[], observer_ids int4[], -- multi-observer variant
seed DEFAULT NULL, fit_bstar DEFAULT false, max_iter DEFAULT 15,
fit_range_rate DEFAULT false, weights DEFAULT NULL) → RECORD
tle_from_angles(ra_hours float8[], dec_degrees float8[], times timestamptz[], obs observer,
seed DEFAULT NULL, fit_bstar DEFAULT false, max_iter DEFAULT 15, weights DEFAULT NULL) → RECORD
tle_from_angles(ra_hours float8[], dec_degrees float8[], times timestamptz[],
observers observer[], observer_ids int4[], -- multi-observer variant
seed DEFAULT NULL, fit_bstar DEFAULT false, max_iter DEFAULT 15, weights DEFAULT NULL) → RECORD
tle_fit_residuals(fitted tle, positions eci_position[], times timestamptz[])
→ SETOF (t, dx_km, dy_km, dz_km, pos_err_km) IMMUTABLE
```
## Operators & Indexes
### GiST — tle_ops (DEFAULT for type tle)
```sql
CREATE INDEX ON satellites USING gist (elements);
```
| Operator | Meaning | Usage |
|----------|---------|-------|
| `&&` | Orbital key overlap (altitude band AND inclination range) | `WHERE a.elements && b.elements` |
| `<->` | 2-D orbital distance (km) — L2 norm of altitude gap + inclination gap | `ORDER BY elements <-> ref_tle LIMIT 10` |
### SP-GiST — tle_spgist_ops (opt-in)
```sql
CREATE INDEX ON satellites USING spgist (elements tle_spgist_ops);
```
| Operator | Meaning | Usage |
|----------|---------|-------|
| `&?` | Visibility cone check — could satellite be visible from observer? | `WHERE elements &? ROW(obs, t0, t1, 10.0)::observer_window` |
SP-GiST is a 2-level orbital trie (SMA → inclination) with query-time RAAN filter. Returns a conservative superset — survivors need `predict_passes()` for ground truth.
## Common Query Patterns
### Observe a satellite
```sql
SELECT topo_elevation(observe(elements, '40.0N 105.3W 1655m'::observer, NOW()))
FROM satellites WHERE name = 'ISS';
```
### Batch propagation over a catalog
```sql
SELECT name,
topo_elevation(observe_safe(elements, '40.0N 105.3W'::observer, NOW())) AS el
FROM satellites
WHERE topo_elevation(observe_safe(elements, '40.0N 105.3W'::observer, NOW())) > 10;
```
### Predict passes for one satellite
```sql
SELECT pass_aos_time(p), pass_max_elevation(p), pass_duration(p)
FROM satellites,
LATERAL predict_passes(elements, '40.0N 105.3W 1655m'::observer,
NOW(), NOW() + '3 days'::interval, 10.0) AS p
WHERE name = 'ISS';
```
### SP-GiST accelerated pass prediction
```sql
SELECT s.name, p.*
FROM satellites s,
LATERAL predict_passes(s.elements, '40.0N 105.3W 1655m'::observer,
NOW(), NOW() + '1 day'::interval, 10.0) AS p
WHERE s.elements &? ROW(
'40.0N 105.3W 1655m'::observer, NOW(), NOW() + '1 day'::interval, 10.0
)::observer_window;
```
### Observe a planet
```sql
SELECT topo_azimuth(planet_observe(4, '40.0N 105.3W'::observer, NOW())) AS mars_az,
topo_elevation(planet_observe(4, '40.0N 105.3W'::observer, NOW())) AS mars_el;
```
### Tonight's visible planets
```sql
SELECT body_name, topo_elevation(obs) AS el, topo_azimuth(obs) AS az
FROM (VALUES (1,'Mercury'),(2,'Venus'),(4,'Mars'),(5,'Jupiter'),(6,'Saturn')) AS p(id, body_name),
LATERAL planet_observe(p.id, '40.0N 105.3W'::observer, NOW()) AS obs
WHERE topo_elevation(obs) > 0;
```
### GiST conjunction screening
```sql
SELECT a.name, b.name,
tle_distance(a.elements, b.elements, NOW()) AS dist_km
FROM satellites a, satellites b
WHERE a.id < b.id
AND a.elements && b.elements
AND tle_distance(a.elements, b.elements, NOW()) < 50;
```
### Observe a comet/asteroid from MPC data
```sql
-- From orbital_elements type:
SELECT topo_elevation(small_body_observe(oe, '40.0N 105.3W'::observer, NOW()))
FROM asteroids WHERE name = 'Ceres';
-- Bulk MPC import:
COPY mpc_raw(line) FROM '/path/to/MPCORB.DAT';
INSERT INTO asteroids (name, oe)
SELECT substring(line FROM 1 FOR 7), oe_from_mpc(line) FROM mpc_raw;
```
### Lambert transfer — Earth to Mars
```sql
SELECT * FROM lambert_transfer(3, 4,
'2026-07-01'::timestamptz,
'2027-01-15'::timestamptz);
-- Returns: c3_departure, c3_arrival, v_inf_departure, v_inf_arrival, tof_days, transfer_sma
```
### Pork chop plot grid
```sql
SELECT dep, arr, lambert_c3(3, 4, dep, arr) AS c3
FROM generate_series('2026-01-01'::timestamptz, '2026-12-01', '10 days') AS dep,
generate_series('2026-07-01'::timestamptz, '2027-06-01', '10 days') AS arr;
```
### Jupiter radio burst prediction
```sql
SELECT io_phase_angle(t) AS io_phase,
jupiter_cml('40.0N 105.3W'::observer, t) AS cml,
jupiter_burst_probability(io_phase_angle(t),
jupiter_cml('40.0N 105.3W'::observer, t)) AS prob
FROM generate_series(NOW(), NOW() + '24 hours', '15 minutes') AS t
WHERE jupiter_burst_probability(io_phase_angle(t),
jupiter_cml('40.0N 105.3W'::observer, t)) > 0.3;
```
### Orbit determination from observations
```sql
SELECT (tle_from_eci(
ARRAY[eci1, eci2, eci3, eci4, eci5],
ARRAY[t1, t2, t3, t4, t5]
)).*
-- Returns: fitted_tle, iterations, rms_final, rms_initial, status, condition_number, covariance, nstate
```
## Error Handling
### _safe() variants
`sgp4_propagate_safe()`, `observe_safe()`, `star_observe_safe()` return NULL on error instead of raising exceptions. Use for batch queries over potentially invalid data.
### SGP4 error codes (raised by non-_safe functions)
| Code | Meaning |
|------|---------|
| -1 | Nearly parabolic orbit |
| -2 | Negative semi-major axis (decayed) |
| -3 | Orbit within Earth radius (continues with NOTICE) |
| -4 | Orbit within Earth radius (continues with NOTICE) |
| -5 | Negative mean motion |
| -6 | Kepler solver convergence failure |
### Input validation errors
- Lambert: same-body check, arrival before departure, invalid body_id (not 18)
- Stars: RA outside [0,24), Dec outside [-90,90]
- Comets: negative perihelion distance
- Observer: invalid coordinate format
## Key Constants
### WGS-72 (SGP4 propagation only)
```
mu = 398600.8 km³/s²
ae = 6378.135 km
J2 = 0.001082616
ke = 0.0743669161331734132 min⁻¹
```
### WGS-84 (coordinate output only)
```
a = 6378.137 km
f = 1/298.257223563
```
### Astronomical
```
AU = 149597870.7 km (IAU 2012)
Gauss k = 0.01720209895 AU^(3/2)/day
Obliquity J2000 = 23.4392911°
J2000 epoch = JD 2451545.0 (2000 Jan 1.5 TT)
```
### Critical rule
TLEs are fitted against WGS-72 constants. Propagation MUST use WGS-72. Coordinate output uses WGS-84. Never mix. This is handled internally — all pg_orrery functions use the correct constants automatically.