Skip to content

PIPE2D-1843: Update H4 NIR linearity and ISR#171

Open
CraigLoomis wants to merge 3 commits into
masterfrom
tickets/PIPE2D-1843
Open

PIPE2D-1843: Update H4 NIR linearity and ISR#171
CraigLoomis wants to merge 3 commits into
masterfrom
tickets/PIPE2D-1843

Conversation

@CraigLoomis

Copy link
Copy Markdown
Member

Summary

Three commits replacing most of the H4 NIR ISR path. See per-commit messages, especially the one covering isrTask.py

Test plan

  • scons clean (131 tests, lint clean)
  • reduceExposure.yaml#isr on 141370, 141526, 142109, 144220 × n1/n3/n4 in u/cpl/tickets/PIPE2D-1843_2026-06-03_03

Still need to following before this can be merged to master:

  • Datamodel ticket: add DEFECT, LINEARITY_DEFECT, UNSTABLE mask planes. These might get renamed.
  • Rest of new linearity fits in drp_pfs_data. n3 and n2 are in a test collection; still need to generate n1 and n4
  • Some other person's code review, at least of the isrTask.py changes.

CraigLoomis and others added 3 commits June 11, 2026 05:08
…ch detector

New ``python/lsst/obs/pfs/h4Linearity/`` package — the H4-specific NIR
ISR machinery. Cleanly separated from the rest of obs_pfs so the ISR
caller (``PfsIsrTask``) is the only thing that ties it into the
broader pipeline.

Subpackages:

  - ``types``        — bit-flag constants for the (H, W) uint16 internal
                       mask (BORDER_PIX, MASKED_BY_INPUT, INSUFFICIENT_
                       POINTS, FIT_FAILED, NON_MONOTONIC, ABOVE/BELOW_
                       VALID_RANGE, UNCLASSIFIED, UNSTABLE, ASIC_GLITCH,
                       HIGH_FIT_RESIDUAL, DEAD composite) + Ramp /
                       LinearizedRamp / Diagnostics / LinearityCorrection
                       dataclasses.
  - ``fit``          — per-pixel polynomial fit (default Chebyshev)
                       producing a LinearityCorrection plus
                       Diagnostics. Emits the fit-time bits above:
                       MASKED_BY_INPUT for caller defects, DEAD-group
                       for INSUFFICIENT_POINTS / FIT_FAILED /
                       NON_MONOTONIC, BORDER_PIX (alone) for the outer
                       4-pixel ring, HIGH_FIT_RESIDUAL when
                       residualRms > ``badLinearityMedianMultiplier``
                       × median(still-good residualRms). Per-pixel
                       ``saturationKnee`` detector uses a leave-one-out
                       median of the refDelta window so a cluster of
                       saturating early deltas cannot mask its own
                       neighbours.
  - ``apply``        — apply the fitted correction to a Ramp. ``apply``
                       takes the caller's internal mask as
                       ``Ramp.validMask``, preserves all incoming bits,
                       and skips the runtime > fitMax / < fitMin range
                       check on pixels already flagged (the
                       "first-reason-wins" rule). Returns a
                       LinearizedRamp with a uint16 badPixelMask
                       carrying calib + caller + range bits.
                       ``applyFrame`` handles single-frame CDS endpoints.
  - ``io``           — ``saveFits`` / ``loadFits`` (HDU layout: COEFFS,
                       LIMITS, BPM) + ``isH4LinearityFile`` predicate.
  - ``models``       — polynomial model classes (``PolynomialModel``,
                       chebyshev / monomial evaluators).
  - ``cr``           — iterative UTR-rate-based CR + ASIC-glitch
                       detector. Runs on a (H, W, N-1) delta cube,
                       does per-pixel IQR-σ + cumulative-drop checks,
                       classifies flagged deltas as CR / glitch pair /
                       boundary glitch / unclassified, and adds a
                       4σ-IQR outlier-count BAD-pixel gate (RTS /
                       telegraph-noise pixels). ``result.rate`` is the
                       UTR-weighted slope of the corrected ramp
                       (closed-form delta weights u[j] = 6(j+1)(N-1-j)
                       / (N(N-1)(N+1)), self-consistent fixed point).
                       ASIC-glitch repair is off by default — interior
                       pairs are detected so they don't masquerade as
                       CRs but left in place; end glitches and CRs are
                       repaired.
  - ``sim``          — programmable defect simulator (CRs, ASIC
                       glitches, ground-truth labels) used by the
                       test suite.
  - ``isrPlots``     — diagnostic plotting (per-pixel ramps,
                       half-vs-half rate comparisons, glitch histograms).
  - ``validate``     — top-level orchestration helpers (``processRamp``,
                       halves-vs-halves UTR-rate validator, summary
                       formatters). ``processRamp`` is a thin caller
                       of ``PfsIsrTask.makeNirExposure`` — single source
                       of CR detection + mask projection.
  - ``saturation``   — pixel-level saturation helpers.
  - ``loaders``      — butler-side loader plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Changes are all either to config knobs or to makeNirExposure and its callees.

