/* * moon_funcs.c -- Planetary moon observation * * SQL functions for observing moons of Jupiter, Saturn, Uranus, and Mars. * Each moon's position is computed in the VSOP87 ecliptic J2000 frame * relative to its parent planet, then combined with the parent's * heliocentric position to get geocentric az/el. * * Pipeline for each moon: * 1. Parent planet heliocentric position (VSOP87) * 2. Moon position relative to parent (L12/TASS17/GUST86/MARSSAT) * 3. Moon heliocentric = parent + moon_relative * 4. Moon geocentric = moon_heliocentric - Earth_heliocentric * 5. Ecliptic -> equatorial -> precess -> az/el */ #include "postgres.h" #include "fmgr.h" #include "funcapi.h" #include "utils/timestamp.h" #include "types.h" #include "astro_math.h" #include "vsop87.h" #include "l12.h" #include "tass17.h" #include "gust86.h" #include "marssat.h" #include PG_FUNCTION_INFO_V1(galilean_observe); PG_FUNCTION_INFO_V1(saturn_moon_observe); PG_FUNCTION_INFO_V1(uranus_moon_observe); PG_FUNCTION_INFO_V1(mars_moon_observe); /* * observe_from_geocentric() is now in astro_math.h as a static inline, * shared by planet_funcs.c, moon_funcs.c, and de_funcs.c. */ /* ================================================================ * Internal: common pattern for all planetary moons * * Given: moon position relative to parent (VSOP87 ecliptic J2000, AU) * parent's VSOP87 body index (0-based) * observer, JD * * Computes geocentric position and returns topocentric az/el. * ================================================================ */ static void observe_planetary_moon(const double moon_rel[3], int vsop_parent, double jd, const pg_observer *obs, pg_topocentric *result) { double parent_xyz[6]; double earth_xyz[6]; double geo_ecl[3]; /* Parent planet heliocentric */ GetVsop87Coor(jd, vsop_parent, parent_xyz); /* Earth heliocentric */ GetVsop87Coor(jd, 2, earth_xyz); /* VSOP87 body 2 = Earth */ /* Moon geocentric = (parent + moon_relative) - Earth */ geo_ecl[0] = (parent_xyz[0] + moon_rel[0]) - earth_xyz[0]; geo_ecl[1] = (parent_xyz[1] + moon_rel[1]) - earth_xyz[1]; geo_ecl[2] = (parent_xyz[2] + moon_rel[2]) - earth_xyz[2]; observe_from_geocentric(geo_ecl, jd, obs, result); } /* ================================================================ * galilean_observe(body_id int, observer, timestamptz) -> topocentric * * Observe a Galilean moon of Jupiter. * Body IDs: 0=Io, 1=Europa, 2=Ganymede, 3=Callisto * * Uses L1.2 theory (Lainey, Duriez & Vienne) for moon positions * and VSOP87 for Jupiter and Earth. * ================================================================ */ Datum galilean_observe(PG_FUNCTION_ARGS) { int32 body_id = PG_GETARG_INT32(0); pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(1); int64 ts = PG_GETARG_INT64(2); double jd; double moon_xyz[3]; pg_topocentric *result; if (body_id < L12_IO || body_id > L12_CALLISTO) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("galilean_observe: body_id %d must be 0-3 (Io, Europa, Ganymede, Callisto)", body_id))); jd = timestamptz_to_jd(ts); /* Moon position relative to Jupiter, VSOP87 ecliptic J2000, AU */ GetL12Coor(jd, body_id, moon_xyz, NULL); result = (pg_topocentric *) palloc(sizeof(pg_topocentric)); observe_planetary_moon(moon_xyz, 4, jd, obs, result); /* VSOP87 body 4 = Jupiter */ PG_RETURN_POINTER(result); } /* ================================================================ * saturn_moon_observe(body_id int, observer, timestamptz) -> topocentric * * Observe a moon of Saturn. * Body IDs: 0=Mimas, 1=Enceladus, 2=Tethys, 3=Dione, * 4=Rhea, 5=Titan, 6=Iapetus, 7=Hyperion * * Uses TASS 1.7 theory (Vienne & Duriez). * ================================================================ */ Datum saturn_moon_observe(PG_FUNCTION_ARGS) { int32 body_id = PG_GETARG_INT32(0); pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(1); int64 ts = PG_GETARG_INT64(2); double jd; double moon_xyz[3]; pg_topocentric *result; if (body_id < TASS17_MIMAS || body_id > TASS17_HYPERION) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("saturn_moon_observe: body_id %d must be 0-7 (Mimas-Hyperion)", body_id))); jd = timestamptz_to_jd(ts); GetTass17Coor(jd, body_id, moon_xyz, NULL); result = (pg_topocentric *) palloc(sizeof(pg_topocentric)); observe_planetary_moon(moon_xyz, 5, jd, obs, result); /* VSOP87 body 5 = Saturn */ PG_RETURN_POINTER(result); } /* ================================================================ * uranus_moon_observe(body_id int, observer, timestamptz) -> topocentric * * Observe a moon of Uranus. * Body IDs: 0=Miranda, 1=Ariel, 2=Umbriel, 3=Titania, 4=Oberon * * Uses GUST86 theory (Laskar & Jacobson). * ================================================================ */ Datum uranus_moon_observe(PG_FUNCTION_ARGS) { int32 body_id = PG_GETARG_INT32(0); pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(1); int64 ts = PG_GETARG_INT64(2); double jd; double moon_xyz[3]; pg_topocentric *result; if (body_id < GUST86_MIRANDA || body_id > GUST86_OBERON) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("uranus_moon_observe: body_id %d must be 0-4 (Miranda-Oberon)", body_id))); jd = timestamptz_to_jd(ts); GetGust86Coor(jd, body_id, moon_xyz, NULL); result = (pg_topocentric *) palloc(sizeof(pg_topocentric)); observe_planetary_moon(moon_xyz, 6, jd, obs, result); /* VSOP87 body 6 = Uranus */ PG_RETURN_POINTER(result); } /* ================================================================ * mars_moon_observe(body_id int, observer, timestamptz) -> topocentric * * Observe a moon of Mars. * Body IDs: 0=Phobos, 1=Deimos * * Uses MarsSat theory (Lainey, 2007). * ================================================================ */ Datum mars_moon_observe(PG_FUNCTION_ARGS) { int32 body_id = PG_GETARG_INT32(0); pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(1); int64 ts = PG_GETARG_INT64(2); double jd; double moon_xyz[3]; pg_topocentric *result; if (body_id < MARS_SAT_PHOBOS || body_id > MARS_SAT_DEIMOS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("mars_moon_observe: body_id %d must be 0-1 (Phobos, Deimos)", body_id))); jd = timestamptz_to_jd(ts); GetMarsSatCoor(jd, body_id, moon_xyz, NULL); result = (pg_topocentric *) palloc(sizeof(pg_topocentric)); observe_planetary_moon(moon_xyz, 3, jd, obs, result); /* VSOP87 body 3 = Mars */ PG_RETURN_POINTER(result); }