Skip to content

Commit f6dbdc0

Browse files
committed
Remove parents and children of bad sources
1 parent 99c06bf commit f6dbdc0

2 files changed

Lines changed: 31 additions & 7 deletions

File tree

python/lsst/ip/diffim/detectAndMeasure.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ class DetectAndMeasureConnections(pipeBase.PipelineTaskConnections,
7676
storageClass="SourceCatalog",
7777
name="{fakesType}{coaddName}Diff_diaSrc",
7878
)
79+
badSources = pipeBase.connectionTypes.Output(
80+
doc="Sources and blends removed from the diaSources catalog.",
81+
dimensions=("instrument", "visit", "detector"),
82+
storageClass="SourceCatalog",
83+
name="{fakesType}{coaddName}Diff_diaSrc_removedSources",
84+
)
7985
subtractedMeasuredExposure = pipeBase.connectionTypes.Output(
8086
doc="Difference image with detection mask plane filled in.",
8187
dimensions=("instrument", "visit", "detector"),
@@ -382,7 +388,7 @@ def _measureSources(self, science, matchedTemplate, difference, initialDiaSource
382388
streakInfo = self._runStreakMasking(difference.maskedImage)
383389

384390
self.measureDiaSources(initialDiaSources, science, difference, matchedTemplate)
385-
diaSources = self._removeBadSources(initialDiaSources)
391+
diaSources, removedSources = self._removeBadSources(initialDiaSources)
386392

387393
if self.config.doForcedMeasurement:
388394
self.measureForcedSources(diaSources, science, difference.getWcs())
@@ -392,6 +398,7 @@ def _measureSources(self, science, matchedTemplate, difference, initialDiaSource
392398
measurementResults = pipeBase.Struct(
393399
subtractedMeasuredExposure=difference,
394400
diaSources=diaSources,
401+
removedSources=removedSources,
395402
)
396403
if self.config.doMaskStreaks and self.config.writeStreakInfo:
397404
measurementResults.mergeItems(streakInfo, 'maskedStreaks')
@@ -502,17 +509,33 @@ def _removeBadSources(self, diaSources):
502509
The updated catalog of detected sources, with any source that has a
503510
flag in ``config.badSourceFlags`` set removed.
504511
"""
505-
selector = np.ones(len(diaSources), dtype=bool)
512+
bad_sources = np.zeros(len(diaSources), dtype=bool)
506513
for flag in self.config.badSourceFlags:
507514
flags = diaSources[flag]
508515
nBad = np.count_nonzero(flags)
509516
if nBad > 0:
510517
self.log.debug("Found %d unphysical sources with flag %s.", nBad, flag)
511-
selector &= ~flags
512-
nBadTotal = np.count_nonzero(~selector)
518+
bad_sources |= flags
519+
# Remove parents of bad children, and children of bad parents.
520+
# This is due to the measurement plugins, where it is assumed that
521+
# parent blends have all of their children in the catalog, and vice versa.
522+
parents = (
523+
(diaSources["parent"] == 0)
524+
& (diaSources["deblend_nChild"] > 1)
525+
& (~diaSources["deblend_skipped"])
526+
)
527+
children = (diaSources["parent"] != 0)
528+
parents_to_remove = np.unique(diaSources["parent"][children & bad_sources])
529+
bad_parents = parents & bad_sources
530+
bad_parents |= np.in1d(diaSources["id"], parents_to_remove)
531+
children_to_remove = np.in1d(diaSources["parent"], diaSources["id"][bad_parents])
532+
bad_children = (bad_sources & children) | children_to_remove
533+
bad_sources |= bad_parents | bad_children
534+
535+
nBadTotal = np.count_nonzero(bad_sources)
513536
self.metadata.add("nRemovedBadFlaggedSources", nBadTotal)
514-
self.log.info("Removed %d unphysical sources.", nBadTotal)
515-
return diaSources[selector].copy(deep=True)
537+
self.log.info("Removed %d unphysical sources and blends.", nBadTotal)
538+
return diaSources[~bad_sources].copy(deep=True), diaSources[bad_sources]
516539

517540
def addSkySources(self, diaSources, mask, seed,
518541
subtask=None):

tests/test_detectAndMeasure.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,9 @@ def test_remove_unphysical(self):
247247
badDiaSrc = ~bbox.contains(diaSources.getX(), diaSources.getY())
248248
nBad = np.count_nonzero(badDiaSrc)
249249
self.assertEqual(nBad, nSetBad)
250-
diaSourcesNoBad = detectionTask._removeBadSources(diaSources)
250+
diaSourcesNoBad, removedSources = detectionTask._removeBadSources(diaSources)
251251
badDiaSrcNoBad = ~bbox.contains(diaSourcesNoBad.getX(), diaSourcesNoBad.getY())
252+
self.assertEqual(len(removedSources), nSetBad)
252253

253254
# Verify that no sources outside the image bounding box remain
254255
self.assertEqual(np.count_nonzero(badDiaSrcNoBad), 0)

0 commit comments

Comments
 (0)