pg_orrery/src/de_reader.h
Ryan Malloy 3915d1784f Rename pg_orbit to pg_orrery
An existing product called PG Orbit (a mobile PostgreSQL client)
creates a naming conflict. pg_orrery — a database orrery built from
Keplerian parameters and SQL instead of brass gears.

Build system: control file, Makefile, Dockerfile, docker init script.
C source: GUC prefix, PG_FUNCTION_INFO_V1 symbol, header guards,
ereport prefixes, comments across ~30 files including vendored SGP4.
SQL: all 5 install/migration scripts, function name pg_orrery_ephemeris_info.
Tests: 9 SQL suites, 8 expected outputs, standalone DE reader test.
Documentation: CLAUDE.md, README.md, DESIGN.md, Starlight site infra,
36 MDX pages, OG renderer, logo SVG, docker-compose, agent threads.

All 13 regression suites pass. Docs site builds (37 pages).
2026-02-17 13:36:22 -07:00

141 lines
4.4 KiB
C

/*
* de_reader.h -- Clean-room JPL Development Ephemeris reader
*
* Reads JPL DE430/DE440/DE441 binary ephemeris files.
* Implements Chebyshev polynomial evaluation via Clenshaw recurrence.
*
* No GPL dependency: written from the public JPL binary format spec.
* No global state: each handle is independently opened/managed.
*
* Reference:
* JPL IOM 312.N-03-009 "The JPL Planetary and Lunar Ephemerides,
* DE405/LE405" (Standish 1998) — format description.
*/
#ifndef PG_ORRERY_DE_READER_H
#define PG_ORRERY_DE_READER_H
#include <stdint.h>
/*
* JPL DE body targets.
*
* The ephemeris stores 13 "body groups" in a specific order.
* Each group has its own coefficient layout (offset, ncoeff, nsub).
*/
#define DE_MERCURY 0
#define DE_VENUS 1
#define DE_EMB 2 /* Earth-Moon Barycenter */
#define DE_MARS 3
#define DE_JUPITER 4
#define DE_SATURN 5
#define DE_URANUS 6
#define DE_NEPTUNE 7
#define DE_PLUTO 8
#define DE_MOON 9 /* Moon (geocentric) */
#define DE_SUN 10
#define DE_NUTATION 11 /* nutations (dpsi, deps) */
#define DE_LIBRATION 12 /* lunar librations */
#define DE_NUM_BODIES 13
/*
* DE reader error codes.
*/
#define DE_OK 0
#define DE_ERR_OPEN -1 /* cannot open file */
#define DE_ERR_READ -2 /* read() failed or short read */
#define DE_ERR_HEADER -3 /* header validation failed */
#define DE_ERR_RANGE -4 /* JD out of ephemeris range */
#define DE_ERR_BODY -5 /* invalid body target */
#define DE_ERR_CANARY -6 /* canary validation failed */
#define DE_ERR_ENDIAN -7 /* byte order detection failed */
/*
* Coefficient layout for one body group.
* Parsed from the header's IPT array.
*/
typedef struct de_body_layout
{
int offset; /* word offset within record (1-based) */
int ncoeff; /* number of Chebyshev coefficients per component */
int nsub; /* number of sub-intervals per record interval */
} de_body_layout;
/*
* DE reader handle.
*
* One per PostgreSQL backend. Owns its file descriptor and
* a pre-allocated coefficient buffer.
*/
typedef struct de_handle
{
int fd; /* file descriptor */
int swap_bytes; /* 1 if byte-swapping needed */
/* Header metadata */
double start_jd; /* first valid JD */
double end_jd; /* last valid JD */
double interval_days; /* days per record */
double au_km; /* AU in km (from header) */
double emrat; /* Earth-Moon mass ratio */
int ncoeff; /* number of doubles per record */
int de_version; /* e.g. 441 */
/* Coefficient layout per body group */
de_body_layout layout[DE_NUM_BODIES];
/* Record buffer: re-used across queries */
double *record_buf; /* ncoeff doubles */
int cached_recno; /* which record is loaded, -1 = none */
/* Record geometry */
int record_bytes; /* ncoeff * sizeof(double) */
long data_offset; /* byte offset to first data record */
} de_handle;
/*
* Open and validate a JPL DE binary file.
*
* Returns a heap-allocated handle on success, NULL on failure.
* Sets *errcode to one of DE_OK / DE_ERR_*.
* Caller must eventually call de_reader_close().
*
* Does NOT use ereport() — caller translates error codes.
*/
de_handle *de_reader_open(const char *path, int *errcode);
/*
* Get the position of a body relative to a center.
*
* target: DE_MERCURY..DE_SUN (0-10)
* center: DE_SUN (10) for heliocentric, DE_EMB (2) for geocentric, etc.
* Use -1 for "raw" (no center subtraction)
* jd: Julian date (TDB)
* pos[3]: output position in AU (ICRS equatorial frame)
*
* Returns DE_OK on success, DE_ERR_* on failure.
*
* For Earth position: returns Earth (derived from EMB and Moon)
* For Moon position with center=Earth: returns geocentric Moon
*/
int de_reader_get_pos(de_handle *h, double jd, int target, int center,
double pos[3]);
/*
* Close the DE reader handle and free all resources.
* Safe to call with NULL handle.
*/
void de_reader_close(de_handle *h);
/*
* Look up a named constant from the DE header.
* Returns the value, or NAN if not found (use isnan() to check).
*/
double de_reader_get_const(de_handle *h, const char *name);
#endif /* PG_ORRERY_DE_READER_H */