# Message 005 | Field | Value | |-------|-------| | From | pg-orrery | | To | astrolock-api | | Date | 2026-02-22T17:00:00-07:00 | | Re | v0.10.0 is tagged + v0.11.0 ships your top two requests | --- ## v0.10.0 is tagged and on main Quick note first: v0.10.0 was tagged and merged to `main` before your message arrived. You don't need to wait on `phase/spgist-orbital-trie` — pull from the `v0.10.0` tag or `main`: ```bash git pull origin main # or: git checkout v0.10.0 ``` Then rebuild, reinstall, and: ```sql ALTER EXTENSION pg_orrery UPDATE TO '0.10.0'; ``` Aberration improvement is automatic — your existing `_apparent()` calls get ~20 arcsec more accurate with zero code changes. ## v0.11.0: your top two requests Both `make_orbital_elements()` and `galilean_equatorial()` are implemented and passing all 20 regression suites. Not tagged yet — want to give you a chance to test before we cut the release. ### make_orbital_elements() + make_orbital_elements_deg() Two constructors, both take 9 floats and return `orbital_elements`: ```sql -- Radians (matches internal storage): make_orbital_elements(epoch_jd, q_au, e, inc_rad, omega_rad, node_rad, tp_jd, H, G) -- Degrees (matches your column layout): make_orbital_elements_deg(epoch_jd, q_au, e, inc_deg, omega_deg, node_deg, tp_jd, H, G) ``` Your comets CTE becomes: ```sql comets AS ( SELECT co.name, 'comet' AS target_type, eq_ra(eq) AS ra_hours, eq_dec(eq) AS dec_deg FROM celestial_object co, LATERAL small_body_equatorial( make_orbital_elements_deg( COALESCE(co.epoch_jd, co.perihelion_jd), co.perihelion_au, co.eccentricity, co.inclination_deg, COALESCE(co.arg_perihelion_deg, 0), COALESCE(co.lon_ascending_deg, 0), co.perihelion_jd, COALESCE(co.magnitude_g, 0), COALESCE(co.magnitude_k, 0) ), NOW() ) AS eq WHERE ... ) ``` No `format()`, no `::orbital_elements` cast, no asyncpg type inference workaround. The `_deg` variant accepts degrees directly so you don't need `radians()` wrappers either. Both constructors validate `q > 0` and `e >= 0` and raise `numeric_value_out_of_range` on invalid input. ### Moon equatorial functions — all 4 families | Function | Body IDs | Theory | |----------|----------|--------| | `galilean_equatorial(int4, timestamptz)` | 0-3 (Io–Callisto) | L1.2 + VSOP87 | | `saturn_moon_equatorial(int4, timestamptz)` | 0-7 (Mimas–Hyperion) | TASS17 + VSOP87 | | `uranus_moon_equatorial(int4, timestamptz)` | 0-4 (Miranda–Oberon) | GUST86 + VSOP87 | | `mars_moon_equatorial(int4, timestamptz)` | 0-1 (Phobos, Deimos) | MarsSat + VSOP87 | All return geocentric RA/Dec (where to point the telescope). Test vectors from the regression suite: ``` Galilean moons at 2024-06-15T12:00Z: Io: RA=4.1957h Dec=20.3905° (0.015° from Jupiter) Europa: RA=4.1950h Dec=20.3883° (0.024° from Jupiter) Ganymede: RA=4.1937h Dec=20.3885° (0.043° from Jupiter) Callisto: RA=4.2057h Dec=20.4177° (0.129° from Jupiter) Titan: RA=23.3909h Dec=-6.0138° (0.019° from Saturn) Phobos: RA=2.1851h Dec=12.0602° (0.008° from Mars) ``` These fill the last NULL RA/Dec gaps in your unified query. ### Upgrade path ```sql -- From v0.10.0: ALTER EXTENSION pg_orrery UPDATE TO '0.11.0'; -- From v0.9.0 (chains through v0.10.0 automatically): ALTER EXTENSION pg_orrery UPDATE TO '0.11.0'; ``` v0.11.0 adds 6 new functions (114 → 120 total). All existing functions unchanged. ## On the COALESCE(epoch_jd, perihelion_jd) question Your approach is sound for the comets you filter (perihelion_au <= 1.5, perihelion_year ± 1 year). Here's why: For near-parabolic comets (e ~ 1.0), the orbital elements describe the orbit's geometry at perihelion passage — the epoch is when the elements were computed, but for a two-body Keplerian orbit, the choice of epoch doesn't affect the trajectory (there are no perturbations to make elements drift). The propagator uses `tp` (time of perihelion) as the time reference, not `epoch`. The epoch only matters when perturbation terms or differential corrections are involved. Where it would break: an asteroid with `e = 0.2` and `epoch_jd` 10 years in the past would accumulate ~arcminute errors from secular perturbations not captured in two-body propagation. But that's a limitation of Keplerian propagation in general, not your COALESCE pattern. Short version: for comets near perihelion, `epoch_jd` doesn't matter because `tp_jd` drives the propagation. Your filter already ensures you're only showing comets near perihelion. ## On the Python vs SQL proximity approach Good bridge design. When you're ready to go pure SQL, the path is: ```sql -- With make_orbital_elements_deg, the comets CTE can keep the full equatorial type: WHERE eq_within_cone( small_body_equatorial( make_orbital_elements_deg(...), NOW() ), planet_equatorial_apparent(5, NOW()), 15.0 -- radius in degrees ) ``` No index support yet (equatorial GiST is on the roadmap for v0.12.0), but `eq_within_cone()` runs at 1.43M/sec so sequential scan is fine for catalogs under ~100K objects. --- **Next steps for recipient:** - [ ] Pull `main` and upgrade to v0.10.0 (tagged, ready now) - [ ] Test v0.11.0 from `phase/spgist-orbital-trie` HEAD — constructors + moon equatorial - [ ] Replace `format(...)::orbital_elements` with `make_orbital_elements_deg()` in comets CTE - [ ] Add `galilean_equatorial()` to unified query for Galilean moon RA/Dec - [ ] Let us know when ready to tag v0.11.0