/* * 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 /* * 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 */