constellation_full_name(text) returns full IAU name from 3-letter abbreviation (88-entry static table, IMMUTABLE). Returns NULL for invalid input — composable with constellation() in queries. Three rise_set_status functions classify body visibility as 'rises_and_sets', 'circumpolar', or 'never_rises' by sampling elevation at 48 points across 24h. Separate diagnostic path — called only when rise/set returns NULL, zero cost in normal case. 147 → 151 SQL objects. 25 → 26 regression suites. All pass.
414 lines
24 KiB
Markdown
414 lines
24 KiB
Markdown
# pg_orrery — A Database Orrery for PostgreSQL
|
|
|
|
## What This Is
|
|
A database orrery — celestial mechanics types and functions for PostgreSQL. Native C extension using PGXS, 151 SQL objects (135 user-visible functions + 16 GiST support), 9 custom types, covering satellites (SGP4/SDP4), planets (VSOP87 + optional JPL DE441), Moon (ELP2000-82B), 19 planetary moons (L1.2/TASS17/GUST86/MarsSat), stars (with proper motion and annual parallax), comets, asteroids (MPC catalog), Jupiter radio bursts, interplanetary Lambert transfers, equatorial RA/Dec coordinates with GiST-indexed angular separation, atmospheric refraction, annual stellar aberration, light-time correction, rise/set prediction (geometric + refracted) with status diagnostics, and IAU constellation identification with full name lookup (Roman 1987).
|
|
|
|
**Current version:** 0.15.0
|
|
**Repository:** https://git.supported.systems/warehack.ing/pg_orrery
|
|
**Documentation:** https://pg-orrery.warehack.ing
|
|
|
|
## Build System
|
|
```bash
|
|
make PG_CONFIG=/usr/bin/pg_config # Compile with PGXS
|
|
sudo make install PG_CONFIG=/usr/bin/pg_config # Install extension
|
|
make installcheck PG_CONFIG=/usr/bin/pg_config # Run 26 regression test suites
|
|
```
|
|
|
|
Requires: PostgreSQL 17 development headers, GCC, Make.
|
|
|
|
### Docker
|
|
```bash
|
|
make docker-build # Build standalone image (pg17 + pg_orrery)
|
|
make docker-test # Smoke test the image
|
|
make docker-push # Push to git.supported.systems registry
|
|
```
|
|
|
|
Image: `git.supported.systems/warehack.ing/pg_orrery:pg17`
|
|
|
|
## Project Layout
|
|
```
|
|
pg_orrery.control # Extension metadata (version 0.15.0)
|
|
Makefile # PGXS build + Docker targets
|
|
sql/
|
|
pg_orrery--0.1.0.sql # v0.1.0: satellite types/functions/operators
|
|
pg_orrery--0.2.0.sql # v0.2.0: solar system (57 functions)
|
|
pg_orrery--0.3.0.sql # v0.3.0: DE ephemeris (68 functions)
|
|
pg_orrery--0.4.0.sql # v0.4.0: orbit determination
|
|
pg_orrery--0.5.0.sql # v0.5.0: SP-GiST orbital trie
|
|
pg_orrery--0.6.0.sql # v0.6.0: conjunction screening
|
|
pg_orrery--0.7.0.sql # v0.7.0: GiST improvements
|
|
pg_orrery--0.8.0.sql # v0.8.0: orbital_elements type + MPC parser (82 functions)
|
|
pg_orrery--0.9.0.sql # v0.9.0: equatorial type, refraction, proper motion, light-time (106 functions)
|
|
pg_orrery--0.10.0.sql # v0.10.0: angular separation, cone search, apparent functions (114 functions)
|
|
pg_orrery--0.11.0.sql # v0.11.0: orbital_elements constructors, moon equatorial (120 functions)
|
|
pg_orrery--0.12.0.sql # v0.12.0: equatorial GiST, DE moon equatorial (132 objects)
|
|
pg_orrery--0.13.0.sql # v0.13.0: nutation, make_equatorial, rise/set (141 objects)
|
|
pg_orrery--0.14.0.sql # v0.14.0: refracted rise/set, constellation ID (147 objects)
|
|
pg_orrery--0.15.0.sql # v0.15.0: constellation full name, rise/set status (151 objects)
|
|
pg_orrery--0.1.0--0.2.0.sql # Migration: v0.1.0 → v0.2.0 (adds solar system)
|
|
pg_orrery--0.2.0--0.3.0.sql # Migration: v0.2.0 → v0.3.0 (adds DE ephemeris)
|
|
pg_orrery--0.3.0--0.4.0.sql # Migration: v0.3.0 → v0.4.0
|
|
pg_orrery--0.4.0--0.5.0.sql # Migration: v0.4.0 → v0.5.0
|
|
pg_orrery--0.5.0--0.6.0.sql # Migration: v0.5.0 → v0.6.0
|
|
pg_orrery--0.6.0--0.7.0.sql # Migration: v0.6.0 → v0.7.0
|
|
pg_orrery--0.7.0--0.8.0.sql # Migration: v0.7.0 → v0.8.0 (orbital_elements type)
|
|
pg_orrery--0.8.0--0.9.0.sql # Migration: v0.8.0 → v0.9.0 (equatorial, refraction, proper motion, light-time)
|
|
pg_orrery--0.9.0--0.10.0.sql # Migration: v0.9.0 → v0.10.0 (angular separation, cone search)
|
|
pg_orrery--0.10.0--0.11.0.sql # Migration: v0.10.0 → v0.11.0 (constructors, moon equatorial)
|
|
pg_orrery--0.11.0--0.12.0.sql # Migration: v0.11.0 → v0.12.0 (equatorial GiST, DE moon equatorial)
|
|
pg_orrery--0.12.0--0.13.0.sql # Migration: v0.12.0 → v0.13.0 (nutation, make_equatorial, rise/set)
|
|
pg_orrery--0.13.0--0.14.0.sql # Migration: v0.13.0 → v0.14.0 (refracted rise/set, constellation ID)
|
|
pg_orrery--0.14.0--0.15.0.sql # Migration: v0.14.0 → v0.15.0 (constellation full name, rise/set status)
|
|
src/
|
|
pg_orrery.c # PG_MODULE_MAGIC + _PG_init() (GUC registration)
|
|
types.h # All struct definitions + constants + DE body ID mapping
|
|
astro_math.h # Shared astronomical helpers + observe_from_geocentric()
|
|
# --- Satellite (v0.1.0) ---
|
|
tle_type.c # TLE custom type (I/O, binary, 15 accessors)
|
|
eci_type.c # ECI position type + geodetic/topocentric types
|
|
observer_type.c # Observer type with flexible string parsing
|
|
sgp4_funcs.c # sgp4_propagate(), _safe(), _series(), tle_distance()
|
|
coord_funcs.c # eci_to_geodetic(), eci_to_topocentric(), ground_track()
|
|
pass_funcs.c # next_pass(), predict_passes(), predict_passes_refracted(), pass_visible()
|
|
gist_tle.c # GiST operator class for TLE (&&, <->)
|
|
gist_equatorial.c # GiST operator class for equatorial (KNN <->)
|
|
# --- Solar System (v0.2.0) ---
|
|
vsop87.c / vsop87.h # VSOP87 planetary ephemeris (Bretagnon 1988)
|
|
elp82b.c / elp82b.h # ELP2000-82B lunar ephemeris (Chapront 1988)
|
|
precession.c / precession.h # IAU 1976 precession (Lieske 1979)
|
|
sidereal_time.c / .h # GMST calculation (Vallado Eq. 3-47)
|
|
elliptic_to_rectangular.c/.h # Orbital element conversions
|
|
planet_funcs.c # planet_observe(), planet_heliocentric(), sun/moon_observe(), _equatorial(), _apparent()
|
|
star_funcs.c # star_observe(), star_observe_safe(), star_equatorial(), star_observe_pm(), star_equatorial_pm()
|
|
kepler_funcs.c # kepler_propagate(), comet_observe()
|
|
kepler.h # Shared Kepler solver interface (kepler_position())
|
|
orbital_elements_type.c # orbital_elements type, MPC parser, small_body_observe/equatorial/apparent()
|
|
equatorial_funcs.c # equatorial type I/O, accessors, satellite/planet/sun/moon RA/Dec
|
|
refraction_funcs.c # atmospheric_refraction(), _ext(), topo_elevation_apparent()
|
|
rise_set_funcs.c # planet/sun/moon rise/set (geometric + refracted)
|
|
constellation_data.h / .c # Roman (1987) IAU boundary table (CDS VI/42, 357 segments)
|
|
constellation_funcs.c # constellation() from equatorial or RA/Dec
|
|
l12.c / l12.h # L1.2 Galilean moon theory (Lieske 1998)
|
|
tass17.c / tass17.h # TASS 1.7 Saturn moon theory (Vienne & Duriez 1995)
|
|
gust86.c / gust86.h # GUST86 Uranus moon theory (Laskar & Jacobson 1987)
|
|
marssat.c / marssat.h # MarsSat Mars moon theory (Jacobson 2014)
|
|
moon_funcs.c # galilean/saturn/uranus/mars_moon_observe()
|
|
radio_funcs.c # io_phase_angle(), jupiter_cml(), burst_probability()
|
|
lambert.c / lambert.h # Lambert transfer solver (Izzo 2015)
|
|
transfer_funcs.c # lambert_transfer(), lambert_c3()
|
|
# --- JPL DE Ephemeris (v0.3.0) ---
|
|
de_reader.h / de_reader.c # Clean-room JPL DE binary reader (Chebyshev/Clenshaw)
|
|
eph_provider.h / eph_provider.c # Provider dispatch, GUC, lazy init, frame rotation
|
|
de_funcs.c # All _de() SQL function implementations (incl. moon equatorial DE)
|
|
sgp4/ # Vendored SGP4/SDP4 (Bill Gray's sat_code, MIT license)
|
|
sgp4.c # Near-earth propagator (period < 225 min)
|
|
sdp4.c # Deep-space propagator (period >= 225 min)
|
|
deep.c # Lunar/solar perturbations, resonance integration
|
|
common.c # Shared initialization (Brouwer mean elements, Kepler solver)
|
|
basics.c # select_ephemeris(), FMod2p()
|
|
get_el.c # TLE parsing (parse_elements(), checksum)
|
|
tle_out.c # TLE output (write_elements_in_tle_format())
|
|
norad.h / norad_in.h # Public + internal headers
|
|
PROVENANCE.md # Vendoring decision, modifications, verification
|
|
LICENSE # MIT license (Bill Gray / Project Pluto)
|
|
test/
|
|
sql/ # 26 regression test suites
|
|
expected/ # Expected output
|
|
data/vallado_518.json # 518 Vallado test vectors (AIAA 2006-6753-Rev1)
|
|
docs/
|
|
DESIGN.md # Architecture decisions, theory-to-code mappings
|
|
Dockerfile # Starlight docs site (Astro + Caddy)
|
|
package.json # Docs site dependencies
|
|
astro.config.mjs # Starlight configuration
|
|
src/content/docs/ # MDX documentation pages
|
|
```
|
|
|
|
## Type System
|
|
|
|
All types are fixed-size, `STORAGE = plain`, `ALIGNMENT = double`. No TOAST overhead.
|
|
|
|
| Type | Bytes | Description |
|
|
|------|-------|-------------|
|
|
| `tle` | 112 | Parsed mean orbital elements for SGP4/SDP4 |
|
|
| `eci_position` | 48 | x,y,z + vx,vy,vz (km, km/s) in TEME frame |
|
|
| `geodetic` | 24 | lat, lon (radians), alt (km) above WGS-84 |
|
|
| `topocentric` | 32 | azimuth, elevation, range, range_rate |
|
|
| `observer` | 24 | lat, lon (radians), alt_m (meters) |
|
|
| `pass_event` | 48 | AOS/MAX/LOS times + max_el + AOS/LOS azimuth |
|
|
| `heliocentric` | 24 | x, y, z in AU (ecliptic J2000 frame) |
|
|
| `orbital_elements` | 72 | Classical Keplerian elements for comets/asteroids (epoch, q, e, inc, omega, Omega, tp, H, G) |
|
|
| `equatorial` | 24 | Apparent RA (hours), Dec (degrees), distance (km) — of date |
|
|
|
|
## Function Domains (151 SQL objects)
|
|
|
|
| Domain | Theory | Key Functions | Count |
|
|
|--------|--------|---------------|-------|
|
|
| Satellite | SGP4/SDP4 (Brouwer 1959) | `observe()`, `predict_passes()`, `eci_to_equatorial()` | 25 |
|
|
| Planets | VSOP87 (Bretagnon 1988) | `planet_observe()`, `planet_equatorial()`, `planet_observe_apparent()` | 7 |
|
|
| Sun/Moon | VSOP87 + ELP2000-82B | `sun_observe()`, `moon_observe()`, `sun/moon_equatorial()` | 6 |
|
|
| Planetary moons | L1.2, TASS17, GUST86, MarsSat | `galilean_observe()`, `saturn_moon_observe()`, `*_equatorial()` | 12 |
|
|
| Stars | J2000 + IAU 1976 precession | `star_observe()`, `star_equatorial()`, `star_observe_pm()` | 5 |
|
|
| Comets/asteroids | Two-body Keplerian + MPC | `small_body_observe()`, `small_body_equatorial()`, `oe_from_mpc()` | 19 |
|
|
| Refraction | Bennett (1982) | `atmospheric_refraction()`, `predict_passes_refracted()` | 4 |
|
|
| Equatorial spatial | Vincenty formula | `eq_angular_distance()`, `eq_within_cone()`, `<->` | 2 |
|
|
| Jupiter radio | Carr et al. (1983) | `jupiter_burst_probability()` | 3 |
|
|
| Transfers | Lambert (Izzo 2015) | `lambert_transfer()`, `lambert_c3()` | 2 |
|
|
| DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `*_equatorial_de()`, `*_apparent_de()` | 23 |
|
|
| GiST index (TLE) | Altitude-band approximation | `&&` (overlap), `<->` (distance) | 8 |
|
|
| GiST index (equatorial) | Spherical bounding box | `<->` (KNN ordering) | 8 |
|
|
| Rise/set | Bisection (60s scan) | `planet_next_rise()`, `sun_next_rise_refracted()`, `*_rise_set_status()` | 15 |
|
|
| Constellation | Roman (1987) CDS VI/42 | `constellation()`, `constellation_full_name()` | 3 |
|
|
| Diagnostics | -- | `pg_orrery_ephemeris_info()` | 1 |
|
|
|
|
All functions are `PARALLEL SAFE`. VSOP87/ELP82B functions are `IMMUTABLE` (compiled-in coefficients). DE functions are `STABLE` (external file dependency).
|
|
|
|
## 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 |
|
|
|
|
### Planetary Moons (per-family indexing)
|
|
- **Galilean** (0-3): Io, Europa, Ganymede, Callisto
|
|
- **Saturn** (0-7): Mimas, Enceladus, Tethys, Dione, Rhea, Titan, Iapetus, Hyperion
|
|
- **Uranus** (0-4): Miranda, Ariel, Umbriel, Titania, Oberon
|
|
- **Mars** (0-1): Phobos, Deimos
|
|
|
|
## Constant Chain of Custody
|
|
|
|
**The most critical design constraint.** TLEs absorb geodetic model biases — using wrong constants silently corrupts positions by kilometers.
|
|
|
|
### Rules
|
|
1. **SGP4 propagation**: WGS-72 constants ONLY (mu, ae, J2, J3, J4, ke)
|
|
2. **Coordinate output** (geodetic, topocentric): WGS-84 (a=6378.137km, f=1/298.257223563)
|
|
3. **TEME frame**: Only 4 of 106 IAU-80 nutation terms (matching SGP4's internal model)
|
|
4. **Solar system pipeline**: IAU 1976 precession, J2000 obliquity, GMST from Vallado Eq. 3-47
|
|
5. **Never mix**: WGS-72 propagation + WGS-84 output. No other combination.
|
|
6. **DE frame rotation**: DE positions (ICRS equatorial) pass through `equatorial_to_ecliptic()` at the provider boundary before entering the observation pipeline
|
|
7. **Same-provider rule**: Both target and Earth must come from the same provider in any geocentric computation (never mix DE target with VSOP87 Earth)
|
|
8. **DE AU consistency**: Verify DE header AU matches compiled-in `AU_KM` (149597870.7) at init time
|
|
|
|
### WGS-72 Constants (from Hoots & Roehrich STR#3, propagation only)
|
|
```c
|
|
#define WGS72_MU 398600.8 /* km^3/s^2 */
|
|
#define WGS72_AE 6378.135 /* km */
|
|
#define WGS72_J2 0.001082616
|
|
#define WGS72_KE 0.0743669161331734132 /* (min)^(-1) */
|
|
```
|
|
|
|
### WGS-84 Constants (coordinate output only)
|
|
```c
|
|
#define WGS84_A 6378.137 /* km */
|
|
#define WGS84_F (1.0 / 298.257223563)
|
|
```
|
|
|
|
### Astronomical Constants
|
|
```c
|
|
#define AU_KM 149597870.7 /* IAU 2012 */
|
|
#define GAUSS_K 0.01720209895 /* AU^(3/2)/day */
|
|
#define OBLIQUITY_J2000 0.40909280422232897 /* 23.4392911 deg in radians */
|
|
#define J2000_JD 2451545.0 /* 2000 Jan 1.5 TT */
|
|
#define C_LIGHT_AU_DAY 173.1446327 /* speed of light in AU/day */
|
|
```
|
|
|
|
## JPL DE Ephemeris (Optional)
|
|
|
|
v0.3.0 adds optional JPL DE440/441 ephemeris support (~0.1 milliarcsecond accuracy) alongside the existing VSOP87 pipeline (~1 arcsecond). DE functions are separate `_de()` variants — existing VSOP87 functions are completely unchanged.
|
|
|
|
### Architecture
|
|
|
|
- **Clean-room DE reader** (`de_reader.c`): ~250 lines of C. Parses the JPL binary format, evaluates Chebyshev polynomials via Clenshaw recurrence. No GPL dependency (avoids Bill Gray's `jpl_eph`).
|
|
- **Per-backend lazy init**: Each PostgreSQL backend opens its own file descriptor on first `_de()` call. Never opens in `_PG_init()` (postmaster context). Safe for `PARALLEL SAFE`.
|
|
- **VSOP87 fallback**: Every `_de()` function falls back to its VSOP87/ELP82B equivalent when DE is unavailable.
|
|
- **STABLE volatility**: DE functions are `STABLE` (not `IMMUTABLE`) because output depends on an external file. Existing VSOP87 functions remain `IMMUTABLE`.
|
|
|
|
### GUC Configuration
|
|
|
|
```sql
|
|
-- Set the path to a JPL DE binary file (requires superuser)
|
|
ALTER SYSTEM SET pg_orrery.ephemeris_path = '/var/lib/postgres/de441.bin';
|
|
SELECT pg_reload_conf();
|
|
|
|
-- Check which provider is active
|
|
SELECT * FROM pg_orrery_ephemeris_info();
|
|
```
|
|
|
|
| GUC | Type | Default | Context |
|
|
|-----|------|---------|---------|
|
|
| `pg_orrery.ephemeris_path` | string | `''` (empty = VSOP87 only) | `SIGHUP` (superuser only) |
|
|
|
|
### DE Function Variants
|
|
|
|
Every `_de()` function mirrors an existing VSOP87 function:
|
|
|
|
| DE Function | VSOP87 Equivalent | Volatility |
|
|
|-------------|-------------------|------------|
|
|
| `planet_heliocentric_de()` | `planet_heliocentric()` | STABLE |
|
|
| `planet_observe_de()` | `planet_observe()` | STABLE |
|
|
| `sun_observe_de()` | `sun_observe()` | STABLE |
|
|
| `moon_observe_de()` | `moon_observe()` | STABLE |
|
|
| `lambert_transfer_de()` | `lambert_transfer()` | STABLE |
|
|
| `lambert_c3_de()` | `lambert_c3()` | STABLE |
|
|
| `galilean_observe_de()` | `galilean_observe()` | STABLE |
|
|
| `saturn_moon_observe_de()` | `saturn_moon_observe()` | STABLE |
|
|
| `uranus_moon_observe_de()` | `uranus_moon_observe()` | STABLE |
|
|
| `mars_moon_observe_de()` | `mars_moon_observe()` | STABLE |
|
|
| `planet_equatorial_de()` | `planet_equatorial()` | STABLE |
|
|
| `moon_equatorial_de()` | `moon_equatorial()` | STABLE |
|
|
| `galilean_equatorial_de()` | `galilean_equatorial()` | STABLE |
|
|
| `saturn_moon_equatorial_de()` | `saturn_moon_equatorial()` | STABLE |
|
|
| `uranus_moon_equatorial_de()` | `uranus_moon_equatorial()` | STABLE |
|
|
| `mars_moon_equatorial_de()` | `mars_moon_equatorial()` | STABLE |
|
|
| `planet_observe_apparent_de()` | `planet_observe_apparent()` | STABLE |
|
|
| `sun_observe_apparent_de()` | `sun_observe_apparent()` | STABLE |
|
|
| `moon_observe_apparent_de()` | `moon_observe_apparent()` | STABLE |
|
|
| `planet_equatorial_apparent_de()` | `planet_equatorial_apparent()` | STABLE |
|
|
| `moon_equatorial_apparent_de()` | `moon_equatorial_apparent()` | STABLE |
|
|
| `small_body_observe_apparent_de()` | `small_body_observe_apparent()` | STABLE |
|
|
| `pg_orrery_ephemeris_info()` | — | STABLE |
|
|
|
|
## Vendored SGP4/SDP4
|
|
|
|
Bill Gray's sat_code (MIT license): https://github.com/Bill-Gray/sat_code
|
|
|
|
Vendored into `src/sgp4/` from upstream commit `ff7b98957dfa2979700a482bde9de9542807293e`. The `.cpp` files were renamed to `.c` — the code is valid C99 with zero C++ features (no classes, templates, namespaces, exceptions, or STL). This eliminates the `g++` and `-lstdc++` dependencies.
|
|
|
|
Modifications from upstream are minimal and documented in `src/sgp4/PROVENANCE.md`:
|
|
- Renamed `.cpp` → `.c` (no code changes — already valid C99)
|
|
- Stripped Win32 `DLL_FUNC`/`__stdcall` decorators
|
|
- Removed `extern "C"` wrapper (now compiled as C)
|
|
- Removed unused SGP/SGP8/SDP8 model prototypes
|
|
- Added forward declarations (`-Wmissing-prototypes`)
|
|
- Changed bare `inline` to `static inline` for C99 compliance
|
|
- Added equation citations referencing STR#3 and Vallado Rev-1
|
|
|
|
All numerical logic is byte-identical to upstream. Verified against 518 Vallado test vectors (AIAA 2006-6753-Rev1).
|
|
|
|
## Testing
|
|
|
|
26 regression test suites via `make installcheck`:
|
|
|
|
| Suite | What it tests |
|
|
|-------|--------------|
|
|
| tle_parse | TLE I/O round-trip, malformed input rejection, all 15 accessors |
|
|
| sgp4_propagate | SGP4/SDP4, propagation series, tle_distance |
|
|
| coord_transforms | TEME-to-geodetic, TEME-to-topocentric, ground_track |
|
|
| pass_prediction | predict_passes, next_pass, pass_visible, min elevation filter |
|
|
| gist_index | `&&` overlap, `<->` distance, GiST index scan, KNN ordering (TLE) |
|
|
| convenience | observe(), observe_safe(), tle_from_lines(), observer_from_geodetic() |
|
|
| star_observe | Star observation, IAU 1976 precession, heliocentric type I/O |
|
|
| kepler_comet | Keplerian propagation (elliptic/parabolic/hyperbolic), comet_observe |
|
|
| planet_observe | VSOP87 planets, sun_observe, moon_observe (ELP2000-82B) |
|
|
| moon_observe | Galilean/Saturn/Uranus/Mars moons, Io phase, Jupiter CML, burst probability |
|
|
| lambert_transfer | Lambert solver, lambert_c3, pork chop grid, error handling |
|
|
| de_ephemeris | DE function fallback to VSOP87, cross-provider consistency, error handling |
|
|
| od_fit | Orbit determination from ECI/topocentric/angles-only observations |
|
|
| spgist_tle | SP-GiST orbital trie index operations |
|
|
| orbital_elements | orbital_elements type I/O, MPC parser, small_body_observe/heliocentric |
|
|
| equatorial | equatorial type I/O, RA/Dec for planets/stars/satellites, proper motion, light-time |
|
|
| refraction | Bennett refraction, P/T correction, apparent elevation, refracted pass prediction |
|
|
| aberration | Annual aberration magnitude, DE apparent fallback, angular distance, cone search, stellar parallax |
|
|
| vallado_518 | 518 Vallado test vectors (AIAA 2006-6753-Rev1), per-satellite breakdown |
|
|
| v011_features | make_orbital_elements constructors, moon equatorial functions |
|
|
| gist_equatorial | Equatorial GiST KNN ordering, RA wrapping, cone search, EXPLAIN index scan |
|
|
| v012_features | DE moon equatorial fallback to VSOP87, invalid body_id rejection |
|
|
| v013_features | Nutation correction, make_equatorial constructor |
|
|
| rise_set | Planet/Sun/Moon rise/set (geometric + refracted), circumpolar, polar night |
|
|
| constellation | Roman (1987) boundary lookup, known stars, solar system objects, edge cases |
|
|
| v015_features | constellation_full_name lookup, rise_set_status diagnostics (circumpolar/never_rises) |
|
|
|
|
### PG Version Matrix
|
|
|
|
Test all 26 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker:
|
|
|
|
```bash
|
|
make test-matrix # Full matrix (PG 14-18)
|
|
make test-pg18 # Single version
|
|
PG_TEST_VERSIONS="16 17" make test-matrix # Subset
|
|
make test-matrix-clean # Remove logs + test images
|
|
```
|
|
|
|
Logs saved to `test/matrix-logs/pg${ver}.log`. The script reuses the Dockerfile `builder` stage as the test engine — no additional test infrastructure.
|
|
|
|
**Adding a new PG version:** Update `PG_TEST_VERSIONS` default in `Makefile` and `PG_VERSIONS` default in `test/pg-version-matrix.sh`.
|
|
|
|
## Error Handling Patterns
|
|
|
|
- `_safe()` variants (`sgp4_propagate_safe`, `observe_safe`, `star_observe_safe`) return NULL on error instead of raising exceptions. Use these for batch queries over potentially invalid data.
|
|
- SGP4 error codes: -1 (nearly parabolic), -2 (negative semi-major axis/decayed), -3/-4 (orbit within Earth, returns with NOTICE), -5 (negative mean motion), -6 (convergence failure)
|
|
- Pass prediction: propagation failures return -pi elevation (below horizon), shedding the failed timestep without aborting the scan.
|
|
- Input validation: same-body Lambert check, arrival-before-departure, invalid body_id, RA out of [0,24), negative perihelion distance.
|
|
|
|
## Documentation Site
|
|
|
|
**Live:** https://pg-orrery.warehack.ing
|
|
|
|
Starlight docs at `docs/` — 44+ MDX pages covering all domains.
|
|
|
|
Sections: Getting Started, Guides (9 domain walkthroughs incl. DE ephemeris), Workflow Translation (Skyfield/Horizons/GMAT/Radio Jupiter Pro comparisons), Reference (all 151 SQL objects incl. DE variants, equatorial GiST, refraction, rise/set, constellation), Architecture (Hamilton's principles, constant custody, observation pipeline), Performance (benchmarks).
|
|
|
|
### Local Development
|
|
```bash
|
|
cd docs && npm run dev # Dev server on :4321
|
|
cd docs && npm run build # Static build to dist/
|
|
```
|
|
|
|
### Production Deployment
|
|
|
|
The docs site deploys to the `warehack.ing` VPS (`149.28.126.25`) which runs caddy-docker-proxy with wildcard DNS for `*.warehack.ing`.
|
|
|
|
**Deploy (or redeploy after changes):**
|
|
```bash
|
|
ssh -A warehack-ing@pg-orrery.warehack.ing
|
|
cd ~/pg_orrery
|
|
git pull origin phase/spgist-orbital-trie # or the current branch
|
|
cd docs
|
|
make prod # builds image + starts container
|
|
```
|
|
|
|
**First-time setup on VPS:**
|
|
```bash
|
|
ssh -A warehack-ing@pg-orrery.warehack.ing
|
|
git clone git@git.supported.systems:warehack.ing/pg_orrery.git
|
|
cd pg_orrery && git checkout phase/spgist-orbital-trie
|
|
cat > docs/.env << 'EOF'
|
|
COMPOSE_PROJECT_NAME=pg-orrery-docs
|
|
NODE_ENV=production
|
|
VITE_HMR_HOST=pg-orrery.warehack.ing
|
|
EOF
|
|
cd docs && make prod
|
|
```
|
|
|
|
**Makefile targets:**
|
|
- `make prod` — build + start production (Caddy serves static files)
|
|
- `make dev` — build + start dev mode (hot-reload, volume mounts)
|
|
- `make down` — stop containers
|
|
- `make restart` — stop + start production
|
|
- `make clean` — stop + remove volumes
|
|
- `make logs` — tail container logs
|
|
|
|
**Infrastructure:** Container `pg-orrery-docs` joins external `caddy` network. caddy-docker-proxy reads labels to auto-configure reverse proxy + TLS (Let's Encrypt via Vultr DNS challenge). TLS cert provisioning takes ~2 minutes on first deploy.
|
|
|
|
**Do NOT run the docs container locally** if also deployed on the VPS — competing ACME DNS challenges will corrupt each other's TXT records.
|
|
|
|
## Coding Style
|
|
- Standard PostgreSQL extension C style
|
|
- `ereport(ERROR, ...)` for user-facing errors, never `elog(ERROR, ...)`
|
|
- All memory via `palloc`/`pfree` (PostgreSQL memory contexts)
|
|
- Comments explain "why", not "what"
|
|
- No global mutable state — all computation from function arguments (exceptions: per-backend DE handle via `on_proc_exit`; 3 statics in vendored `deep.c` + 1 cache in `sdp4.c`, safe in PostgreSQL's fork model, never modified by pg_orrery)
|
|
- Every function handling SGP4 must check the error return code
|
|
- All functions marked `PARALLEL SAFE`
|
|
- DE functions: always fall back to VSOP87/ELP82B on any error
|
|
|
|
## Git Conventions
|
|
- One commit per logical change
|
|
- Branch per phase: `phase/spgist-orbital-trie`
|
|
- Tag releases: `v0.1.0`, `v0.2.0`, `v0.3.0`
|
|
- Commit messages: imperative mood, no AI attribution
|