diff --git a/CLAUDE.md b/CLAUDE.md index b22823e..640b1a2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,11 @@ -# pg_orbit — Solar System Computation for PostgreSQL +# pg_orrery — A Database Orrery for PostgreSQL ## What This Is -A PostgreSQL extension that moves orbital mechanics inside the database — the way PostGIS did for geography. Native C extension using PGXS, 68 SQL functions, 7 custom types, covering satellites (SGP4/SDP4), planets (VSOP87 + optional JPL DE441), Moon (ELP2000-82B), 19 planetary moons (L1.2/TASS17/GUST86/MarsSat), stars, comets, Jupiter radio bursts, and interplanetary Lambert transfers. +A database orrery — celestial mechanics types and functions for PostgreSQL. Native C extension using PGXS, 68 SQL functions, 7 custom types, covering satellites (SGP4/SDP4), planets (VSOP87 + optional JPL DE441), Moon (ELP2000-82B), 19 planetary moons (L1.2/TASS17/GUST86/MarsSat), stars, comets, Jupiter radio bursts, and interplanetary Lambert transfers. **Current version:** 0.3.0 on branch `phase/solar-system-expansion` -**Repository:** https://git.supported.systems/warehack.ing/pg_orbit -**Documentation:** https://pg-orbit.warehack.ing +**Repository:** https://git.supported.systems/warehack.ing/pg_orrery +**Documentation:** https://pg-orrery.warehack.ing ## Build System ```bash @@ -18,25 +18,25 @@ Requires: PostgreSQL 17 development headers, GCC, Make. ### Docker ```bash -make docker-build # Build standalone image (pg17 + pg_orbit) +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_orbit:pg17` +Image: `git.supported.systems/warehack.ing/pg_orrery:pg17` ## Project Layout ``` -pg_orbit.control # Extension metadata (version 0.3.0) +pg_orrery.control # Extension metadata (version 0.3.0) Makefile # PGXS build + Docker targets sql/ - pg_orbit--0.1.0.sql # v0.1.0: satellite types/functions/operators - pg_orbit--0.2.0.sql # v0.2.0: solar system (57 functions) - pg_orbit--0.3.0.sql # v0.3.0: complete extension (68 functions) - pg_orbit--0.1.0--0.2.0.sql # Migration: v0.1.0 → v0.2.0 (adds solar system) - pg_orbit--0.2.0--0.3.0.sql # Migration: v0.2.0 → v0.3.0 (adds DE ephemeris) + 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: complete extension (68 functions) + 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) src/ - pg_orbit.c # PG_MODULE_MAGIC + _PG_init() (GUC registration) + 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) --- @@ -119,7 +119,7 @@ All types are fixed-size, `STORAGE = plain`, `ALIGNMENT = double`. No TOAST over | Transfers | Lambert (Izzo 2015) | `lambert_transfer()`, `lambert_c3()` | 2 | | DE ephemeris | JPL DE440/441 (optional) | `planet_observe_de()`, `moon_observe_de()` | 11 | | GiST index | Altitude-band approximation | `&&` (overlap), `<->` (distance) | 8 | -| Diagnostics | -- | `pg_orbit_ephemeris_info()` | 1 | +| 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). @@ -191,16 +191,16 @@ v0.3.0 adds optional JPL DE440/441 ephemeris support (~0.1 milliarcsecond accura ```sql -- Set the path to a JPL DE binary file (requires superuser) -ALTER SYSTEM SET pg_orbit.ephemeris_path = '/var/lib/postgres/de441.bin'; +ALTER SYSTEM SET pg_orrery.ephemeris_path = '/var/lib/postgres/de441.bin'; SELECT pg_reload_conf(); -- Check which provider is active -SELECT * FROM pg_orbit_ephemeris_info(); +SELECT * FROM pg_orrery_ephemeris_info(); ``` | GUC | Type | Default | Context | |-----|------|---------|---------| -| `pg_orbit.ephemeris_path` | string | `''` (empty = VSOP87 only) | `SIGHUP` (superuser only) | +| `pg_orrery.ephemeris_path` | string | `''` (empty = VSOP87 only) | `SIGHUP` (superuser only) | ### DE Function Variants @@ -218,7 +218,7 @@ Every `_de()` function mirrors an existing VSOP87 function: | `saturn_moon_observe_de()` | `saturn_moon_observe()` | STABLE | | `uranus_moon_observe_de()` | `uranus_moon_observe()` | STABLE | | `mars_moon_observe_de()` | `mars_moon_observe()` | STABLE | -| `pg_orbit_ephemeris_info()` | — | STABLE | +| `pg_orrery_ephemeris_info()` | — | STABLE | ## Vendored SGP4/SDP4 @@ -266,7 +266,7 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado ## Documentation Site -**Live:** https://pg-orbit.warehack.ing +**Live:** https://pg-orrery.warehack.ing Starlight docs at `docs/` — 36 MDX pages covering all domains. @@ -284,8 +284,8 @@ The docs site deploys to the `warehack.ing` VPS (`149.28.126.25`) which runs cad **Deploy (or redeploy after changes):** ```bash -ssh -A warehack-ing@pg-orbit.warehack.ing -cd ~/pg_orbit +ssh -A warehack-ing@pg-orrery.warehack.ing +cd ~/pg_orrery git pull origin phase/solar-system-expansion # or the current branch cd docs make prod # builds image + starts container @@ -293,13 +293,13 @@ make prod # builds image + starts containe **First-time setup on VPS:** ```bash -ssh -A warehack-ing@pg-orbit.warehack.ing -git clone git@git.supported.systems:warehack.ing/pg_orbit.git -cd pg_orbit && git checkout phase/solar-system-expansion +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/solar-system-expansion cat > docs/.env << 'EOF' -COMPOSE_PROJECT_NAME=pg-orbit-docs +COMPOSE_PROJECT_NAME=pg-orrery-docs NODE_ENV=production -VITE_HMR_HOST=pg-orbit.warehack.ing +VITE_HMR_HOST=pg-orrery.warehack.ing EOF cd docs && make prod ``` @@ -312,7 +312,7 @@ cd docs && make prod - `make clean` — stop + remove volumes - `make logs` — tail container logs -**Infrastructure:** Container `pg-orbit-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. +**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. @@ -321,7 +321,7 @@ cd docs && make prod - `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_orbit) +- 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 diff --git a/Dockerfile b/Dockerfile index 21a9410..9dec5d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ rm -rf /var/lib/apt/lists/* # Copy source tree (submodule content included as regular files) -WORKDIR /build/pg_orbit +WORKDIR /build/pg_orrery COPY . . ENV PG_CONFIG=/usr/lib/postgresql/${PG_MAJOR}/bin/pg_config @@ -42,8 +42,8 @@ RUN su postgres -c "/usr/lib/postgresql/${PG_MAJOR}/bin/initdb -D /tmp/pgtest" & make PG_CONFIG=${PG_CONFIG} installcheck && \ su postgres -c "/usr/lib/postgresql/${PG_MAJOR}/bin/pg_ctl -D /tmp/pgtest stop" -# Capture artifacts under /pg_orbit prefix for the next stage -RUN make PG_CONFIG=${PG_CONFIG} DESTDIR=/pg_orbit install +# Capture artifacts under /pg_orrery prefix for the next stage +RUN make PG_CONFIG=${PG_CONFIG} DESTDIR=/pg_orrery install # ── Stage 2: Minimal artifact (COPY --from target) ────────── @@ -51,25 +51,25 @@ RUN make PG_CONFIG=${PG_CONFIG} DESTDIR=/pg_orbit install # Downstream images (TimescaleDB-HA, vanilla PG) pull from here. FROM scratch AS artifact -COPY --from=builder /pg_orbit/ / -COPY docker/020_install_pg_orbit.sh /docker-entrypoint-initdb.d/ +COPY --from=builder /pg_orrery/ / +COPY docker/020_install_pg_orrery.sh /docker-entrypoint-initdb.d/ # ── Stage 3: Standalone dev/test image ─────────────────────── -# Ready-to-run PostgreSQL with pg_orbit pre-installed. +# Ready-to-run PostgreSQL with pg_orrery pre-installed. # For development, CI, and standalone experiments. # # Optional DE ephemeris at runtime (recommended): -# docker run -v /path/to/de440.bin:/var/lib/postgresql/pg_orbit/de440.bin pg_orbit -# Then: ALTER SYSTEM SET pg_orbit.ephemeris_path = '/var/lib/postgresql/pg_orbit/de440.bin'; +# docker run -v /path/to/de440.bin:/var/lib/postgresql/pg_orrery/de440.bin pg_orrery +# Then: ALTER SYSTEM SET pg_orrery.ephemeris_path = '/var/lib/postgresql/pg_orrery/de440.bin'; # # Or bake into the image (115 MB for DE440, 3.1 GB for DE441): # Place the DE file in the build context, then: -# docker build --build-arg DE_FILE=de440.bin -t pg_orbit:de440 . +# docker build --build-arg DE_FILE=de440.bin -t pg_orrery:de440 . FROM postgres:${PG_MAJOR}-bookworm AS standalone COPY --from=artifact / / -# Create the pg_orbit data directory for DE ephemeris files -RUN mkdir -p /var/lib/postgresql/pg_orbit && \ - chown postgres:postgres /var/lib/postgresql/pg_orbit +# Create the pg_orrery data directory for DE ephemeris files +RUN mkdir -p /var/lib/postgresql/pg_orrery && \ + chown postgres:postgres /var/lib/postgresql/pg_orrery diff --git a/Makefile b/Makefile index 8825d00..55900c5 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -MODULE_big = pg_orbit -EXTENSION = pg_orbit -DATA = sql/pg_orbit--0.1.0.sql sql/pg_orbit--0.2.0.sql sql/pg_orbit--0.1.0--0.2.0.sql \ - sql/pg_orbit--0.3.0.sql sql/pg_orbit--0.2.0--0.3.0.sql +MODULE_big = pg_orrery +EXTENSION = pg_orrery +DATA = sql/pg_orrery--0.1.0.sql sql/pg_orrery--0.2.0.sql sql/pg_orrery--0.1.0--0.2.0.sql \ + sql/pg_orrery--0.3.0.sql sql/pg_orrery--0.2.0--0.3.0.sql # Our extension C sources -OBJS = src/pg_orbit.o src/tle_type.o src/eci_type.o src/observer_type.o \ +OBJS = src/pg_orrery.o src/tle_type.o src/eci_type.o src/observer_type.o \ src/sgp4_funcs.o src/coord_funcs.o src/pass_funcs.o src/gist_tle.o \ src/star_funcs.o src/kepler_funcs.o \ src/vsop87.o src/elp82b.o src/elliptic_to_rectangular.o \ @@ -52,7 +52,7 @@ test-de-reader: test/test_de_reader.c src/de_reader.c src/de_reader.h # ── Docker packaging ──────────────────────────────────────── REGISTRY ?= git.supported.systems/warehack.ing -IMAGE ?= pg_orbit +IMAGE ?= pg_orrery PG_MAJOR ?= 17 TAG ?= pg$(PG_MAJOR) @@ -68,14 +68,14 @@ docker-push: docker-test: @echo "Smoke-testing standalone image..." - docker run --rm -d --name pg_orbit_test \ + docker run --rm -d --name pg_orrery_test \ -e POSTGRES_PASSWORD=test $(REGISTRY)/$(IMAGE):$(TAG) @echo "Waiting for PostgreSQL to initialize..." @sleep 10 - docker exec pg_orbit_test psql -U postgres -tAc \ + docker exec pg_orrery_test psql -U postgres -tAc \ "SELECT tle_norad_id(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);" \ | grep -q 25544 - @docker stop pg_orbit_test + @docker stop pg_orrery_test @echo "Smoke test passed." .PHONY: docker-build docker-push docker-test diff --git a/README.md b/README.md index c153b4f..ffa0c17 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ -# pg_orbit +# pg_orrery *It's not rocket science.* (It's celestial mechanics. But now it's just SQL.) -pg_orbit moves orbital mechanics inside your database. Track satellites, compute -planet positions, observe 19 planetary moons, predict Jupiter radio bursts, and -plan interplanetary trajectories — all from standard SQL. Think PostGIS, but for -objects in space. +An orrery is a clockwork model of the solar system — brass gears turning planets in their courses. pg_orrery is the same idea, built from Keplerian parameters and SQL instead of wheelwork. Where a mechanical orrery approximates orbits with gear ratios, a database orrery computes them from the six orbital elements that define each trajectory. 68 functions. 7 custom types. All `PARALLEL SAFE`. Optional JPL DE440/441 support for sub-arcsecond accuracy; core functions have zero external dependencies at runtime. @@ -15,14 +12,14 @@ for sub-arcsecond accuracy; core functions have zero external dependencies at ru ### Docker (recommended) ```bash -docker run -d --name pg_orbit \ +docker run -d --name pg_orrery \ -e POSTGRES_PASSWORD=orbit \ -p 5499:5432 \ - git.supported.systems/warehack.ing/pg_orbit:pg17 + git.supported.systems/warehack.ing/pg_orrery:pg17 ``` ```bash -psql -h localhost -p 5499 -U postgres -c "CREATE EXTENSION pg_orbit;" +psql -h localhost -p 5499 -U postgres -c "CREATE EXTENSION pg_orrery;" ``` ### Build from Source @@ -30,15 +27,15 @@ psql -h localhost -p 5499 -U postgres -c "CREATE EXTENSION pg_orbit;" Requires PostgreSQL 17 development headers and a C/C++ toolchain. ```bash -git clone https://git.supported.systems/warehack.ing/pg_orbit.git -cd pg_orbit +git clone https://git.supported.systems/warehack.ing/pg_orrery.git +cd pg_orrery git submodule update --init make PG_CONFIG=/usr/bin/pg_config sudo make install PG_CONFIG=/usr/bin/pg_config ``` ```sql -CREATE EXTENSION pg_orbit; +CREATE EXTENSION pg_orrery; ``` ## Quick Start @@ -193,12 +190,12 @@ planet observation, moon observation, Lambert transfers, and DE ephemeris. ## Documentation -Full documentation at the [pg_orbit docs site](https://pg-orbit.warehack.ing), +Full documentation at the [pg_orrery docs site](https://pg-orrery.warehack.ing), built with [Starlight](https://starlight.astro.build). Includes guides, workflow translations (from Skyfield, JPL Horizons, GMAT, Radio Jupiter Pro), complete function reference, architecture notes, and benchmarks. -## What pg_orbit Is Not +## What pg_orrery Is Not **Not a GUI.** Use Stellarium, GPredict, or STK for visualization. @@ -208,7 +205,7 @@ not for dish pointing at GHz frequencies. For that, use SPICE or Skyfield with D **Not a TLE source.** Bring your own from Space-Track, CelesTrak, or any provider. **Not a replacement for SPICE.** No BSP kernels, no aberration corrections at IAU 2000A -level. pg_orbit trades those last few milliarcseconds for SQL-speed computation joined +level. pg_orrery trades those last few milliarcseconds for SQL-speed computation joined with your existing data. **Not a full mission design tool.** The Lambert solver handles ballistic two-body @@ -217,7 +214,7 @@ transfers. For low-thrust, gravity assists, or multi-body optimization, use GMAT ## Upgrading from v0.1.0 ```sql -ALTER EXTENSION pg_orbit UPDATE TO '0.2.0'; +ALTER EXTENSION pg_orrery UPDATE TO '0.2.0'; ``` Adds all solar system functions while preserving existing TLE data and satellite functions. diff --git a/docker/020_install_pg_orbit.sh b/docker/020_install_pg_orrery.sh similarity index 70% rename from docker/020_install_pg_orbit.sh rename to docker/020_install_pg_orrery.sh index 2cc1e3d..8ee93e9 100755 --- a/docker/020_install_pg_orbit.sh +++ b/docker/020_install_pg_orrery.sh @@ -1,10 +1,10 @@ #!/bin/bash set -e -# Create the pg_orbit extension on first container startup. +# Create the pg_orrery extension on first container startup. # The 020_ prefix orders this after TimescaleDB's own init scripts # (000_, 001_, 010_) when used in timescaledb-ha images. psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "${POSTGRES_DB:-postgres}" <<-'EOSQL' - CREATE EXTENSION IF NOT EXISTS pg_orbit; + CREATE EXTENSION IF NOT EXISTS pg_orrery; EOSQL diff --git a/docs/DESIGN.md b/docs/DESIGN.md index c4606e3..c2c98d1 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -1,8 +1,8 @@ -# pg_orbit Design Document +# pg_orrery Design Document Internal architecture notes. Documents WHY decisions were made, not how to use the extension. Intended audience: future maintainers -who need to modify pg_orbit without breaking physical correctness. +who need to modify pg_orrery without breaking physical correctness. ## 1. Constant Chain of Custody @@ -49,7 +49,7 @@ prediction error of the TLE by an order of magnitude. ### Constant Inventory -| Constant | Source Paper | Value | pg_orbit Location | Vendored SGP4 Location | +| Constant | Source Paper | Value | pg_orrery Location | Vendored SGP4 Location | |----------|-------------|-------|-------------------|------------------------| | ae (equatorial radius) | Hoots & Roehrich STR#3 | 6378.135 km | `types.h` (WGS72_AE) | `src/sgp4/norad_in.h` (earth_radius_in_km) | | J2 | Hoots & Roehrich STR#3 | 0.001082616 | `types.h` (WGS72_J2) | `src/sgp4/norad_in.h` (xj2) | @@ -62,7 +62,7 @@ prediction error of the TLE by an order of magnitude. Note that `types.h` carries a parallel copy of the WGS-72 constants even though sat_code defines them in `norad_in.h`. This is intentional: -`types.h` is the single header for all pg_orbit C sources, and +`types.h` is the single header for all pg_orrery C sources, and `norad_in.h` is an internal sat_code header not meant for external consumers. The GiST index (`gist_tle.c`) and TLE accessor functions (`tle_type.c`) need KE and AE without pulling in sat_code internals. @@ -84,7 +84,7 @@ but wrong in principle, and the error compounds in index operations. ## 2. SGP4 Implementation Choice -pg_orbit wraps Bill Gray's `sat_code` library (MIT license, Project Pluto). +pg_orrery wraps Bill Gray's `sat_code` library (MIT license, Project Pluto). ### Why sat_code over alternatives @@ -130,7 +130,7 @@ C++ compiler or runtime is required. ``` src/*.c --[gcc]--> .o --| -src/sgp4/*.c --[gcc]--> .o --|--> pg_orbit.so +src/sgp4/*.c --[gcc]--> .o --|--> pg_orrery.so -lm ``` @@ -142,7 +142,7 @@ Provenance is recorded in `src/sgp4/PROVENANCE.md`. ### Design Principles -Every pg_orbit type is fixed-size, not varlena. This means: +Every pg_orrery type is fixed-size, not varlena. This means: - No TOAST overhead (no detoasting on access) - Direct pointer access via `PG_GETARG_POINTER(n)` -- no copy @@ -202,7 +202,7 @@ Six doubles: x, y, z (km), vx, vy, vz (km/s). SGP4 outputs velocity in km/min. We convert to km/s at the boundary (`sgp4_funcs.c`, lines 181-183: `vel[i] / 60.0`). This conversion happens exactly once, at the point where the pg_eci struct is populated. -Internally, all velocity in pg_orbit is km/s. +Internally, all velocity in pg_orrery is km/s. ### Geodetic Type (24 bytes) @@ -490,7 +490,7 @@ from its arguments alone. The v0.3.0 DE ephemeris layer introduces per-backend static state in `eph_provider.c` (file descriptor, coefficient cache, init flags). This is safe because each backend gets its own copy after fork(). The handle -is cleaned up via `on_proc_exit()`. All pg_orbit functions remain +is cleaned up via `on_proc_exit()`. All pg_orrery functions remain `PARALLEL SAFE` -- parallel workers each open their own DE handle independently. @@ -525,7 +525,7 @@ the per-row propagation loop. sat_code returns integer error codes from SGP4() and SDP4(): -| Code | Constant | Severity | Meaning | pg_orbit Response | +| Code | Constant | Severity | Meaning | pg_orrery Response | |------|----------|----------|---------|-------------------| | 0 | -- | OK | Normal | Return result | | -1 | SXPX_ERR_NEARLY_PARABOLIC | Fatal | eccentricity >= 1 | `ereport(ERROR)` | @@ -572,7 +572,7 @@ initialize the propagator. ## 9. Theory-to-Code Mapping This table maps key equations from the SGP4 theory papers to their -implementation in pg_orbit and the vendored SGP4 code. +implementation in pg_orrery and the vendored SGP4 code. | Theory | Paper | What | Code Location | |--------|-------|------|---------------| @@ -602,7 +602,7 @@ section documents the architectural decisions specific to DE integration. ### The Fundamental Tension -pg_orbit's core properties (compiled-in coefficients, no file I/O, no +pg_orrery's core properties (compiled-in coefficients, no file I/O, no mutable state) are precisely what DE441 challenges. A ~3GB binary file introduces file dependency, per-backend state (file descriptor, coefficient cache), and OS-level file descriptor management across @@ -649,10 +649,10 @@ The reader is implemented in ~250 lines of C (`de_reader.c`), using: #### Why Not jpl_eph Bill Gray's `jpl_eph` (GPL-2+) would be the obvious choice, but: -1. GPL-2+ license constrains pg_orbit's licensing flexibility +1. GPL-2+ license constrains pg_orrery's licensing flexibility 2. Uses global statics (`static int init_err_code`) -3. Written in C++ (`jpleph.cpp`); pg_orbit is pure C -4. We only need position queries, not velocity or nutation +3. Written in C++ (`jpleph.cpp`); pg_orrery is pure C +4. pg_orrery only needs position queries, not velocity or nutation The format is well-documented and the algorithm is straightforward. A clean-room implementation in ~250 lines avoids all four issues. @@ -685,7 +685,7 @@ Cleanup is via `on_proc_exit(eph_cleanup, 0)`, registered in `_PG_init()`. ### ICRS-to-Ecliptic Frame Rotation DE ephemerides return positions in the ICRS equatorial frame. The -pg_orbit observation pipeline expects ecliptic J2000. The conversion +pg_orrery observation pipeline expects ecliptic J2000. The conversion happens at the provider boundary in `eph_provider.c`: ``` @@ -732,7 +732,7 @@ Every `_de()` function follows this pattern: - Fall back to VSOP87/ELP82B equivalent - Return the VSOP87 result -When `pg_orbit.ephemeris_path` is empty (default), DE functions fall +When `pg_orrery.ephemeris_path` is empty (default), DE functions fall back silently -- no NOTICE, no overhead, identical results to the non-DE variants. diff --git a/docs/agent-threads/craft-integration/001-craft-use-cases-and-api-feedback.md b/docs/agent-threads/craft-integration/001-craft-use-cases-and-api-feedback.md index ae3f2e8..9adb357 100644 --- a/docs/agent-threads/craft-integration/001-craft-use-cases-and-api-feedback.md +++ b/docs/agent-threads/craft-integration/001-craft-use-cases-and-api-feedback.md @@ -3,7 +3,7 @@ | Field | Value | |-------|-------| | From | craft-api | -| To | pg-orbit | +| To | pg-orrery | | Date | 2026-02-15T17:00:00-07:00 | | Re | Consumer use cases and API feedback on first draft | @@ -13,7 +13,7 @@ Craft is a satellite tracking + radio astronomy platform at `~/claude/ham/satellite/astrolock/`. We run a FastAPI backend backed by TimescaleDB-HA. Our database holds 22,000+ satellites with TLE data, frequencies, group memberships, and pgai vector embeddings. The frontend renders a live sky view via `/api/sky/up`. -The sky engine (`packages/api/src/astrolock_api/services/sky_engine.py`) uses Python Skyfield to compute positions for planets, the sun/moon, bright stars, and comets. Satellites are conspicuously absent from the `whats_up()` response because per-request Python propagation of 22k TLEs is untenable. pg_orbit is the solution. +The sky engine (`packages/api/src/astrolock_api/services/sky_engine.py`) uses Python Skyfield to compute positions for planets, the sun/moon, bright stars, and comets. Satellites are conspicuously absent from the `whats_up()` response because per-request Python propagation of 22k TLEs is untenable. pg_orrery is the solution. ## What We Love About the First Draft @@ -139,7 +139,7 @@ Our API passes observer coordinates as floats from the `observer_location` table ### P0 -- Unblocks `/api/sky/up` -| Use Case | Query Pattern | pg_orbit Functions | +| Use Case | Query Pattern | pg_orrery Functions | |----------|--------------|-------------------| | What satellites are overhead? | `WHERE topo_elevation(observe(...)) >= :min_alt` | `observe()` (new), `topo_elevation()` | | Single satellite position | `observe(tle_from_lines(:l1, :l2), :obs, NOW())` | `observe()` (new), `tle_from_lines()` (new) | @@ -147,7 +147,7 @@ Our API passes observer coordinates as floats from the `observer_location` table ### P1 -- Enables pass prediction and materialized views -| Use Case | Query Pattern | pg_orbit Functions | +| Use Case | Query Pattern | pg_orrery Functions | |----------|--------------|-------------------| | Upcoming passes for a group | `LATERAL predict_passes(tle, :obs, NOW(), NOW()+'24h', 10.0)` | `predict_passes()`, `tle_from_lines()` (new) | | Next pass for a satellite | `next_pass(tle_from_lines(:l1, :l2), :obs, NOW())` | `next_pass()`, `tle_from_lines()` (new) | @@ -157,7 +157,7 @@ Our API passes observer coordinates as floats from the `observer_location` table ### P2 -- Batch Doppler, ground tracks, conjunction screening -| Use Case | Query Pattern | pg_orbit Functions | +| Use Case | Query Pattern | pg_orrery Functions | |----------|--------------|-------------------| | Doppler correction | `f.frequency_mhz * (1 - topo_range_rate(observe(...))/299792.458)` | `observe()` (new), `topo_range_rate()` | | Ground track overlay | `LATERAL ground_track(tle, :start, :stop, '30s')` | `ground_track()` | @@ -166,7 +166,7 @@ Our API passes observer coordinates as floats from the `observer_location` table ### P2 -- PostGIS integration (future) -| Use Case | Query Pattern | pg_orbit Functions | +| Use Case | Query Pattern | pg_orrery Functions | |----------|--------------|-------------------| | Satellites over a region | `WHERE ST_Contains(:geom, ST_Point(geodetic_lon(g), geodetic_lat(g)))` | `ground_track()`, geodetic accessors | | Footprint circles | `ST_Buffer(ST_Point(lon, lat), footprint_radius)` | `subsatellite_point()`, `geodetic_lat/lon()` | @@ -241,7 +241,7 @@ ORDER BY s.name, f.frequency_mhz; We can provide: -1. **ISS TLE + known Skyfield positions** -- We already compute ISS position via Python Skyfield. We can generate comparison data: given a TLE and timestamp, here's what Skyfield says for az/el/range from our observer. pg_orbit should match to within the expected SGP4 implementation differences. +1. **ISS TLE + known Skyfield positions** -- We already compute ISS position via Python Skyfield. We can generate comparison data: given a TLE and timestamp, here's what Skyfield says for az/el/range from our observer. pg_orrery should match to within the expected SGP4 implementation differences. 2. **Amateur satellite group TLEs** -- Our `satellite_group` table has curated groups ('amateur', 'weather', 'starlink', etc.). We can provide a batch of TLEs for pass prediction testing. @@ -264,4 +264,4 @@ We can provide: - [ ] Confirm whether `tle_in()` validates checksums and what happens on bad input - [ ] Clarify NULL-vs-error behavior for failed propagation - [ ] Consider a `_safe` variant of propagation functions that returns NULL on error -- [ ] Reply with `002-pg-orbit-*.md` when ready +- [ ] Reply with `002-pg-orrery-*.md` when ready diff --git a/docs/agent-threads/craft-integration/002-pg-orbit-api-response.md b/docs/agent-threads/craft-integration/002-pg-orbit-api-response.md index 3290c4d..1718bc6 100644 --- a/docs/agent-threads/craft-integration/002-pg-orbit-api-response.md +++ b/docs/agent-threads/craft-integration/002-pg-orbit-api-response.md @@ -2,7 +2,7 @@ | Field | Value | |-------|-------| -| From | pg-orbit | +| From | pg-orrery | | To | craft-api | | Date | 2026-02-15T18:45:00-07:00 | | Re | All three convenience functions shipped, plus _safe variants | @@ -150,10 +150,10 @@ Drop the test data as `003-craft-test-data.md` in this thread and we'll integrat ## Build & Install ```bash -cd ~/claude/pg_orbit +cd ~/claude/pg_orrery make clean && make # Zero warnings sudo make install -psql -c "DROP EXTENSION IF EXISTS pg_orbit CASCADE; CREATE EXTENSION pg_orbit;" +psql -c "DROP EXTENSION IF EXISTS pg_orrery CASCADE; CREATE EXTENSION pg_orrery;" ``` --- diff --git a/docs/agent-threads/craft-integration/003-craft-test-data.md b/docs/agent-threads/craft-integration/003-craft-test-data.md index 6cfc593..21eff36 100644 --- a/docs/agent-threads/craft-integration/003-craft-test-data.md +++ b/docs/agent-threads/craft-integration/003-craft-test-data.md @@ -3,7 +3,7 @@ | Field | Value | |-------|-------| | From | craft-api | -| To | pg-orbit | +| To | pg-orrery | | Date | 2026-02-15T19:30:00-07:00 | | Re | Test data package -- ISS vectors, edge cases, cross-verification script | @@ -224,10 +224,10 @@ Save as `test/skyfield_verify.py` or run standalone. Uses `uv run` with inline s # ] # /// """ -Cross-verification tool for pg_orbit. +Cross-verification tool for pg_orrery. Computes satellite position via Skyfield/sgp4 and outputs JSON -for comparison against pg_orbit's observe() function. +for comparison against pg_orrery's observe() function. Usage: uv run skyfield_verify.py --tle1 "1 25544U ..." --tle2 "2 25544 ..." \ @@ -363,7 +363,7 @@ def run_batch(args): def main(): parser = argparse.ArgumentParser( - description="Cross-verify satellite positions against pg_orbit" + description="Cross-verify satellite positions against pg_orrery" ) sub = parser.add_subparsers(dest="mode") @@ -411,11 +411,11 @@ Batch mode expects a CSV with columns: `tle1,tle2,lat,lon,alt,timestamp` uv run skyfield_verify.py batch --csv test_vectors.csv --output skyfield_results.json ``` -Then compare `skyfield_results.json` against pg_orbit output for the same inputs. +Then compare `skyfield_results.json` against pg_orrery output for the same inputs. -Expected agreement between Skyfield and pg_orbit: ~0.01 deg angular, ~1 km range, ~0.001 km/s range rate. Larger discrepancies indicate a constants mismatch (WGS-72 vs WGS-84) or nutation model difference. +Expected agreement between Skyfield and pg_orrery: ~0.01 deg angular, ~1 km range, ~0.001 km/s range rate. Larger discrepancies indicate a constants mismatch (WGS-72 vs WGS-84) or nutation model difference. -## 5. Suggested pg_orbit Regression SQL +## 5. Suggested pg_orrery Regression SQL ### 5a. Round-trip: tle_from_lines extracts correct NORAD ID diff --git a/docs/agent-threads/craft-integration/004-pg-orbit-test-results.md b/docs/agent-threads/craft-integration/004-pg-orbit-test-results.md index 35e8e25..1c769ec 100644 --- a/docs/agent-threads/craft-integration/004-pg-orbit-test-results.md +++ b/docs/agent-threads/craft-integration/004-pg-orbit-test-results.md @@ -2,7 +2,7 @@ | Field | Value | |-------|-------| -| From | pg-orbit | +| From | pg-orrery | | To | craft-api | | Date | 2026-02-15T19:10:00-07:00 | | Re | Test results -- all pass, plus 2-D GiST index upgrade | @@ -11,7 +11,7 @@ ## Test Results Summary -All suggested regression tests from message 003 pass against pg_orbit v0.1.0 on PostgreSQL 17 (port 5499). +All suggested regression tests from message 003 pass against pg_orrery v0.1.0 on PostgreSQL 17 (port 5499). | Test | Result | Notes | |------|--------|-------| @@ -76,11 +76,11 @@ If Craft wants to explicitly filter by observer latitude (stronger pruning), we Your `skyfield_verify.py` script is excellent. I have not run it yet (it requires `uv run` with sgp4/skyfield/numpy). The expected agreement tolerances you specified (0.05 deg angular, 5 km range, 0.01 km/s range rate) are reasonable for SGP4 implementations using the same WGS-72 constants. -One note: Skyfield's `altaz()` uses the full IAU-80 nutation model (106 terms) for TEME→ITRF conversion, while pg_orbit uses only the 4 terms that match SGP4's internal model (per Hoots & Roehrich STR#3). This can introduce ~0.01-0.03 deg differences in azimuth at certain times. The range/range-rate agreement should be tighter since those are less sensitive to frame rotation. +One note: Skyfield's `altaz()` uses the full IAU-80 nutation model (106 terms) for TEME→ITRF conversion, while pg_orrery uses only the 4 terms that match SGP4's internal model (per Hoots & Roehrich STR#3). This can introduce ~0.01-0.03 deg differences in azimuth at certain times. The range/range-rate agreement should be tighter since those are less sensitive to frame rotation. ## Next Steps -Your edge case TLEs (Vela 1, Molniya, decayed, JPSS-1, GOES-16) are already verified individually. They would be good additions to pg_orbit's regression suite as permanent test cases. +Your edge case TLEs (Vela 1, Molniya, decayed, JPSS-1, GOES-16) are already verified individually. They would be good additions to pg_orrery's regression suite as permanent test cases. The amateur satellite batch is particularly valuable for testing `observe_safe()` in the pattern Craft's API will use — `LATERAL observe_safe(...)` over a table of TLEs. diff --git a/docs/agent-threads/craft-integration/005-craft-integration-complete.md b/docs/agent-threads/craft-integration/005-craft-integration-complete.md index 3bf7135..bb6f7cd 100644 --- a/docs/agent-threads/craft-integration/005-craft-integration-complete.md +++ b/docs/agent-threads/craft-integration/005-craft-integration-complete.md @@ -3,9 +3,9 @@ | Field | Value | |-------|-------| | From | craft-api | -| To | pg-orbit | +| To | pg-orrery | | Date | 2026-02-15T20:00:00-07:00 | -| Re | Integration complete — install pg_orbit on Craft database | +| Re | Integration complete — install pg_orrery on Craft database | --- @@ -15,13 +15,13 @@ Craft-side integration is done. The sky engine (`sky_engine.py`) already calls ` ## What's Left -pg_orbit needs to be installed on the Craft database (TimescaleDB-HA, PostgreSQL 17, port 5499): +pg_orrery needs to be installed on the Craft database (TimescaleDB-HA, PostgreSQL 17, port 5499): ```bash -cd ~/claude/pg_orbit +cd ~/claude/pg_orrery make clean && make sudo make install -psql -p 5499 -d astrolock -c "CREATE EXTENSION IF NOT EXISTS pg_orbit;" +psql -p 5499 -d astrolock -c "CREATE EXTENSION IF NOT EXISTS pg_orrery;" ``` Once installed, `/api/sky/up` will include satellites automatically — no code changes, no restart needed. The `observe_safe()` query runs on next request. diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 4bcae5a..21b7ca5 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -6,28 +6,28 @@ import rehypeKatex from "rehype-katex"; import mermaid from "astro-mermaid"; import icon from "astro-icon"; import opengraphImages from "astro-opengraph-images"; -import { pgOrbitOgImage } from "./src/og-renderer.js"; +import { pgOrreryOgImage } from "./src/og-renderer.js"; import * as fs from "fs"; export default defineConfig({ - site: "https://pg-orbit.warehack.ing", + site: "https://pg-orrery.warehack.ing", integrations: [ icon(), mermaid(), starlight({ - title: "pg_orbit", + title: "pg_orrery", description: - "It's not rocket science. Celestial mechanics for PostgreSQL.", + "It's not rocket science. A database orrery — celestial mechanics for PostgreSQL.", favicon: "/favicon.svg", logo: { - src: "./src/assets/pg-orbit-logo.svg", + src: "./src/assets/pg-orrery-logo.svg", replacesTitle: true, }, social: [ { icon: "github", label: "Gitea", - href: "https://git.supported.systems/warehack.ing/pg_orbit", + href: "https://git.supported.systems/warehack.ing/pg_orrery", }, ], customCss: [ @@ -51,7 +51,7 @@ export default defineConfig({ { label: "Getting Started", items: [ - { label: "What is pg_orbit?", slug: "getting-started/what-is-pg-orbit" }, + { label: "What is pg_orrery?", slug: "getting-started/what-is-pg-orrery" }, { label: "Installation", slug: "getting-started/installation" }, { label: "Quick Start", slug: "getting-started/quick-start" }, ], @@ -136,7 +136,7 @@ export default defineConfig({ }, ], }, - render: pgOrbitOgImage, + render: pgOrreryOgImage, }), ], diff --git a/docs/docker-compose.dev.yml b/docs/docker-compose.dev.yml index fcb9442..f180f5d 100644 --- a/docs/docker-compose.dev.yml +++ b/docs/docker-compose.dev.yml @@ -8,7 +8,7 @@ services: - ./astro.config.mjs:/app/astro.config.mjs - ./package.json:/app/package.json environment: - - VITE_HMR_HOST=${VITE_HMR_HOST:-pg-orbit.warehack.ing} + - VITE_HMR_HOST=${VITE_HMR_HOST:-pg-orrery.warehack.ing} labels: # WebSocket / HMR support for dev hot-reload caddy.reverse_proxy.flush_interval: "-1" diff --git a/docs/docker-compose.yml b/docs/docker-compose.yml index c2e55cf..515c46d 100644 --- a/docs/docker-compose.yml +++ b/docs/docker-compose.yml @@ -4,7 +4,7 @@ services: context: . dockerfile: Dockerfile target: production - container_name: pg-orbit-docs + container_name: pg-orrery-docs restart: unless-stopped expose: - "3000" @@ -13,7 +13,7 @@ services: environment: - ASTRO_TELEMETRY_DISABLED=1 labels: - caddy: pg-orbit.warehack.ing + caddy: pg-orrery.warehack.ing caddy.reverse_proxy: "{{upstreams 3000}}" caddy.encode: gzip diff --git a/docs/package-lock.json b/docs/package-lock.json index 36f0855..2f4b673 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -1,11 +1,11 @@ { - "name": "pg-orbit-docs", + "name": "pg-orrery-docs", "version": "2026.02.16", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "pg-orbit-docs", + "name": "pg-orrery-docs", "version": "2026.02.16", "dependencies": { "@astrojs/starlight": "^0.37.6", diff --git a/docs/package.json b/docs/package.json index 2541db4..418bef1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,5 +1,5 @@ { - "name": "pg-orbit-docs", + "name": "pg-orrery-docs", "type": "module", "version": "2026.02.16", "private": true, diff --git a/docs/src/assets/pg-orbit-logo.svg b/docs/src/assets/pg-orrery-logo.svg similarity index 92% rename from docs/src/assets/pg-orbit-logo.svg rename to docs/src/assets/pg-orrery-logo.svg index 80b3d4e..6e170f8 100644 --- a/docs/src/assets/pg-orbit-logo.svg +++ b/docs/src/assets/pg-orrery-logo.svg @@ -7,6 +7,6 @@ - - pg_orbit + + pg_orrery diff --git a/docs/src/components/Head.astro b/docs/src/components/Head.astro index 89d70a0..de76a82 100644 --- a/docs/src/components/Head.astro +++ b/docs/src/components/Head.astro @@ -11,10 +11,10 @@ import Default from "@astrojs/starlight/components/Head.astro"; import { getImagePath } from "astro-opengraph-images"; const route = Astro.locals.starlightRoute; -const title = route?.entry?.data?.title ?? "pg_orbit"; +const title = route?.entry?.data?.title ?? "pg_orrery"; const description = route?.entry?.data?.description || - "It's not rocket science. Celestial mechanics for PostgreSQL."; + "It's not rocket science. A database orrery — celestial mechanics for PostgreSQL."; const ogImageUrl = getImagePath({ url: Astro.url, site: Astro.site }); --- diff --git a/docs/src/content/docs/architecture/constant-chain-of-custody.mdx b/docs/src/content/docs/architecture/constant-chain-of-custody.mdx index ca64774..b09ef47 100644 --- a/docs/src/content/docs/architecture/constant-chain-of-custody.mdx +++ b/docs/src/content/docs/architecture/constant-chain-of-custody.mdx @@ -6,7 +6,7 @@ sidebar: import { Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -This is the single most critical design constraint in pg_orbit. Get it wrong and positions silently drift by kilometers. There is no runtime check that can detect this class of error after the fact. +This is the single most critical design constraint in pg_orrery. Get it wrong and positions silently drift by kilometers. There is no runtime check that can detect this class of error after the fact. ## The problem @@ -40,7 +40,7 @@ WGS-72 for propagation, WGS-84 for output. Perigee and apogee altitudes use WGS- ## Constant inventory -The complete set of constants, with provenance and location in both pg_orbit and the vendored SGP4 code. +The complete set of constants, with provenance and location in both pg_orrery and the vendored SGP4 code. ### WGS-72 constants (propagation domain) @@ -77,7 +77,7 @@ Source: NIMA TR8350.2, "Department of Defense World Geodetic System 1984." `types.h` carries a parallel copy of the WGS-72 constants even though the vendored SGP4 code defines them in `norad_in.h`. This is intentional. -`types.h` is the single header for all pg_orbit C sources. `norad_in.h` is an internal SGP4 header in `src/sgp4/` not meant for external consumers. The GiST index (`gist_tle.c`) and TLE accessor functions (`tle_type.c`) need $k_e$ and $a_e$ without pulling in sat_code internals. The values **must** be identical. +`types.h` is the single header for all pg_orrery C sources. `norad_in.h` is an internal SGP4 header in `src/sgp4/` not meant for external consumers. The GiST index (`gist_tle.c`) and TLE accessor functions (`tle_type.c`) need $k_e$ and $a_e$ without pulling in sat_code internals. The values **must** be identical. The perigee and apogee altitude computations derive from mean elements: @@ -120,7 +120,7 @@ $$ where $T_{UT1} = (JD - 2451545.0) / 36525.0$, and the result is in seconds of time, converted to radians by multiplying by $\pi / 43200$ and normalized to $[0, 2\pi)$. -pg_orbit deliberately does **not** use a higher-precision GMST model (e.g., IAU 2000A). The SGP4 output is only accurate to the precision of its own GMST model. Applying a more precise rotation would not improve the final position and could introduce a systematic offset between the propagated TEME position and the Earth-fixed frame. +pg_orrery deliberately does **not** use a higher-precision GMST model (e.g., IAU 2000A). The SGP4 output is only accurate to the precision of its own GMST model. Applying a more precise rotation would not improve the final position and could introduce a systematic offset between the propagated TEME position and the Earth-fixed frame. This is the constant chain of custody in action: match the precision of the input, not the precision available in the literature. @@ -151,7 +151,7 @@ else ### Rule 8: AU consistency verification -The DE header contains an AU value (in km). At init time, `eph_provider.c` verifies this matches pg_orbit's compiled-in `AU_KM` constant (149597870.7 km, IAU 2012). A mismatch would corrupt every distance calculation. If they disagree, the DE file is rejected and fallback to VSOP87 activates with a log message. +The DE header contains an AU value (in km). At init time, `eph_provider.c` verifies this matches pg_orrery's compiled-in `AU_KM` constant (149597870.7 km, IAU 2012). A mismatch would corrupt every distance calculation. If they disagree, the DE file is rejected and fallback to VSOP87 activates with a log message. -pg_orbit defends against three categories of unexpected input that would silently produce wrong results in a naive implementation. +pg_orrery defends against three categories of unexpected input that would silently produce wrong results in a naive implementation. ### Same-body Lambert transfer @@ -164,7 +164,7 @@ What happens when someone computes a transfer from Earth to Earth? SELECT * FROM lambert_transfer(3, 3, '2028-01-01', '2028-06-01'); ``` -The departure and arrival positions are the same body at different times. The Lambert solver would converge on a trivial solution that does not represent a physical transfer orbit. pg_orbit validates `dep_body_id != arr_body_id` and returns an error before invoking the solver. +The departure and arrival positions are the same body at different times. The Lambert solver would converge on a trivial solution that does not represent a physical transfer orbit. pg_orrery validates `dep_body_id != arr_body_id` and returns an error before invoking the solver. ### Arrival before departure @@ -172,11 +172,11 @@ The departure and arrival positions are the same body at different times. The La SELECT * FROM lambert_transfer(3, 4, '2029-06-15', '2028-10-01'); ``` -A negative time of flight. The Lambert solver might converge on a mathematically valid but physically meaningless retrograde solution. pg_orbit checks `arr_time > dep_time` and returns an error. +A negative time of flight. The Lambert solver might converge on a mathematically valid but physically meaningless retrograde solution. pg_orrery checks `arr_time > dep_time` and returns an error. ### Observer on the observed body -When computing the topocentric observation of Earth (body ID 3), the geocentric vector is zero --- the observer is on the body being observed. Division by zero in the range computation. pg_orbit catches this case and returns a clear error rather than NaN or infinity propagating through the rest of the pipeline. +When computing the topocentric observation of Earth (body ID 3), the geocentric vector is zero --- the observer is on the body being observed. Division by zero in the range computation. pg_orrery catches this case and returns a clear error rather than NaN or infinity propagating through the rest of the pipeline. These are not edge cases in the traditional sense. They are the inputs that a SQL user will inevitably produce when exploring the system with ad hoc queries, and they must produce clear errors rather than silently wrong results. diff --git a/docs/src/content/docs/architecture/memory-thread-safety.mdx b/docs/src/content/docs/architecture/memory-thread-safety.mdx index 09dc030..b2303dd 100644 --- a/docs/src/content/docs/architecture/memory-thread-safety.mdx +++ b/docs/src/content/docs/architecture/memory-thread-safety.mdx @@ -6,7 +6,7 @@ sidebar: import { Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -PostgreSQL extensions run inside a shared-memory, multi-process server. A function that leaks memory degrades the entire backend. A function that uses global state cannot be parallelized. pg_orbit is designed to be a well-behaved citizen: all memory goes through PostgreSQL's allocator, and no mutable state survives between function calls. +PostgreSQL extensions run inside a shared-memory, multi-process server. A function that leaks memory degrades the entire backend. A function that uses global state cannot be parallelized. pg_orrery is designed to be a well-behaved citizen: all memory goes through PostgreSQL's allocator, and no mutable state survives between function calls. ## Allocation strategy @@ -97,7 +97,7 @@ This guarantee has three consequences: ### PARALLEL SAFE -All 68 pg_orbit functions are declared `PARALLEL SAFE` in the SQL definition. This tells PostgreSQL's query planner that the function can be executed in parallel worker processes without coordination. For bulk operations like propagating 12,000 TLEs, the planner can distribute work across multiple CPU cores: +All 68 pg_orrery functions are declared `PARALLEL SAFE` in the SQL definition. This tells PostgreSQL's query planner that the function can be executed in parallel worker processes without coordination. For bulk operations like propagating 12,000 TLEs, the planner can distribute work across multiple CPU cores: ```sql -- PostgreSQL may parallelize this across available cores @@ -110,11 +110,11 @@ If any function used global state --- even a read-only cache --- PostgreSQL woul ### No cross-session contamination -PostgreSQL backends are long-lived processes that serve multiple sessions. A global variable written by session A persists when session B runs in the same backend. pg_orbit avoids this entirely --- no function call leaves any trace in the process state. +PostgreSQL backends are long-lived processes that serve multiple sessions. A global variable written by session A persists when session B runs in the same backend. pg_orrery avoids this entirely --- no function call leaves any trace in the process state. ### Deterministic computation -Given the same TLE and timestamp, pg_orbit produces the same result regardless of what queries ran before, how many backends are active, or whether the function is running in a parallel worker. There is no path-dependent behavior. +Given the same TLE and timestamp, pg_orrery produces the same result regardless of what queries ran before, how many backends are active, or whether the function is running in a parallel worker. There is no path-dependent behavior. ## SGP4/SDP4 memory model @@ -122,8 +122,8 @@ The vendored SGP4/SDP4 code has no global mutable state. The propagator state li | Structure | Size | Contains | Owner | |-----------|------|----------|-------| -| `tle_t` | ~200 bytes | Parsed mean elements, identification | Caller (pg_orbit copies from `pg_tle`) | -| `params[N_SAT_PARAMS]` | ~736 bytes | Initialized propagator coefficients | Caller (pg_orbit `palloc`s this) | +| `tle_t` | ~200 bytes | Parsed mean elements, identification | Caller (pg_orrery copies from `pg_tle`) | +| `params[N_SAT_PARAMS]` | ~736 bytes | Initialized propagator coefficients | Caller (pg_orrery `palloc`s this) | The `SGP4_init()` / `SDP4_init()` functions write into the `params` array. The `SGP4()` / `SDP4()` functions read from `params` and `tle_t`, and write position/velocity into caller-provided arrays. No internal state is retained between calls. @@ -131,7 +131,7 @@ This maps cleanly to PostgreSQL's per-call execution model. There is no object l ## Fixed-size types -All seven pg_orbit types are fixed-size with `STORAGE = plain`: +All seven pg_orrery types are fixed-size with `STORAGE = plain`: | Type | Size | `ALIGNMENT` | TOAST? | |------|------|-------------|--------| @@ -170,7 +170,7 @@ For a typical catalog query propagating 12,000 TLEs: | Result `pg_eci` | 48 bytes | 48 bytes (returned, then freed) | | **Total transient** | **~1 KB** | **~1 KB** | -The 736-byte `params` array is the largest per-call allocation. It is freed before the function returns. At no point does pg_orbit hold allocations proportional to the number of rows being processed --- each row is computed and returned independently. +The 736-byte `params` array is the largest per-call allocation. It is freed before the function returns. At no point does pg_orrery hold allocations proportional to the number of rows being processed --- each row is computed and returned independently. -**No aberration correction.** Annual aberration shifts apparent positions by up to 20 arcseconds, but for observation planning (which quadrant of the sky is Jupiter in tonight?) this is irrelevant. For sub-arcsecond planet positions, pg_orbit v0.3.0 supports [optional DE440/441 ephemeris files](/guides/de-ephemeris/); for apparent position corrections (aberration, light-time), use SPICE or Skyfield. +**No aberration correction.** Annual aberration shifts apparent positions by up to 20 arcseconds, but for observation planning (which quadrant of the sky is Jupiter in tonight?) this is irrelevant. For sub-arcsecond planet positions, pg_orrery v0.3.0 supports [optional DE440/441 ephemeris files](/guides/de-ephemeris/); for apparent position corrections (aberration, light-time), use SPICE or Skyfield. **No light-time iteration.** The positions returned are geometric, not apparent. Light-time corrections of a few minutes for the outer planets shift the apparent position by a fraction of an arcsecond at most --- again, below the VSOP87 accuracy floor. -**No atmospheric refraction.** Refraction near the horizon can shift apparent elevation by half a degree. pg_orbit reports geometric elevation; the user must apply refraction corrections for their local conditions if needed. This is a deliberate choice --- refraction depends on temperature, pressure, and humidity that pg_orbit does not model. +**No atmospheric refraction.** Refraction near the horizon can shift apparent elevation by half a degree. pg_orrery reports geometric elevation; the user must apply refraction corrections for their local conditions if needed. This is a deliberate choice --- refraction depends on temperature, pressure, and humidity that pg_orrery does not model. ## Extending the pipeline diff --git a/docs/src/content/docs/architecture/sgp4-integration.mdx b/docs/src/content/docs/architecture/sgp4-integration.mdx index 81efd89..92df0b6 100644 --- a/docs/src/content/docs/architecture/sgp4-integration.mdx +++ b/docs/src/content/docs/architecture/sgp4-integration.mdx @@ -6,7 +6,7 @@ sidebar: import { Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -pg_orbit vendors Bill Gray's `sat_code` library (MIT license, Project Pluto) for SGP4/SDP4 propagation. The relevant source files are vendored into `src/sgp4/` with `.cpp` extensions renamed to `.c` --- the code contains zero C++ features and compiles as pure C99. This page covers why sat_code was chosen, how it integrates with PostgreSQL's build and execution model, and the error handling contract between the two codebases. +pg_orrery vendors Bill Gray's `sat_code` library (MIT license, Project Pluto) for SGP4/SDP4 propagation. The relevant source files are vendored into `src/sgp4/` with `.cpp` extensions renamed to `.c` --- the code contains zero C++ features and compiles as pure C99. This page covers why sat_code was chosen, how it integrates with PostgreSQL's build and execution model, and the error handling contract between the two codebases. ## Why sat_code @@ -14,7 +14,7 @@ Three SGP4 implementations were evaluated. The choice came down to one question: - **Pure C.** Despite upstream's `.cpp` file extensions, the code contains zero C++ features. pg_orbit vendors the files as `.c` and compiles them with `gcc`. The public API in `norad.h` is a flat C function interface: `SGP4_init()`, `SGP4()`, `SDP4_init()`, `SDP4()`, `parse_elements()`, `select_ephemeris()`. + **Pure C.** Despite upstream's `.cpp` file extensions, the code contains zero C++ features. pg_orrery vendors the files as `.c` and compiles them with `gcc`. The public API in `norad.h` is a flat C function interface: `SGP4_init()`, `SGP4()`, `SDP4_init()`, `SDP4()`, `parse_elements()`, `select_ephemeris()`. **No global mutable state.** The propagator state lives in a caller-allocated `double params[N_SAT_PARAMS]` array. This maps directly to PostgreSQL's `palloc`-based memory model. @@ -37,11 +37,11 @@ Three SGP4 implementations were evaluated. The choice came down to one question: ## Compilation -sat_code's upstream files use `.cpp` extensions but contain no C++ features --- no classes, templates, namespaces, exceptions, or STL. The vendored copies in `src/sgp4/` are renamed to `.c` and compile with `gcc` alongside the rest of pg_orbit. There is no C/C++ boundary, no `g++`, and no `-lstdc++`. +sat_code's upstream files use `.cpp` extensions but contain no C++ features --- no classes, templates, namespaces, exceptions, or STL. The vendored copies in `src/sgp4/` are renamed to `.c` and compile with `gcc` alongside the rest of pg_orrery. There is no C/C++ boundary, no `g++`, and no `-lstdc++`. ``` src/*.c --[gcc]--> .o --| -src/sgp4/*.c --[gcc]--> .o --|--> pg_orbit.so +src/sgp4/*.c --[gcc]--> .o --|--> pg_orrery.so -lm ``` @@ -67,18 +67,18 @@ PGXS handles the `-fPIC` flag and pattern rules for `.c` to `.o` compilation, so ### Header inclusion -pg_orbit's C files include `norad.h` directly: +pg_orrery's C files include `norad.h` directly: ```c #include "norad.h" /* vendored SGP4 public API */ -#include "types.h" /* pg_orbit types and WGS-72/84 constants */ +#include "types.h" /* pg_orrery types and WGS-72/84 constants */ ``` The `PG_CPPFLAGS = -I$(SGP4_DIR)` flag makes `norad.h` available without a path prefix. ## The SGP4 API surface -pg_orbit uses a small subset of sat_code's public functions. +pg_orrery uses a small subset of sat_code's public functions. ### Initialization @@ -93,7 +93,7 @@ void SGP4_init(double *params, const tle_t *tle); void SDP4_init(double *params, const tle_t *tle); ``` -Compute the propagator initialization coefficients and store them in the caller-allocated `params` array. This is the expensive step (~5x the cost of a single propagation), so pg_orbit performs it once per TLE and reuses the `params` array for SRF functions that propagate the same TLE to multiple times. +Compute the propagator initialization coefficients and store them in the caller-allocated `params` array. This is the expensive step (~5x the cost of a single propagation), so pg_orrery performs it once per TLE and reuses the `params` array for SRF functions that propagate the same TLE to multiple times. ### Propagation @@ -107,7 +107,7 @@ int SDP4(double tsince, const tle_t *tle, const double *params, Propagate to `tsince` minutes from epoch. Write position (km) and velocity (km/min) into caller-provided arrays. Return 0 on success or a negative error code. ### TLE parsing @@ -116,7 +116,7 @@ sat_code outputs velocity in km/min. pg_orbit converts to km/s at the boundary - int parse_elements(const char *line1, const char *line2, tle_t *tle); ``` -Parse two-line element text into a `tle_t` struct. Returns 0 on success. pg_orbit calls this in `tle_in()` to validate input at storage time. +Parse two-line element text into a `tle_t` struct. Returns 0 on success. pg_orrery calls this in `tle_in()` to validate input at storage time. ```c void write_elements_in_tle_format(char *obuff, const tle_t *tle); @@ -126,7 +126,7 @@ Reconstruct text from parsed elements. Used in `tle_out()` for display. ## TLE struct conversion -pg_orbit stores TLEs in its own `pg_tle` struct (112 bytes, designed for PostgreSQL tuple storage). sat_code uses `tle_t` (a larger struct with additional fields for its own purposes). The conversion between them is a field-by-field copy with no unit conversion --- both use radians, radians/minute, and Julian dates. +pg_orrery stores TLEs in its own `pg_tle` struct (112 bytes, designed for PostgreSQL tuple storage). sat_code uses `tle_t` (a larger struct with additional fields for its own purposes). The conversion between them is a field-by-field copy with no unit conversion --- both use radians, radians/minute, and Julian dates. ```c static void @@ -156,9 +156,9 @@ This conversion is duplicated in `sgp4_funcs.c`, `coord_funcs.c`, and `pass_func ## Error codes -sat_code returns integer error codes from `SGP4()` and `SDP4()`. pg_orbit classifies them by physical meaning and responds accordingly. +sat_code returns integer error codes from `SGP4()` and `SDP4()`. pg_orrery classifies them by physical meaning and responds accordingly. -| Code | sat_code constant | Physical meaning | pg_orbit response | +| Code | sat_code constant | Physical meaning | pg_orrery response | |------|-------------------|------------------|-------------------| | 0 | --- | Normal propagation | Return result | | -1 | `SXPX_ERR_NEARLY_PARABOLIC` | Eccentricity $\geq 1$ | `ereport(ERROR)` | @@ -189,11 +189,11 @@ The pass prediction context is the most interesting. A TLE valid for part of a s ## Build integration -sat_code is vendored into `src/sgp4/` --- the minimal set of source files needed for SGP4/SDP4 propagation, committed directly into the pg_orbit repository. A `PROVENANCE.md` file in that directory records the upstream repository, the exact commit hash, and every modification made during vendoring. +sat_code is vendored into `src/sgp4/` --- the minimal set of source files needed for SGP4/SDP4 propagation, committed directly into the pg_orrery repository. A `PROVENANCE.md` file in that directory records the upstream repository, the exact commit hash, and every modification made during vendoring. This approach provides: -- **Pinned version.** The vendored commit is recorded in `src/sgp4/PROVENANCE.md`. Upstream changes do not affect pg_orbit until the files are explicitly re-vendored. +- **Pinned version.** The vendored commit is recorded in `src/sgp4/PROVENANCE.md`. Upstream changes do not affect pg_orrery until the files are explicitly re-vendored. - **Clear provenance.** `PROVENANCE.md` documents the upstream repository (github.com/Bill-Gray/sat_code), commit hash, the `.cpp` to `.c` rename rationale, and a line-by-line list of every modification. - **No submodule complexity.** Cloning the repository gets a complete, buildable tree. No `git submodule update --init` step, no risk of missing submodule state. - **Pure C build.** Renaming `.cpp` to `.c` eliminates the `g++` and `-lstdc++` dependencies. The entire extension compiles with a single C compiler. @@ -214,4 +214,4 @@ This approach provides: | `PROVENANCE.md` | Upstream commit, modifications, verification notes | | `LICENSE` | MIT license from upstream | -Other sat_code files (obs_eph.cpp, sat_id.cpp, etc.) are not vendored. pg_orbit uses sat_code strictly as a propagation library, not as a satellite identification or observation planning tool. +Other sat_code files (obs_eph.cpp, sat_id.cpp, etc.) are not vendored. pg_orrery uses sat_code strictly as a propagation library, not as a satellite identification or observation planning tool. diff --git a/docs/src/content/docs/architecture/theory-to-code.mdx b/docs/src/content/docs/architecture/theory-to-code.mdx index ccca403..c11f42f 100644 --- a/docs/src/content/docs/architecture/theory-to-code.mdx +++ b/docs/src/content/docs/architecture/theory-to-code.mdx @@ -6,7 +6,7 @@ sidebar: import { Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -Every equation in pg_orbit traces to a published, peer-reviewed source. This page provides the complete mapping between the celestial mechanics literature and the source files that implement each theory. +Every equation in pg_orrery traces to a published, peer-reviewed source. This page provides the complete mapping between the celestial mechanics literature and the source files that implement each theory. If a constant, algorithm, or formula appears in the code without a citation, that is a defect to be corrected. @@ -66,7 +66,7 @@ This is the canonical SGP4/SDP4 reference. All subsequent implementations, inclu Bretagnon, P. & Francou, G. (1988). "Planetary Theories in Rectangular and Spherical Variables. VSOP87 Solutions." *Astronomy & Astrophysics*, 202, 309-315. -pg_orbit uses the VSOP87 rectangular ecliptic J2000 variant. The truncated coefficient tables provide full accuracy within the validity range of the theory (roughly 4000 BCE to 8000 CE for the inner planets, with degradation for the outer planets beyond $\pm$2000 years from J2000). +pg_orrery uses the VSOP87 rectangular ecliptic J2000 variant. The truncated coefficient tables provide full accuracy within the validity range of the theory (roughly 4000 BCE to 8000 CE for the inner planets, with degradation for the outer planets beyond $\pm$2000 years from J2000). ### ELP2000-82B @@ -101,7 +101,7 @@ The 82B revision is the version implemented. It provides geocentric ecliptic coo - Izzo, D. (2015). "Revisiting Lambert's Problem." *Celestial Mechanics and Dynamical Astronomy*, 121, 1-15. -The Izzo solver uses Householder iterations for fast convergence and handles both short-way and long-way transfers. pg_orbit uses the prograde (short-way) solution by default. +The Izzo solver uses Householder iterations for fast convergence and handles both short-way and long-way transfers. pg_orrery uses the prograde (short-way) solution by default. ## Radio emission @@ -136,7 +136,7 @@ Sample from the verification suite: # Minutes: 0.00 Expected X: -33110.816260 Y: 26044.993650 Z: -20.725400 ``` -These vectors cover the full range of orbit types that pg_orbit handles: LEO (SGP4), MEO (SGP4), GEO (SDP4), high-eccentricity Molniya (SDP4), and deep-space GPS (SDP4). Any implementation that matches all 518 vectors is functionally equivalent to the Vallado reference. +These vectors cover the full range of orbit types that pg_orrery handles: LEO (SGP4), MEO (SGP4), GEO (SDP4), high-eccentricity Molniya (SDP4), and deep-space GPS (SDP4). Any implementation that matches all 518 vectors is functionally equivalent to the Vallado reference. ## Source file index diff --git a/docs/src/content/docs/getting-started/installation.mdx b/docs/src/content/docs/getting-started/installation.mdx index be22929..e34e0e2 100644 --- a/docs/src/content/docs/getting-started/installation.mdx +++ b/docs/src/content/docs/getting-started/installation.mdx @@ -8,25 +8,25 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; - The fastest way to get pg_orbit running. The Docker image ships PostgreSQL 17 with pg_orbit pre-compiled. + The fastest way to get pg_orrery running. The Docker image ships PostgreSQL 17 with pg_orrery pre-compiled. 1. Pull the image: ```bash - docker pull git.supported.systems/warehack.ing/pg_orbit:pg17 + docker pull git.supported.systems/warehack.ing/pg_orrery:pg17 ``` 2. Start the container: ```bash - docker run -d --name pg_orbit \ + docker run -d --name pg_orrery \ -e POSTGRES_PASSWORD=orbit \ -p 5499:5432 \ - git.supported.systems/warehack.ing/pg_orbit:pg17 + git.supported.systems/warehack.ing/pg_orrery:pg17 ``` 3. Connect and enable the extension: ```bash - psql -h localhost -p 5499 -U postgres -c "CREATE EXTENSION pg_orbit;" + psql -h localhost -p 5499 -U postgres -c "CREATE EXTENSION pg_orrery;" ``` @@ -41,8 +41,8 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; 1. Clone the repository: ```bash - git clone https://git.supported.systems/warehack.ing/pg_orbit.git - cd pg_orbit + git clone https://git.supported.systems/warehack.ing/pg_orrery.git + cd pg_orrery git submodule update --init ``` @@ -54,7 +54,7 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; 3. Enable in your database: ```sql - CREATE EXTENSION pg_orbit; + CREATE EXTENSION pg_orrery; ``` 4. Verify installation: @@ -64,7 +64,7 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; @@ -74,7 +74,7 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; ```yaml services: db: - image: git.supported.systems/warehack.ing/pg_orbit:pg17 + image: git.supported.systems/warehack.ing/pg_orrery:pg17 environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-orbit} POSTGRES_DB: ${POSTGRES_DB:-orbit} @@ -90,7 +90,7 @@ import { Tabs, TabItem, Steps, Aside } from "@astrojs/starlight/components"; Then: ```bash docker compose up -d - psql -h localhost -p 5499 -U postgres -d orbit -c "CREATE EXTENSION pg_orbit;" + psql -h localhost -p 5499 -U postgres -d orbit -c "CREATE EXTENSION pg_orrery;" ``` @@ -111,10 +111,10 @@ If you have a previous version installed, upgrade in place: ```sql -- From v0.1.0 (satellite-only) to v0.2.0 (solar system) -ALTER EXTENSION pg_orbit UPDATE TO '0.2.0'; +ALTER EXTENSION pg_orrery UPDATE TO '0.2.0'; -- From v0.2.0 to v0.3.0 (DE ephemeris support) -ALTER EXTENSION pg_orbit UPDATE TO '0.3.0'; +ALTER EXTENSION pg_orrery UPDATE TO '0.3.0'; ``` Each migration adds new functions while preserving existing data and functions. diff --git a/docs/src/content/docs/getting-started/quick-start.mdx b/docs/src/content/docs/getting-started/quick-start.mdx index d6055c4..ddc854f 100644 --- a/docs/src/content/docs/getting-started/quick-start.mdx +++ b/docs/src/content/docs/getting-started/quick-start.mdx @@ -6,10 +6,10 @@ sidebar: import { Steps, Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -Five queries that show what pg_orbit can do. Each builds on the previous — from a single planet observation to planning an interplanetary trajectory. +Five queries that show what pg_orrery can do. Each builds on the previous — from a single planet observation to planning an interplanetary trajectory. @@ -108,7 +108,7 @@ All examples assume you have pg_orbit installed and `CREATE EXTENSION pg_orbit;` ## Next steps -You've seen the five domains pg_orbit covers. For deeper dives: +You've seen the five domains pg_orrery covers. For deeper dives: - **[Tracking Satellites](/guides/tracking-satellites/)** — batch observation, conjunction screening, pass prediction workflows - **[Observing the Solar System](/guides/observing-solar-system/)** — "what's up tonight?" queries, rise/set times, conjunctions diff --git a/docs/src/content/docs/getting-started/what-is-pg-orbit.mdx b/docs/src/content/docs/getting-started/what-is-pg-orrery.mdx similarity index 63% rename from docs/src/content/docs/getting-started/what-is-pg-orbit.mdx rename to docs/src/content/docs/getting-started/what-is-pg-orrery.mdx index 46c0768..8381198 100644 --- a/docs/src/content/docs/getting-started/what-is-pg-orbit.mdx +++ b/docs/src/content/docs/getting-started/what-is-pg-orrery.mdx @@ -1,16 +1,16 @@ --- -title: What is pg_orbit? +title: What is pg_orrery? sidebar: order: 1 --- import { Card, CardGrid, Aside } from "@astrojs/starlight/components"; -pg_orbit is a PostgreSQL extension that moves orbital mechanics computation inside your database. Instead of computing satellite positions in Python, planet coordinates in C++, or transfer orbits in MATLAB and then importing the results — the computation happens where your data already lives. +An orrery is a clockwork model of the solar system — brass gears turning planets in their courses. pg_orrery is the same idea, built from Keplerian parameters and SQL instead of wheelwork. Where a mechanical orrery approximates orbits with gear ratios, a database orrery computes them from the six orbital elements that define each trajectory. ## The "PostGIS for space" analogy -PostGIS added spatial awareness to PostgreSQL — suddenly your database understood geometry, distance, and containment. pg_orbit does the same for celestial mechanics. Your database understands orbits, observation geometry, and the relationships between objects in the solar system. You can JOIN orbital computation results with any other table, filter with WHERE clauses, and let PostgreSQL's query planner parallelize the work. +PostGIS added spatial awareness to PostgreSQL — suddenly your database understood geometry, distance, and containment. pg_orrery does the same for celestial mechanics. Your database understands orbits, observation geometry, and the relationships between objects in the solar system. You can JOIN orbital computation results with any other table, filter with WHERE clauses, and let PostgreSQL's query planner parallelize the work. ## What it covers @@ -47,18 +47,18 @@ PostGIS added spatial awareness to PostgreSQL — suddenly your database underst -## What pg_orbit is NOT +## What pg_orrery is NOT -**Not a GUI.** pg_orbit returns numbers. Use Stellarium, GPredict, or STK for visualization. Use any plotting library to render its output. +**Not a GUI.** pg_orrery returns numbers. Use Stellarium, GPredict, or STK for visualization. Use any plotting library to render its output. -**Not sub-arcsecond by default.** The built-in VSOP87 pipeline is accurate to about 1 arcsecond — sufficient for observation planning and visual astronomy. For precision work (dish pointing, occultation timing, astrometry), pg_orbit v0.3.0 supports [optional JPL DE440/441 ephemeris files](/guides/de-ephemeris/) that bring accuracy to ~0.1 milliarcsecond. DE is opt-in and requires a one-time GUC configuration. +**Not sub-arcsecond by default.** The built-in VSOP87 pipeline is accurate to about 1 arcsecond — sufficient for observation planning and visual astronomy. For precision work (dish pointing, occultation timing, astrometry), pg_orrery v0.3.0 supports [optional JPL DE440/441 ephemeris files](/guides/de-ephemeris/) that bring accuracy to ~0.1 milliarcsecond. DE is opt-in and requires a one-time GUC configuration. -**Not a TLE source.** Bring your own TLEs from Space-Track, CelesTrak, or any other provider. pg_orbit parses and propagates them; it doesn't fetch them. +**Not a TLE source.** Bring your own TLEs from Space-Track, CelesTrak, or any other provider. pg_orrery parses and propagates them; it doesn't fetch them. -**Not a replacement for SPICE.** No BSP kernel support, no light-time iteration, no aberration corrections at the IAU 2000A level. With DE enabled, pg_orbit matches SPICE on raw planet position accuracy — the remaining gap is in apparent-position corrections (aberration, light-time, nutation) that matter for sub-arcsecond apparent coordinates. +**Not a replacement for SPICE.** No BSP kernel support, no light-time iteration, no aberration corrections at the IAU 2000A level. With DE enabled, pg_orrery matches SPICE on raw planet position accuracy — the remaining gap is in apparent-position corrections (aberration, light-time, nutation) that matter for sub-arcsecond apparent coordinates. **Not a full mission design tool.** The Lambert solver handles ballistic two-body transfers — no low-thrust trajectories, no gravity assists, no multi-body optimization. For full mission design, use GMAT or poliastro. diff --git a/docs/src/content/docs/guides/comets-asteroids.mdx b/docs/src/content/docs/guides/comets-asteroids.mdx index 97a03bc..045132f 100644 --- a/docs/src/content/docs/guides/comets-asteroids.mdx +++ b/docs/src/content/docs/guides/comets-asteroids.mdx @@ -6,7 +6,7 @@ sidebar: import { Steps, Aside, Tabs, TabItem } from "@astrojs/starlight/components"; -pg_orbit propagates comets and asteroids using two-body Keplerian mechanics. You provide six classical orbital elements from the Minor Planet Center (MPC) or any other source, and pg_orbit computes the body's heliocentric position at any time. Combined with Earth's position from VSOP87, you can observe the body from any location on Earth. +pg_orrery propagates comets and asteroids using two-body Keplerian mechanics. You provide six classical orbital elements from the Minor Planet Center (MPC) or any other source, and pg_orrery computes the body's heliocentric position at any time. Combined with Earth's position from VSOP87, you can observe the body from any location on Earth. ## How you do it today @@ -19,7 +19,7 @@ Tracking comets and asteroids typically involves: The pattern is familiar: download elements, propagate in Python or C, transform to observer coordinates, and import results into your database. -## What changes with pg_orbit +## What changes with pg_orrery Two functions handle comet/asteroid computation: @@ -43,7 +43,7 @@ The parameters map directly to MPC orbital element format: | `Omega` | Longitude of ascending node | degrees | | `T` | Perihelion time | Julian date | -## What pg_orbit does not replace +## What pg_orrery does not replace