Source code for xlens.process_pipe.detect_multiband

import lsst.afw.math as afwMath
import lsst.afw.table as afwTable
import lsst.pipe.base.connectionTypes as cT
from lsst.meas.algorithms import DynamicDetectionTask
from lsst.meas.base import SkyMapIdGeneratorConfig
from lsst.pex.config import ConfigurableField
from lsst.pipe.base import (
    PipelineTask,
    PipelineTaskConfig,
    PipelineTaskConnections,
    Struct,
)


[docs] class DetectCoaddSourcesConnections( PipelineTaskConnections, dimensions=("tract", "patch", "band", "skymap"), defaultTemplates={"inputCoaddName": "deep", "outputCoaddName": "deep"}, ):
[docs] detectionSchema = cT.InitOutput( doc="Schema of the detection catalog", name="{outputCoaddName}Coadd_det_schema", storageClass="SourceCatalog", )
[docs] exposure = cT.Input( doc="Exposure post detection", name="{outputCoaddName}Coadd_calexp", storageClass="ExposureF", dimensions=("tract", "patch", "band", "skymap"), )
[docs] outputBackgrounds = cT.Output( doc="Output Backgrounds used in detection", name="{outputCoaddName}Coadd_calexp_background", storageClass="Background", dimensions=("tract", "patch", "band", "skymap"), )
[docs] outputSources = cT.Output( doc="Detected sources catalog", name="{outputCoaddName}Coadd_det", storageClass="SourceCatalog", dimensions=("tract", "patch", "band", "skymap"), )
[docs] class DetectCoaddSourcesConfig( PipelineTaskConfig, pipelineConnections=DetectCoaddSourcesConnections ): """Configuration parameters for the DetectCoaddSourcesTask"""
[docs] detection = ConfigurableField( target=DynamicDetectionTask, doc="Source detection", )
[docs] idGenerator = SkyMapIdGeneratorConfig.make_field()
[docs] def setDefaults(self): super().setDefaults() self.detection.thresholdType = "pixel_stdev" self.detection.isotropicGrow = True # Coadds are made from background-subtracted CCDs, so any background # subtraction should be very basic self.detection.reEstimateBackground = False self.detection.background.useApprox = False self.detection.background.binSize = 4096 self.detection.background.undersampleStyle = "REDUCE_INTERP_ORDER" # Suppress large footprints that overwhelm the deblender self.detection.doTempWideBackground = True # Include band in packed data IDs that go into object IDs (None -> "as # many bands as are defined", rather than the default of zero). self.idGenerator.packer.n_bands = None
[docs] class DetectCoaddSourcesTask(PipelineTask): """Detect sources on a single filter coadd. Coadding individual visits requires each exposure to be warped. This introduces covariance in the noise properties across pixels. Before detection, we correct the coadd variance by scaling the variance plane in the coadd to match the observed variance. This is an approximate approach -- strictly, we should propagate the full covariance matrix -- but it is simple and works well in practice. After scaling the variance plane, we detect sources and generate footprints by delegating to the @ref SourceDetectionTask_ "detection" subtask. DetectCoaddSourcesTask is meant to be run after assembling a coadded image in a given band. The purpose of the task is to update the background, detect all sources in a single band and generate a set of parent footprints. Subsequent tasks in the multi-band processing procedure will merge sources across bands and, eventually, perform forced photometry. Parameters ---------- schema : `lsst.afw.table.Schema`, optional Initial schema for the output catalog, modified-in place to include all fields set by this task. If None, the source minimal schema will be used. **kwargs Additional keyword arguments. """
[docs] _DefaultName = "detectCoaddSources"
[docs] ConfigClass = DetectCoaddSourcesConfig
def __init__(self, schema=None, **kwargs): super().__init__(**kwargs) if schema is None: schema = afwTable.SourceTable.makeMinimalSchema()
[docs] self.schema = schema
self.makeSubtask("detection", schema=self.schema)
[docs] self.detectionSchema = afwTable.SourceCatalog(self.schema)
[docs] def runQuantum(self, butlerQC, inputRefs, outputRefs): inputs = butlerQC.get(inputRefs) idGenerator = self.config.idGenerator.apply(butlerQC.quantum.dataId) inputs["idFactory"] = idGenerator.make_table_id_factory() inputs["expId"] = idGenerator.catalog_id outputs = self.run(**inputs) butlerQC.put(outputs, outputRefs) return
[docs] def run(self, exposure, idFactory, expId): """Run detection on an exposure. First scale the variance plane to match the observed variance using ``ScaleVarianceTask``. Then invoke the ``SourceDetectionTask_`` "detection" subtask to detect sources. Parameters ---------- exposure : `lsst.afw.image.Exposure` Exposure on which to detect (may be backround-subtracted and scaled, depending on configuration). idFactory : `lsst.afw.table.IdFactory` IdFactory to set source identifiers. expId : `int` Exposure identifier (integer) for RNG seed. Returns ------- result : `lsst.pipe.base.Struct` Results as a struct with attributes: ``sources`` Catalog of detections (`lsst.afw.table.SourceCatalog`). ``backgrounds`` List of backgrounds (`list`). """ backgrounds = afwMath.BackgroundList() table = afwTable.SourceTable.make(self.schema, idFactory) detections = self.detection.run(table, exposure, expId=expId) sources = detections.sources if hasattr(detections, "background") and detections.background: for bg in detections.background: backgrounds.append(bg) return Struct(outputSources=sources, outputBackgrounds=backgrounds)