@@ -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 ):
0 commit comments