Skip to content

Commit 99822b6

Browse files
authored
Merge pull request #432 from lsst/tickets/DM-52435
DM-52435: Diffim bad mask plane handling
2 parents c37df83 + 5757ba3 commit 99822b6

File tree

3 files changed

+29
-17
lines changed

3 files changed

+29
-17
lines changed

python/lsst/ip/diffim/detectAndMeasure.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,13 @@ class DetectAndMeasureConfig(pipeBase.PipelineTaskConfig,
286286
dtype=str,
287287
doc="Sources with any of these flags set are removed before writing the output catalog.",
288288
default=("base_PixelFlags_flag_offimage",
289+
"base_PixelFlags_flag_edge",
289290
"base_PixelFlags_flag_interpolatedCenterAll",
290291
"base_PixelFlags_flag_badCenterAll",
291292
"base_PixelFlags_flag_edgeCenterAll",
292293
"base_PixelFlags_flag_nodataCenterAll",
293294
"base_PixelFlags_flag_saturatedCenterAll",
295+
"base_PixelFlags_flag_saturated_templateCenterAll",
294296
),
295297
)
296298
clearMaskPlanes = lsst.pex.config.ListField(
@@ -371,9 +373,7 @@ def setDefaults(self):
371373
self.detection.thresholdValue = 5.0
372374
self.detection.reEstimateBackground = False
373375
self.detection.thresholdType = "pixel_stdev"
374-
self.detection.excludeMaskPlanes = ["EDGE",
375-
"BAD",
376-
]
376+
self.detection.excludeMaskPlanes = []
377377

378378
# Copy configs for binned streak detection from the base detection task
379379
self.streakDetection.thresholdType = self.detection.thresholdType
@@ -416,9 +416,9 @@ def setDefaults(self):
416416

417417
# Keep track of which footprints contain streaks
418418
self.measurement.plugins["base_PixelFlags"].masksFpAnywhere = [
419-
"STREAK", "INJECTED", "INJECTED_TEMPLATE", "HIGH_VARIANCE"]
419+
"STREAK", "INJECTED", "INJECTED_TEMPLATE", "HIGH_VARIANCE", "SATURATED_TEMPLATE"]
420420
self.measurement.plugins["base_PixelFlags"].masksFpCenter = [
421-
"STREAK", "INJECTED", "INJECTED_TEMPLATE", "HIGH_VARIANCE"]
421+
"STREAK", "INJECTED", "INJECTED_TEMPLATE", "HIGH_VARIANCE", "SATURATED_TEMPLATE"]
422422
self.skySources.avoidMask = ["DETECTED", "DETECTED_NEGATIVE", "BAD", "NO_DATA", "EDGE"]
423423

