Listening for events…

GW Skymap Cross-Match Sweep (v2) — Scope + Frozen Settings

Status: FROZEN 2026-06-16 (Mike chose the standard multimessenger coincidence model) · Owner: Mike + Claude (engine room) Parent: docs/scope-gravitational-wave-eventdex.md (the gw kind), docs/event-spine-framework.md, and the v2 cosmic cross-match (8022a0b, where gw was held out with an honest null because it needs skymaps). This brick supplies the skymaps and closes that gap.

This is the GW skymap sweep: give each gravitational-wave event a real spatial cross-match against the other two cosmic messengers (high-energy neutrinos, ultra-high-energy cosmic rays) using the GW's probabilistic sky localization, not a point. A GW is not a point on the sky; it is a HEALPix probability map. The sweep asks, for each GW: did a neutrino or a cosmic ray arrive from inside this event's 90% credible region (and, for neutrinos, at the right time)?

It does not create a new kind. It enriches the existing gw dossiers with a cited cross_match block, the same enrich-in-place move the tornado/NCEI merge used.

The coincidence model — LOAD-BEARING, FROZEN by Mike 2026-06-16: standard multimessenger

A GW skymap gives a sky region + a merger time. The two messengers differ in what is testable:

  • Neutrino arm (space AND time): a neutrino associates with a GW iff its arrival direction lies inside the GW's 90% credible region AND its arrival time is within ±1000 s of the GW merger. This is the established GW+neutrino search window (the IceCube-170922A / GW follow-up standard): a real astrophysical neutrino from a compact-object merger arrives essentially simultaneously, so the tight time gate is physical and crushes the false-coincidence rate.
  • UHECR arm (space ONLY): a cosmic ray associates iff its arrival direction lies inside the GW's 90% credible region. No time gate — a UHECR is magnetically deflected and arrives delayed by potentially millions of years, so its arrival time carries no information about the GW merger time. Every UHECR spatial association is therefore flagged "suggestive": a coincident direction with no time link is weak by construction, and the paper voice must say so.
  • Credible level: 90% for both arms.

(The rejected alternatives were spatial-only-for-both, which inflates chance coincidences over a decade of data, and a stringent 50%/±500 s neutrino-only window, which Mike did not pick.)

Measured-reality — IN (skymap is a localization, not a forecast)

A GW skymap is a Bayesian localization of a real, detected event — the posterior over where on the sky the measured strain came from, exactly analogous to an earthquake epicenter inverted from measured seismograms (which TerraPulse already ships). It is an estimate of where a thing that physically happened came from, not a forecast of something that might happen. Under the bright line ([[feedback_measured_reality_only]]) it is IN, the same standing as the gw events themselves, the neutrino detections, and the UHECR arrival directions. Nothing here is model output in the forecast/projection sense.

The three layers (verified in PG16, 2026-06-16)

Layer Source slug Position Time Notes
GW (spine) gwosc_eventsgw dossiers (431 census events) HEALPix skymap (fetch from GWOSC) merger GPS time → UTC no point in PG; localization is the skymap
Neutrino icecube_neutrinos (IceCat-1, 348 events) extra_json ra_deg/dec_deg (equatorial) arrival UTC filter out AutoSense probe stubs mixed into the source; keep only real events with ra/dec
UHECR auger_uhecr (131 events) extra_json ra_deg/dec_deg (equatorial) arrival UTC the latitude/longitude columns are the Auger site (−35.2/−69.3), NOT the arrival direction — use extra_json

All three positions are equatorial (RA/Dec, J2000/ICRS), the same frame as the GWOSC skymaps, so no galactic conversion is needed.

Skymaps (the new data — fetch from GWOSC)

GW localizations ship as HEALPix FITS (bayestar/PE skymaps) via GWOSC. For each published gw event, fetch its skymap (curl; httpx hangs against these hosts in this environment), cache under data/gw_skymap_cache/, read with healpy+astropy (clean py3.13 wheels confirmed). The 90% credible region is the smallest set of HEALPix pixels whose summed probability reaches 0.90; a sky position is "inside" iff its pixel is in that set.

Fetch bound (frozen): the neutrino arm pre-filters on time first — only GW events with a neutrino within ±1000 s need a skymap for the neutrino test, which is a handful, so those skymaps are always fetched. The UHECR arm is spatial-only and therefore needs every GW skymap; fetching all ~431 is the heavy part and is what makes this a full brick rather than a quick add. If a skymap is unavailable for an event, that event is recorded as skymap: "unavailable" and excluded from the spatial test, never silently counted as a null.

What a GW slot gains (cited block)

