What
Add a config-selectable UberSeg neighbour treatment to the ngmix module, alongside the current noise-fill, and decide how the segmentation map reaches the per-epoch stamps.
Today a neighbour sharing a galaxy's postage stamp is handled by filling the neighbour's pixels with noise (prepare_ngmix_weights): the per-epoch flag vignet marks them and they are replaced by a Gaussian realisation before the stamp reaches ngmix. The 2026-06-23 tomography call flagged this as suspect — including blended (FLAGS=2) objects produces B-modes, while discarding them is a strong, non-metacalibratable selection bias. UberSeg (Sheldon's MEDS/ngmix treatment) is the principled alternative: mask (weight → 0) every stamp pixel closer to a neighbour than to the central object, rather than synthesising noise over it.
Implementation status
The option is implemented additively, default unchanged, in PR #770:
BLEND_HANDLING = {noisefill, uberseg}, default noisefill, read like CENTROID_SOURCE. With the default the behaviour is byte-for-byte identical to today (asserted in tests).
uberseg_weight(weight, seg, object_number) reimplements Sheldon's meds._uberseg.uberseg_tree nearest-segment Voronoi partition with a scipy cKDTree. We reimplement rather than depend on meds: the astronomy MEDS is esheldon/meds (not the PyPI meds, which is an unrelated package), and import meds drags the full fitsio/esutil stack for a single C tree. The surviving central core is a single connected, roughly circular region — emergent geometry of the partition, faithful to MEDS get_uberseg (no separate circular aperture).
- Plumbed runner →
Ngmix → do_ngmix_metacal → make_ngmix_observation → prepare_ngmix_weights; Postage_stamp gains a per-epoch segs list.
- Unit tests: synthetic two-object stamp (mask geometry, single-connected core, matches brute-force nearest-segment), noisefill byte-identity, uberseg leaves the image untouched while hard-masking the weight.
⚠️ Open decision — the segmentation-map source
UberSeg needs the segmentation map with object IDs at each stamp, plus the central object's NUMBER. ShapePipe passes only a binary flag vignet to ngmix today, cut per-exposure (multi-epoch). The segmentation map with NUMBERs is the coadd's (the tile SExtractor detection) — but ngmix fits per-epoch exposure stamps, in different pixel frames. MEDS itself resolves this by interpolating the coadd seg into each single-epoch frame (interpolate_coadd_seg). So the source is genuinely forked:
- Extend
vignetmaker to cut a coadd SEGMENTATION vignet (the tile SExtractor already has the CHECKIMAGE machinery; it currently emits only BACKGROUND) and reproject it into each epoch frame via the per-epoch WCS — Sheldon-faithful, but needs nearest-neighbour resampling of an integer seg map.
- Approximate from the existing per-epoch binary flag vignet — no reprojection, but the binary flag carries no per-object IDs, so the "closer to neighbour than to central" distance transform cannot be computed faithfully (it conflates neighbours with cosmic rays / bad pixels).
PR #770 implements everything not gated by this (the algorithm, the BLEND_HANDLING plumbing, the consumption seam, the unit tests); selecting uberseg without a seg map raises with a pointer here. This decision wants the shape-measurement experts (Axel Guinot, Martin Kilbinger, Fabian Hervas Peters): which seg source, and is per-epoch reprojection of the coadd seg the right path?
Science note for the A/B validation
Following the explicit design intent (and Axel's "leave neighbour objects on the image" proposal), the uberseg path zeroes the weight and leaves the image untouched — it does not noise-fill the masked region. The open consideration: metacal shears the image in Fourier space using all pixels regardless of weight, so residual neighbour flux can leak through the shear even at weight 0. This is exactly what the noise-fill-vs-uberseg A/B B-mode comparison (on a FLAGS=2-inclusive sample, via the Paper II / sp_validation B-mode machinery) must measure — and what Axel's weight-symmetrisation follow-on (out of scope here) would address. Fabian validates the science before any production default flip.
Scope fence
Add the option, its tests, the consumption seam; resolve the seg source; then validate. Not in scope: changing the noise-fill path, flipping the production default, the weight-symmetrisation / cosmic-ray-only-noise refinement, or the get_noise-vs-sigma_mad noise-estimate question (that belongs with #769).
Implemented (un-gated parts) by PR #770 (Closes #776). Part of ShapePipe longer-term improvements (#773) — not blocking the ngmix v2.0 merge.
— Claude, on behalf of Cail
What
Add a config-selectable UberSeg neighbour treatment to the ngmix module, alongside the current noise-fill, and decide how the segmentation map reaches the per-epoch stamps.
Today a neighbour sharing a galaxy's postage stamp is handled by filling the neighbour's pixels with noise (
prepare_ngmix_weights): the per-epoch flag vignet marks them and they are replaced by a Gaussian realisation before the stamp reaches ngmix. The 2026-06-23 tomography call flagged this as suspect — including blended (FLAGS=2) objects produces B-modes, while discarding them is a strong, non-metacalibratable selection bias. UberSeg (Sheldon's MEDS/ngmix treatment) is the principled alternative: mask (weight → 0) every stamp pixel closer to a neighbour than to the central object, rather than synthesising noise over it.Implementation status
The option is implemented additively, default unchanged, in PR #770:
BLEND_HANDLING = {noisefill, uberseg}, defaultnoisefill, read likeCENTROID_SOURCE. With the default the behaviour is byte-for-byte identical to today (asserted in tests).uberseg_weight(weight, seg, object_number)reimplements Sheldon'smeds._uberseg.uberseg_treenearest-segment Voronoi partition with a scipycKDTree. We reimplement rather than depend onmeds: the astronomy MEDS isesheldon/meds(not the PyPImeds, which is an unrelated package), andimport medsdrags the fullfitsio/esutilstack for a single C tree. The surviving central core is a single connected, roughly circular region — emergent geometry of the partition, faithful to MEDSget_uberseg(no separate circular aperture).Ngmix→do_ngmix_metacal→make_ngmix_observation→prepare_ngmix_weights;Postage_stampgains a per-epochsegslist.UberSeg needs the segmentation map with object IDs at each stamp, plus the central object's NUMBER. ShapePipe passes only a binary flag vignet to ngmix today, cut per-exposure (multi-epoch). The segmentation map with NUMBERs is the coadd's (the tile SExtractor detection) — but ngmix fits per-epoch exposure stamps, in different pixel frames. MEDS itself resolves this by interpolating the coadd seg into each single-epoch frame (
interpolate_coadd_seg). So the source is genuinely forked:vignetmakerto cut a coaddSEGMENTATIONvignet (the tile SExtractor already has theCHECKIMAGEmachinery; it currently emits onlyBACKGROUND) and reproject it into each epoch frame via the per-epoch WCS — Sheldon-faithful, but needs nearest-neighbour resampling of an integer seg map.PR #770 implements everything not gated by this (the algorithm, the
BLEND_HANDLINGplumbing, the consumption seam, the unit tests); selectingubersegwithout a seg map raises with a pointer here. This decision wants the shape-measurement experts (Axel Guinot, Martin Kilbinger, Fabian Hervas Peters): which seg source, and is per-epoch reprojection of the coadd seg the right path?Science note for the A/B validation
Following the explicit design intent (and Axel's "leave neighbour objects on the image" proposal), the
ubersegpath zeroes the weight and leaves the image untouched — it does not noise-fill the masked region. The open consideration: metacal shears the image in Fourier space using all pixels regardless of weight, so residual neighbour flux can leak through the shear even at weight 0. This is exactly what the noise-fill-vs-uberseg A/B B-mode comparison (on aFLAGS=2-inclusive sample, via the Paper II / sp_validation B-mode machinery) must measure — and what Axel's weight-symmetrisation follow-on (out of scope here) would address. Fabian validates the science before any production default flip.Scope fence
Add the option, its tests, the consumption seam; resolve the seg source; then validate. Not in scope: changing the noise-fill path, flipping the production default, the weight-symmetrisation / cosmic-ray-only-noise refinement, or the
get_noise-vs-sigma_madnoise-estimate question (that belongs with #769).Implemented (un-gated parts) by PR #770 (
Closes #776). Part of ShapePipe longer-term improvements (#773) — not blocking the ngmix v2.0 merge.— Claude, on behalf of Cail