424424
def validate(self):
@@ -963,6 +963,9 @@ def addSkySources(self, diaSources, mask, seed,
963963
"""
964964
if subtask is None:
965965
subtask = self.skySources
966+
if subtask.config.nSources <= 0:
967+
self.metadata[f"n_{subtask.getName()}"] = 0
968+
return
966969
skySourceFootprints = subtask.run(mask=mask, seed=seed, catalog=diaSources)
967970
self.metadata[f"n_{subtask.getName()}"] = len(skySourceFootprints)
968971

python/lsst/ip/diffim/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ def footprint_mean(sources, sky=0):
410410
else:
411411
sky_mean = np.nan
412412
sky_std = np.nan
413-
sky_difference = 0
413+
sky_difference = np.nanmedian(np.abs(difference.image.array))
414414
science_footprints, difference_footprints, ratio = footprint_mean(selectStars, sky_difference)
415415
return lsst.pipe.base.Struct(differenceFootprintRatioMean=ratio.mean(),
416416
differenceFootprintRatioStdev=ratio.std(),

tests/test_detectAndMeasure.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ def _check_values(self, values, minValue=None, maxValue=None):
111111
self.assertTrue(np.all(values <= maxValue))
112112

113113
def _setup_detection(self, doSkySources=True, nSkySources=5,
114-
doSubtractBackground=False, run_sattle=False, **kwargs):
114+
doSubtractBackground=False, run_sattle=False,
115+
badSourceFlags=None, **kwargs):
115116
"""Setup and configure the detection and measurement PipelineTask.
116117
117118
Parameters
@@ -143,12 +144,15 @@ def _setup_detection(self, doSkySources=True, nSkySources=5,
143144
detector=12,
144145
universe=lsst.daf.butler.DimensionUniverse(),
145146
)
147+
if badSourceFlags is None:
148+
badSourceFlags = ["base_PixelFlags_flag_offimage", ]
146149
config.idGenerator.packer.name = "observation"
147150
config.idGenerator.packer["observation"].n_observations = 10000
148151
config.idGenerator.packer["observation"].n_detectors = 99
149152
config.idGenerator.n_releases = 8
150153
config.idGenerator.release_id = 2
151154
config.doSubtractBackground = doSubtractBackground
155+
config.badSourceFlags = badSourceFlags
152156
self.idGenerator = config.idGenerator.apply(dataId)
153157

154158
return self.detectionTask(config=config)
@@ -542,8 +546,12 @@ def test_exclude_mask_detections(self):
542546
matchedTemplate, _ = makeTestImage(noiseLevel=noiseLevel/4, noiseSeed=7, **kwargs)
543547

544548
# Configure the detection Task
545-
detectionTask = self._setup_detection()
546-
excludeMaskPlanes = detectionTask.config.detection.excludeMaskPlanes
549+
badSourceFlags = ["base_PixelFlags_flag_offimage",
550+
"base_PixelFlags_flag_edgeCenterAll",
551+
"base_PixelFlags_flag_badCenterAll",
552+
"base_PixelFlags_flag_saturatedCenterAll", ]
553+
detectionTask = self._setup_detection(nSkySources=0, badSourceFlags=badSourceFlags)
554+
excludeMaskPlanes = ["EDGE", "BAD", "SAT"]
547555
nBad = len(excludeMaskPlanes)
548556
self.assertGreater(nBad, 0)
549557
kwargs["seed"] = transientSeed
@@ -563,10 +571,8 @@ def _detection_wrapper(setFlags=True):
563571
srcBbox = lsst.geom.Box2I(lsst.geom.Point2I(srcX - radius, srcY - radius),
564572
lsst.geom.Extent2I(2*radius + 1, 2*radius + 1))
565573
difference[srcBbox].mask.array |= lsst.afw.image.Mask.getPlaneBitMask(badMask)
566-
if setFlags:
567574
with self.assertRaises(AlgorithmError):
568575
output = detectionTask.run(science, matchedTemplate, difference, sources)
569-
return
570576
else:
571577
output = detectionTask.run(science, matchedTemplate, difference, sources)
572578
refIds = []
@@ -881,9 +887,7 @@ def test_detection_xy0(self):
881887

882888
self.assertImagesEqual(subtractedMeasuredExposure.image, difference.image)
883889

884-
# Not all of the sources will be detected: preconvolution results in
885-
# a larger edge mask, so we miss an edge source.
886-
self.assertEqual(len(output.diaSources), len(sources)-1)
890+
self.assertEqual(len(output.diaSources), len(sources))
887891
# no sources should be flagged as negative
888892
self.assertEqual(len(~output.diaSources["is_negative"]), len(output.diaSources))
889893
# TODO DM-41496: restore this block once we handle detections on edge
@@ -1103,13 +1107,19 @@ def test_exclude_mask_detections(self):
11031107
kwargs = {"seed": staticSeed, "psfSize": 2.4, "fluxLevel": fluxLevel}
11041108
science, sources = makeTestImage(noiseLevel=noiseLevel, noiseSeed=6, **kwargs)
11051109
science.getInfo().setVisitInfo(makeVisitInfo())
1110+
detector = DetectorWrapper(numAmps=1).detector
1111+
science.setDetector(detector)
11061112
matchedTemplate, _ = makeTestImage(noiseLevel=noiseLevel/4, noiseSeed=7, **kwargs)
11071113

11081114
subtractTask = subtractImages.AlardLuptonPreconvolveSubtractTask()
11091115
scienceKernel = science.psf.getKernel()
11101116
# Configure the detection Task
1111-
detectionTask = self._setup_detection()
1112-
excludeMaskPlanes = detectionTask.config.detection.excludeMaskPlanes
1117+
badSourceFlags = ["base_PixelFlags_flag_offimage",
1118+
"base_PixelFlags_flag_edgeCenterAll",
1119+
"base_PixelFlags_flag_badCenterAll",
1120+
"base_PixelFlags_flag_saturatedCenterAll", ]
1121+
detectionTask = self._setup_detection(nSkySources=0, badSourceFlags=badSourceFlags)
1122+
excludeMaskPlanes = ["EDGE", "BAD", "SAT"]
11131123
nBad = len(excludeMaskPlanes)
11141124
self.assertGreater(nBad, 0)
11151125
kwargs["seed"] = transientSeed
@@ -1133,7 +1143,6 @@ def _detection_wrapper(setFlags=True):
11331143
if setFlags:
11341144
with self.assertRaises(AlgorithmError):
11351145
output = detectionTask.run(science, matchedTemplate, difference, score, sources)
1136-
return
11371146
else:
11381147
output = detectionTask.run(science, matchedTemplate, difference, score, sources)
11391148
refIds = []

0 commit comments

Comments
 (0)