Each gw dossier keeps its existing fields and gains:

  • sources extended to cite the matched messenger catalogs.
  • A cross_match block:
    • credible_level: 0.90, skymap: {source, nside, region_area_deg2, status}.
    • neutrino_associations: [...] — each with the IceCat-1 event id, ra/dec, dt_seconds from merger, inside_90, and passed (inside AND |dt|≤1000 s).
    • uhecr_associations: [...] — each with the Auger event id, ra/dec, energy, inside_90, flag: "suggestive" (spatial-only).
    • n_neutrino_assoc, n_uhecr_assoc, and an honest verdict string.

The expectation, stated up front, is a near-total null (this is why v2 held GW out): a real GW×neutrino temporal+spatial coincidence would be a landmark detection. The value is the honest all-sky search with real localizations, and any spatial UHECR hits reported as suggestive only.

Build bricks

  • Brick A — freeze. THIS DOC (2026-06-16): enrich-in-place on the gw kind, the FROZEN standard-multimessenger coincidence model (neutrino space+time ±1000 s, UHECR space-only, 90% credible), measured-reality IN, the three verified layers + their position gotchas, GWOSC skymap fetch + 90%-region test, cited cross_match block, honest-null expectation.
  • Brick B — neutrino arm DONE (definitive null); UHECR arm logic built, skymaps pending. 2026-06-16: installed healpy 1.19 + astropy 8.0 (clean py3.13 wheels); src/terrapulse/monitor/gw_skymap_sweep.py loads the 348 real IceCat-1 neutrinos (probe stubs excluded) and 115 Auger UHECR directions (ra/dec from extra_json). The neutrino arm is a definitive null with no skymaps required: ZERO of 348 neutrinos fall within ±1000 s of any of the 431 GW events, so there is nothing to localize, the v2 "gw held out" gap is now closed for the real GW+neutrino channel. The UHECR spatial test (point_in_credible_region, healpy 90% region) is implemented and unit-tested. Remaining: the UHECR arm is spatial-only and needs EVERY GW 90% region; GWOSC has no per-event skymap URL (the eventapi lists strain, not skymaps), so the maps come from the per-catalog Zenodo releases (GWTC-2.1/3) plus GraceDB for the 2025 O4 events. That bulk acquisition is the one focused step left; until it runs, the UHECR arm is honestly pending_skymap (never a silent null).
  • Brick C/D — enrich + verify. 2026-06-16: enrich_all folded the cited cross_match block into all 431 gw dossiers (sources now cite gwosc + neutrino + uhecr). 6 unit tests (synthetic-skymap region test + downgrade/normalize loader, temporal gate, verdict shapes).
  • Brick E — UHECR arm RUN (skymaps acquired) — CLEAN NULL. 2026-06-16 (scripts/acquire_gw_skymaps.py): GWOSC has no per-event skymap URL, but each event carries a GraceDB id in its per-event eventapi detail (the catalog list omits it), and GraceDB serves small flattened skymaps publicly. Resolved every confident event to its GraceDB id and pulled the best flattened FITS (PE preferred over bayestar), 312 of 410 confident events (76%) — the 98 misses are O1/O2 events (GraceDB events-API doesn't serve their skymaps; they live in the GWTC-1 release) and a few with no public skymap, all honestly pending_skymap, never silent nulls. Maps downgraded to nside=256 and .npy-cached. Result: a clean null.
    • Neutrino arm: 0 (unchanged definitive null).
    • UHECR arm: 60 null, 225 chance_consistent, 24 excess_poor_localization (a Poisson excess over a uniform-sky baseline, but in regions >100 deg² — an artifact of UHECR sky anisotropy, Auger's southern exposure + the known dipole, not a GW link), and only 3 suggestive (a single UHECR each in a well-localized <100 deg² region: GW240915_001357, GW241127_061008, GW200208_130117). Across the 28 well-localized events the chance-expected total is ~2.8, so 3 singles ≈ chance: no significant GW×UHECR association.
    • Honest verdict (engine room): clean null on both arms. A UHECR spatial overlap is only meaningful in a well-localized region (local UHECR density ≈ global); the cross_match block therefore carries region_area_deg2, localization, chance_expected, and excess_over_chance so every overlap is self-contextualizing, and suggestive is gated on a Poisson 2σ excess AND good localization.
  • First report: deferred (a real association would change that overnight). Engine room.
  • Minor follow-on: the ~11 O1/O2 GWTC-1 skymaps (e.g. GW170817) could be added from the GWTC-1 DCC release tarball to push coverage past 76%; low value (2-detector events are poorly localized).
Live Feed