The linearization package has been entirely replaced, and now runs on
the full ramp *before* artifact detection/repair/masking and the UTR
weighting.

CR/glitch/artifact processing is now done together, to give a better
chance to distinguish CRs from the rest. CRs are now detected per-pixel,
corrected and flagged by default. All the old ASIC glitch and CR
machinery has been removed.

Bad pixel flagging has been cleaned up: all pixels declared bad by
either the defect or linearization products are marked BAD in the
postISRCCD mask, and are also marked with DARK_DEFECT or LINEARITY_DEFECT
(requires a datamodel change). Pixels which fail various internal
tests (e.g. too many outliers from RTS/glitches) get marked BAD and
UNSTABLE (also requires the datamodel change). Detected ASIC-glitch
pixels are also masked BAD when at least one pair height clears
``h4.asicGlitchHeightMaskADU`` (default 0 → mask all).

Internally, after linearization, we convert from (N,H,W) flux to
(H,W,N) deltas once, and no longer have unnecessary flux<->delta
conversions in the normal code path.

The dark cube is now subtracted in place read-by-read, rather than
loading the entire ramp into memory first.

The logic for how to process standard inputs is codified in
rampParams(). Arcs and flats are processed as CDS, darks as UTR, and
science ramps as UTR but with the shutter-closed reads trimmed off.
The trimming is currently hard-coded (and correct for the current iic
sequencing), but once we have the header cards we expect to do that
correctly.

isrTask and makeNirExposure now support processing sub-ramps. isrTask
is controlled by isr:h4.firstRead and isr:h4.lastRead, defaulting to 0
and -1. Dark cube and linearity corrections are done to the correct
read and flux ranges. New header cards have been added to describe
the span. No use is made of that in this ticket, but PIPE2D-1844 does
require the feature.

Hoisted in the UTR variance update from PIPE2D-1778, adapted to the
new CDS-v-UTR and sub-ramp logic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test layer for the H4 NIR ISR refactor. Spread across the natural
boundaries:

  - test_h4LinearityFit.py    — fit() end-to-end: target recovery,
    deterministic tiling, input-mask propagation, multi-ramp,
    saturationKnee, HIGH_FIT_RESIDUAL, disabled path.
  - test_h4LinearityFitThreading.py — _resolveWorkerCount heuristics
    and worker-count-independent determinism for fit().
  - test_h4Linearity_apply.py — apply() / applyFrame() correctness
    including the "first-reason-wins" gating on internal mask bits.
  - test_h4LinearityIo.py     — round-trip saveFits / loadFits +
    isH4LinearityFile predicate.
  - test_polynomial.py        — per-pixel polynomial fit / evaluator.
  - test_h4CR.py              — iterative CR/glitch detector: CR vs
    glitch independence, cumulative-drop demotion, BAD-pixel outlier
    gate, RTS-flagged-vs-noise discrimination, repair semantics.
  - test_sim.py               — ramp defect simulator (CRs, ASIC
    glitches, ground-truth verification) used by test_h4CR.
  - test_h4_cube_semantics.py — pins the (H, W, N) layout end-to-end.
  - test_getDarkCube.py       — getDarkCube + subtractDarkCube
    indexing, gain handling, partial-ramp r0 offset.
  - test_calcUTRrates.py      — calcUTRWeights / calcUTRrates +
    delta-space calcUTRrateFromDeltas equivalence + a three-way
    cross-check pinning calcUTRrates, calcUTRrateFromDeltas, and the
    CR detector's IterativeRepairResult.rate as numerically tied on
    a clean ramp.
  - test_isrHeaderKeys.py     — _stampRampMetadata writes the
    expected H4READ* / H4NREAD / H4NTOT / H4UTRWT keys; plus
    coverage for the new _makeInternalMask + _projectInternalMask
    helpers (border → BAD only, DARK_DEFECT, LINEARITY_DEFECT, SAT,
    UNSTABLE projection rule, ASIC_GLITCH internal bit → BAD only).
  - test_validate_processRamp.py — processRamp wires the requested
    knobs into makeNirExposure and reads crResult back via
    intermediates.
  - conftest.py — smallSyntheticRamp / tinyLinearRamp fixtures used
    by the fit + threading tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@CraigLoomis CraigLoomis force-pushed the tickets/PIPE2D-1843 branch from 583c0c6 to d3865d4 Compare June 11, 2026 15:09
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.

2 participants