quality_control.qc_flags

class kpfpipe.quality_control.qc_flags.QC(kpf_obj)

Bases: object

Base runner for per-level pass/fail QC check methods.

Parameters:

kpf_obj (KPFDataModel) – Finished data product whose QUALITY_CONTROL header receives the 0/1 flags.

LEVEL = None
run()

Run all checks, write each 0/1 result, and aggregate ISGOOD.

Resets self.results at the start so calling run() repeatedly on the same instance is deterministic.

Returns:

Maps each FITS keyword to its (passed, comment) pair (this level’s checks only). ISGOOD is the cross-level aggregate (see below).

Return type:

dict

class kpfpipe.quality_control.qc_flags.QCL0(kpf_obj)

Bases: QC

QC checks for KPF Level 0 raw data products.

LEVEL = 'L0'
data_l0_red_green()

Raw CCD data present: each of GREEN/RED is a supported amp readout.

KPF reads out either 2 or 4 amplifiers per chip, so the expected amp count is inferred from the data rather than fixed: a chip passes when the number of present, non-empty amplifier extensions is a supported readout mode (_SUPPORTED_NAMP), mirroring ImageAssembly.count_amplifiers. This accepts both 2-amp and 4-amp frames and rejects a chip with no data or a partial/invalid amp set (1 or 3). Absent amps are stored as array(None, dtype=object) and skipped – the same present-amp scan QCL1 uses for read noise.

exptime_sane()

EXPTIME present, finite, non-negative, and consistent with ELAPSED.

Bias frames legitimately have EXPTIME=0, so we don’t require strictly positive. When the raw ELAPSED readout time is present, it must not fall short of the requested EXPTIME (premature readout) or exceed it by more than _TIME_TOL_S (the elapsed-vs-requested check formerly done in the masters frame loader); an absent ELAPSED skips only that comparison.

header_keywords_present()

Required PRIMARY keywords exist.

not_junk()

obs_id not on the observer junk list for this frame’s data tree.

“Junk” is a manual observer flag (e.g. the wrong telescope settings) that no automated QC can catch. The list lives at {KPF_DATA_INPUT}/vNext/reference/junk_obs.csv; KPF_DATA_INPUT is recovered from the frame’s own source directory, which rvdata records as self.dirname ({KPF_DATA_INPUT}/L0/{datecode}) when the L0 is read. An absent list or unknown source dir yields not-junk.

radec_consistent()

Pointing agrees with the target and catalog positions.

Thresholds the DiagL0 offsets on QUALITY_CONTROL: TARGOFF < 1”, and the catalog cross-matches OBJOFF/GAIAOFF < 5” (a loose bound, since the loaded pointing coordinates are not Gaia/SIMBAD-derived). Each offset is checked only when present, so a frame with no pointing (e.g. a calibration frame) or a skipped catalog lookup passes.

times_consistent()

DATE-BEG < DATE-MID < DATE-END and |(END-BEG) - ELAPSED| < 0.1 s.

Ports v2.12 L2_datetime. At L0 the raw instrument times live on the WMKO-native PRIMARY (the header later snapshotted verbatim into INSTRUMENT_HEADER at to_kpf1); the 0/1 flag then propagates downstream on QUALITY_CONTROL. Passes the duration check when ELAPSED is absent – only the present cards are checked.

class kpfpipe.quality_control.qc_flags.QCL1(kpf_obj)

Bases: QC

QC checks for KPF Level 1 assembled FFI products.

LEVEL = 'L1'
bias_ok()

Bias subtracted (RECEIPT BIASSUB) and master bias age <= 7 days.

dark_ok()

Dark subtracted (RECEIPT DARKSUB) and master dark age <= 14 days.

data_present()

GREEN_CCD and RED_CCD exist and are non-empty.

ffi_finite()

All values in GREEN_CCD and RED_CCD are finite.

flat_ok()

Flat divided (RECEIPT FLATDIV) and master flat age <= 30 days.

read_noise_nongauss_ok()

Every per-amp non-Gaussian read noise present is in [0.8, 1.5].

read_noise_ok()

Every per-amp read noise present is in [2.0, 6.0] e-.

required_keywords_present()

Every registry-required PRIMARY keyword for L1 is present (presence only).

class kpfpipe.quality_control.qc_flags.QCL2(kpf_obj)

Bases: QC

QC checks for KPF Level 2 extracted spectra products.

LEVEL = 'L2'
extraction_present()

All expected {CHIP}_{FIBER}_FLUX extensions exist and are non-empty.

flux_finite_fraction()

NaN count from headers <= 1% of total L2 flux pixels.

nonzero_flux()

ZEROFRAC < 0.5.

required_keywords_present()

Every registry-required PRIMARY keyword for L2 is present (presence only).

science_snr()

Science SNR is finite and above a minimum floor.

Reads the GSNRSCI/RSNRSCI metrics written by DiagL2.snr (run DiagL2 before QCL2, mirroring the flux_finite_fraction -> nan_counts dependency). Guards against a silently failed extraction.

variance_positive()

No strictly-negative variance where the flux is finite.

A negative extracted variance is unphysical (box/optimal variance is a sum of non-negative terms) and would corrupt downstream RV weighting. Zero variance at off-detector / fully-masked columns is tolerated.

class kpfpipe.quality_control.qc_flags.QCL4(kpf_obj)

Bases: QC

QC checks for KPF Level 4 RV/CCF products.

LEVEL = 'L4'
berv_within_tolerance()

Per-order BERV deviation within +/-1% of the weighted mean.

Ports v2.12 L2_barycentric_rv_percent_change, reading BERVMAXP / BERVMINP written by DiagL4 (run DiagL4 before QCL4). Passes when the metrics are absent (e.g. a calibration frame with no science RV) – there is nothing to flag.

ccf_rv_present()

Each science orderlet has a non-empty CCF cube and computed RVs.

Both stages of the split must have run: CrossCorrelation writes the CCF cube and seeds the RV table (with NaN RV/RV_ERR), and RadialVelocity fills the RV column. A seeded-but-unfilled table (CrossCorrelation without a following RadialVelocity) fails here, since the RVs are the L4 product.

required_keywords_present()

Every registry-required PRIMARY keyword for L4 is present (presence only).

Submodules

base

QC framework base class.

level0

QC checks for KPF Level 0 (raw CCD) data products.

level1

QC checks for KPF Level 1 (assembled FFI) data products.

level2

QC checks for KPF Level 2 (extracted spectra) data products.

level4

QC checks for KPF Level 4 (RVs and CCFs) data products.