@@ -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" ),
@@ -386,7 +392,7 @@ def _measureSources(self, science, matchedTemplate, difference, initialDiaSource
386392 streakInfo = self ._runStreakMasking (difference .maskedImage )
387393
388394 self .measureDiaSources (initialDiaSources , science , difference , matchedTemplate )
389- diaSources = self ._removeBadSources (initialDiaSources )
395+ diaSources , removedSources = self ._removeBadSources (initialDiaSources )
390396
391397 if self .config .doForcedMeasurement :
392398 self .measureForcedSources (diaSources , science , difference .getWcs ())
@@ -396,6 +402,7 @@ def _measureSources(self, science, matchedTemplate, difference, initialDiaSource
396402 measurementResults = pipeBase .Struct (
397403 subtractedMeasuredExposure = difference ,
398404 diaSources = diaSources ,
405+ removedSources = removedSources ,
399406 )
400407 if self .config .doMaskStreaks and self .config .writeStreakInfo :
401408 measurementResults .mergeItems (streakInfo , 'maskedStreaks' )
@@ -506,17 +513,33 @@ def _removeBadSources(self, diaSources):
506513 The updated catalog of detected sources, with any source that has a
507514 flag in ``config.badSourceFlags`` set removed.
508515 """
509- selector = np .ones (len (diaSources ), dtype = bool )
516+ bad_sources = np .zeros (len (diaSources ), dtype = bool )
510517 for flag in self .config .badSourceFlags :
511518 flags = diaSources [flag ]
512519 nBad = np .count_nonzero (flags )
513520 if nBad > 0 :
514521 self .log .debug ("Found %d unphysical sources with flag %s." , nBad , flag )
515- selector &= ~ flags
516- nBadTotal = np .count_nonzero (~ selector )
522+ bad_sources |= flags
523+ # Remove parents of bad children, and children of bad parents.
524+ # This is due to the measurement plugins, where it is assumed that
525+ # parent blends have all of their children in the catalog, and vice versa.
526+ parents = (
527+ (diaSources ["parent" ] == 0 )
528+ & (diaSources ["deblend_nChild" ] > 1 )
529+ & (~ diaSources ["deblend_skipped" ])
530+ )
531+ children = (diaSources ["parent" ] != 0 )
532+ parents_to_remove = np .unique (diaSources ["parent" ][children & bad_sources ])
533+ bad_parents = parents & bad_sources
534+ bad_parents |= np .in1d (diaSources ["id" ], parents_to_remove )
535+ children_to_remove = np .in1d (diaSources ["parent" ], diaSources ["id" ][bad_parents ])
536+ bad_children = (bad_sources & children ) | children_to_remove
537+ bad_sources |= bad_parents | bad_children
538+
539+ nBadTotal = np .count_nonzero (bad_sources )
517540 self .metadata .add ("nRemovedBadFlaggedSources" , nBadTotal )
518- self .log .info ("Removed %d unphysical sources." , nBadTotal )
519- return diaSources [selector ].copy (deep = True )
541+ self .log .info ("Removed %d unphysical sources and blends ." , nBadTotal )
542+ return diaSources [~ bad_sources ].copy (deep = True ), diaSources [ bad_sources ]
520543
521544 def addSkySources (self , diaSources , mask , seed ,
522545 subtask = None ):
0 commit comments