Skip to content

feat: Keck NIRC2 AO reduction (phase 4) — KOA acquire, ground stages, nirc2_native combine, provisional PSF - #12

Merged
Jammy2211 merged 2 commits into
mainfrom
feature/keck-ao-reduction
Jul 9, 2026
Merged

feat: Keck NIRC2 AO reduction (phase 4) — KOA acquire, ground stages, nirc2_native combine, provisional PSF#12
Jammy2211 merged 2 commits into
mainfrom
feature/keck-ao-reduction

Conversation

@Jammy2211

Copy link
Copy Markdown
Contributor

feat: Keck NIRC2 AO reduction (phase 4) — KOA acquire, ground stages, nirc2_native combine, provisional PSF

Implements phases K1–K3 of the design on #9 (research task) per #11, on the post-phase-3 consolidated layout (#10). SHARP-grounded (Lagattuta et al. 2012; Chen et al. 2016, 2019); decisions adopted from #9's batched set: drizzle-package combine backend, B1938+666 validation anchor.

What's new

  • Acquire-backend seam: InstrumentAdapter.archive (mast | koa); acquire/koa.py (PyKOA TAP) fetches raw level-0 science frames, the night's darks (ITIME/COADDS-matched) + flats (nearest flat-bearing night within ±14 days when the science night has none — routine for NIR), PSF-star frames, and the epoch-matched NIRC2 distortion solution (Yelda 2010 / Service 2016 lookup tables from the canonical jluastro/nirc2_distortion distribution, checksummed into provenance). Components self-heal independently on cached re-runs.
  • Ground pre-combine stages: calibrate/ (DN→e⁻, optional matched dark, lamp-on−lamp-off flat, hot/dead bad-pixel mask → NaN → zero drizzle weight) and sky/ (scaled running sky: unit-median structure from object-masked temporally adjacent frames × the frame's own masked median, two passes — kills the edge-of-sequence bias of a plain running median under a drifting K′ sky).
  • nirc2_native combine backend: distortion + phase-correlation registration + native→final rescale as one drizzle pixmap through the standalone drizzle package (same engine as drizzlepac/jwst-resample), per-frame weights = inverse background variance → the weight map is the IVM the unchanged shared noise recipe (noise.rms.noise_map_from, same Casertano R) expects. 10 mas narrow / 40 mas wide final scales (SHARP convention).
  • Provisional-PSF contract: tier A reduces PSF-star epochs (MJD-gap grouping) pipeline-identically and ships every epoch as psf_candidate_<i>.fits (final selection belongs to modelling — SHARP I's evidence-based practice); psf.fits cut from the sharpest epoch; psf_provisional: true in provenance. Tier B (in-field ePSF) also flagged provisional on keck.
  • Design doc: docs/design/keck_ao.md (per-stage deltas, detector constants, open items: wide camera, subarrays, MULTISAM read noise, north-up resampling) — closes the parked write leg of research: plan the Keck NIRC2 AO reduction workflow (SHARP context) #9. Roadmap + AGENTS.md updated.
  • Deps: keck = ["pykoa>=1.7", "drizzle>=2.0"] extra. AGENTS.md test-boundary note: the lightweight drizzle resampler is sanctioned in unit tests behind importorskip (drizzlepac/jwst stack still excluded).

Validation — B1938+666 (SHARP I discovery data)

prototypes/b1938_keck_spike.py: KOA discovery found the actual SHARP I dataset (program U085N2L, UT 2010-06-29/30; 39×180s lens frames; PSF/tip-tilt star pointings at 20″ interleaved in time, exactly as published). Acceptance checks (keck_ao.md):

Acceptance check Result
Blank-sky noise closure (empirical x R^2 / predicted) 0.883 (bounds 0.6-1.6)
Per-frame noise budget, MCDS-32 62.0 e- predicted vs 62-64 e- empirical
PSF candidate FWHM (SHARP reports ~65-70 mas) 72 mas; 4 CR-dominated epochs auto-rejected by diffraction-floor vetting
WHT uniformity over cutout 0.084 < 0.2
Dataset 39 x 180 s lens frames; PSF/tt-star pointings at 20" interleaved, per Lagattuta+12

Acceptance items 3-4 (astrometric parity vs HST; end-to-end PyAutoLens Einstein-radius invariance) follow as their own prompt once this dataset enters a modelling run.

Tests

110 pass in the task worktree (24 new Keck tests). Downstream suites n/a — nothing imports autoreduce. Smoke n/a — no workspace script surface.

Unit tests are numpy/astropy(+drizzle-behind-importorskip) synthetic-frame tests: calibrate math, scaled-sky recovery under drift, sub-pixel registration convention, flux conservation + EXPTIME through the pixmap, noise closure with the read-noise-dominated NIRC2 budget, epoch grouping + candidate selection, loud-failure paths (wide camera, mixed setups, garbage flats).

Review + gate

Review faculty: 8 angles -> 30 candidates -> 10 verified findings, 9 fixed in the second commit (epoch-aware sky grouping, tier-B saturation cut, pointing-coherence guard, portable provenance, distortion-epoch guards, adapter detector boundary, stale-candidate hygiene); 1 deferred as documented keck_ao.md open items. Post-fix verdict CLEAN. Heart YELLOW (6 chronic organism reasons, none touching this repo) acknowledged by the maintainer at sign-off ("ship + merge", 2026-07-09). --auto supervised run; human-directed ship and merge.

🤖 Generated with Claude Code

Jammy2211 and others added 2 commits July 9, 2026 15:15
… nirc2_native combine, provisional PSF

Implements K1-K3 of the design on #9 (per #11), on the post-phase-3 layout:

- acquire-backend seam (archive: mast|koa); acquire/koa.py fetches raw
  level-0 science + ITIME/COADDS-matched darks + nearest-night flats
  (+/-14 d) + PSF-star frames + epoch-matched distortion solutions
  (Yelda 2010 / Service 2016, checksummed), self-healing on re-runs
- ground stages: calibrate/ (DN->e-, dark, lamp-on-off flat, bad pixels)
  and sky/ (scaled running sky, 2 passes — drift-unbiased)
- nirc2_native combine: distortion + phase-correlation registration +
  rescale as one drizzle pixmap; IVM weights make the shared noise
  recipe apply verbatim (same Casertano R)
- sampling-mode-aware read noise (MCDS/Fowler: RN_cds/sqrt(MULTISAM));
  per-frame budget validated on SHARP B1938 K' (62.0 vs 62-64 e-)
- provisional-PSF contract: tier-A PSF-star epochs, coherence +
  diffraction-floor vetting (rejects cosmic-ray epochs), every surviving
  epoch shipped as psf_candidate_<i>.fits, psf_provisional provenance
- docs/design/keck_ao.md (closes the #9 write leg) + roadmap + AGENTS.md
- validated end-to-end on the SHARP I B1938+666 discovery data (U085N2L):
  closure 0.841, PSF FWHM 72 mas, WHT uniformity 0.084, 39x180 s

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ovenance

Review faculty pass (8 angles, 30 candidates -> 10 verified findings, 9 fixed):

- sky windows now split at time gaps (nights / PSF-star visits); single-frame
  recipe moved into the sky module; shared mad_sigma helper
- keck tier-B ePSF regains the per-exposure saturation cut
- KOA acquire: pointing-coherence guard (the footprint-filter analogue),
  distortion-epoch boundary guard, lower(koaimtyp) normalisation
- nirc2_combine: per-frame distortion consistency check, distortion-derived
  grid margin, hoisted mgrid; detector constants now adapter-routed
  (roadmap boundary rule: nothing outside instruments/ names a detector)
- provenance: absolute distortion paths dropped from reduction.json; stale
  psf_candidate files cleared on any keck re-run; candidates in products
- re-validated on B1938+666: closure 0.883, PSF FWHM 72 mas, 110 tests pass

Deferred to keck_ao.md open items: orchestrator dispatch generalisation,
prepared-header schema, header-GAIN cross-check, FWHM unification.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant