Skip to content

Masking unification: external healsparse masks throughout ShapePipe #845

Description

@cailmdaley

Goal. Replace ShapePipe's internal mask generation (GSC-2.3 star halos/spikes rasterized by WeightWatcher, Messier/NGC patches — THELI-vintage, cf. #15) with the external healsparse masks produced by the maskforce pipeline (Hendrik / Ludo / Mike), used from the beginning of the pipeline — including for PSF star selection. One mask system, inserted early, instead of parallel internal and external masks reconciled at the catalogue stage. The old code stays config-selectable until a real-data comparison validates the switch (#850).

Consensus (Slack #weak-lensing-tomography thread, 2026-07-14 → 07-16, Cail / Mike / Axel; Martin in person):

  • Use the maskforce healsparse masks from the start, including for PSF star selection — stars in bright-star halos contaminate the PSF model, and PSFEx outlier rejection alone shouldn't be relied on.
  • healsparse resolution (nside 131072, pixel scale ≈ 1.6″) is sufficient and more conservative than pixel-level masking: a thin defect inflated to the pixel size masks more, not less.
  • maximask is probably unnecessary: saturation / bleeding / bad columns are easy to flag at the single-exposure level, and cosmic rays are handled by Stephen's masking (visually OK).
  • Star halo/spike scaling should be revisited; the current maskforce code may scale these automatically. Quantitative check: tangential shear around bright stars (Validate bright-star mask sizes via tangential shear around stars #851).

Axel's architecture proposal (thread reply, 2026-07-16 — answers the previously-open exposure-level question):

  • Pixel-level masks belong at the single-exposure level, because that's where measurement (PSF, shapes) happens. Per-exposure composition: bad pixels + cosmic rays from Stephen's preprocessing, plus updated bright-star spikes/halos, plus bright nearby objects, potentially bleeding/saturation.
  • Catalogue-level: healsparse as now, but only bright objects + stars — and prefer healsparse's polygon functionality (DS9 regions → HS polygons, effectively infinite resolution) over rasterized bitmaps. (In tension with the coarse-is-conservative argument above — to reconcile.)
  • The tile-level mask input to SExtractor may be droppable: SExtractor only propagates flags into the catalogue without changing its measurements, so tile flags are redundant with catalogue-level masking. (Note: tile flags currently also feed post-detection consumers — verify in Old-vs-new mask comparison on real data (tiles + exposures) #850 before dropping.)
  • Exposure-level healsparse masks can be created per exposure and combined, so masking is computed once in the loop. Mike had proposed the reverse (reproject tile-level maps onto exposures). Either way Consume external healsparse masks: rasterize to pipeline flag images + per-band catalogue flags #847's artifact contract (rasterize healsparse → pipeline_flag FITS through the image WCS) is unchanged; what differs is which healsparse file it reads.

Mask provenance — pinned down (2026-07-16). Ludo assembled pixel/FITS masks tile-by-tile → Mike converted them to healsparse with Healsparse_mask_pool.py (nside 131072, conservatively fattened). The 2025 all-band products at arc:home/mhudson/masks/ are boolean healsparse maps, one file per bit: mask_ugriz_nside131072_n<bit>.hsp. Documented reason bits (script header): 1 faint star halo / 2 bright star halo / 4 bright stars / 8 manual mask / 1024 maximask; 512 = out-of-bounds. Empirical bit check (P3 region, 200k random points): OR{1,2,4,8,64,1024} — Mike's default bitmask 0b10001001111 — reproduces mask_r_nside131072.hsp exactly. So the 2025 series is a per-bit decomposition of the same masking used for the r product (and the r masking is unchanged Oct 2024 → May 2025 in that region — a partial currency answer). The per-band reading floated earlier (16_u/32_g/64_r/128_i/256_z/2048_z2 as band masks) is contradicted: 64 is a reason bit (undocumented in the header — meaning needs Mike), and 16/32/128/256 behave like per-band coverage flags (n128 = 100% of the P3 region, where i-band is absent; n256 = 71%; n2048 empty). No integer bit-flag product exists anywhere — the r-band map on candide (/n17data/UNIONS/WL/masks/mask_r_nside131072.hsp) is the same bool flavour. All files are mirrored to Nibi (~/projects/def-mjhudson/cdaley/masks/). Open for Mike: meaning of bit 64, semantics of 16/32/128/256/2048 (coverage vs mask), and currency of the 2025 products.

Plan. The sub-issues below carry the work. Implementation of the ShapePipe consumer is #847; the old-vs-new comparison gate is #850; mask-size validation is #851.

— Fable, on behalf of Cail

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions