lsst.ip.diffim g8b71addb3a+52a9b18b5a
Loading...
Searching...
No Matches
Classes | Variables
lsst.ip.diffim.detectAndMeasure Namespace Reference

Classes

class  DetectAndMeasureConnections
 

Variables

 expId : `int`
 
 expBits : `int`
 
 idFactory : `lsst.afw.table.IdFactory`
 
 science : `lsst.afw.image.ExposureF`
 
 matchedTemplate : `lsst.afw.image.ExposureF`
 
 difference : `lsst.afw.image.ExposureF`
 
 measurementResults : `lsst.pipe.base.Struct`
 
 sources : `lsst.afw.table.SourceCatalog`
 
 positiveFootprints : `lsst.afw.detection.FootprintSet`, optional
 
 negativeFootprints : `lsst.afw.detection.FootprintSet`, optional
 
 table : `lsst.afw.table.SourceTable`
 
 diaSources : `lsst.afw.table.SourceCatalog`
 
 mask : `lsst.afw.image.Mask`
 
 seed : `int`
 
 wcs : `lsst.afw.geom.SkyWcs`
 
 scoreExposure : `lsst.afw.image.ExposureF`
 

Variable Documentation

◆ diaSources

lsst.ip.diffim.detectAndMeasure.diaSources : `lsst.afw.table.SourceCatalog`
if self.config.doMerge:
    fpSet = positiveFootprints
    fpSet.merge(negativeFootprints, self.config.growFootprint,
                self.config.growFootprint, False)
    diaSources = afwTable.SourceCatalog(table)
    fpSet.makeSources(diaSources)
    self.log.info("Merging detections into %d sources", len(diaSources))
else:
    diaSources = sources

if self.config.doSkySources:
    self.addSkySources(diaSources, difference.mask, difference.info.id)

self.measureDiaSources(diaSources, science, difference, matchedTemplate)

if self.config.doForcedMeasurement:
    self.measureForcedSources(diaSources, science, difference.getWcs())

measurementResults = pipeBase.Struct(
    subtractedMeasuredExposure=difference,
    diaSources=diaSources,
)

return measurementResults

def addSkySources(self, diaSources, mask, seed):
skySourceFootprints = self.skySources.run(mask=mask, seed=seed)
if skySourceFootprints:
    for foot in skySourceFootprints:
        s = diaSources.addNew()
        s.setFootprint(foot)
        s.set(self.skySourceKey, True)

def measureDiaSources(self, diaSources, science, difference, matchedTemplate):
# Note that this may not be correct if we convolved the science image.
# In the future we may wish to persist the matchedScience image.
self.measurement.run(diaSources, difference, science, matchedTemplate)
if self.config.doApCorr:
    apCorrMap = difference.getInfo().getApCorrMap()
    if apCorrMap is None:
        self.log.warning("Difference image does not have valid aperture correction; skipping.")
    else:
        self.applyApCorr.run(
            catalog=diaSources,
            apCorrMap=apCorrMap,
        )

def measureForcedSources(self, diaSources, science, wcs):

Definition at line 381 of file detectAndMeasure.py.

◆ difference

lsst.ip.diffim.detectAndMeasure.difference : `lsst.afw.image.ExposureF`

Definition at line 290 of file detectAndMeasure.py.

◆ expBits

lsst.ip.diffim.detectAndMeasure.expBits : `int`

Definition at line 246 of file detectAndMeasure.py.

◆ expId

lsst.ip.diffim.detectAndMeasure.expId : `int`
doMerge = pexConfig.Field(
    dtype=bool,
    default=True,
    doc="Merge positive and negative diaSources with grow radius "
        "set by growFootprint"
)
doForcedMeasurement = pexConfig.Field(
    dtype=bool,
    default=True,
    doc="Force photometer diaSource locations on PVI?")
doAddMetrics = pexConfig.Field(
    dtype=bool,
    default=False,
    doc="Add columns to the source table to hold analysis metrics?"
)
detection = pexConfig.ConfigurableField(
    target=SourceDetectionTask,
    doc="Final source detection for diaSource measurement",
)
measurement = pexConfig.ConfigurableField(
    target=DipoleFitTask,
    doc="Task to measure sources on the difference image.",
)
doApCorr = lsst.pex.config.Field(
    dtype=bool,
    default=True,
    doc="Run subtask to apply aperture corrections"
)
applyApCorr = lsst.pex.config.ConfigurableField(
    target=ApplyApCorrTask,
    doc="Task to apply aperture corrections"
)
forcedMeasurement = pexConfig.ConfigurableField(
    target=ForcedMeasurementTask,
    doc="Task to force photometer science image at diaSource locations.",
)
growFootprint = pexConfig.Field(
    dtype=int,
    default=2,
    doc="Grow positive and negative footprints by this many pixels before merging"
)
diaSourceMatchRadius = pexConfig.Field(
    dtype=float,
    default=0.5,
    doc="Match radius (in arcseconds) for DiaSource to Source association"
)
doSkySources = pexConfig.Field(
    dtype=bool,
    default=False,
    doc="Generate sky sources?",
)
skySources = pexConfig.ConfigurableField(
    target=SkyObjectsTask,
    doc="Generate sky sources",
)
idGenerator = DetectorVisitIdGeneratorConfig.make_field()

def setDefaults(self):
    # DiaSource Detection
    self.detection.thresholdPolarity = "both"
    self.detection.thresholdValue = 5.0
    self.detection.reEstimateBackground = False
    self.detection.thresholdType = "pixel_stdev"
    self.detection.excludeMaskPlanes = ["EDGE"]

    # Add filtered flux measurement, the correct measurement for pre-convolved images.
    self.measurement.algorithms.names.add('base_PeakLikelihoodFlux')
    self.measurement.plugins.names |= ['ext_trailedSources_Naive',
                                       'base_LocalPhotoCalib',
                                       'base_LocalWcs',
                                       'ext_shapeHSM_HsmSourceMoments',
                                       'ext_shapeHSM_HsmPsfMoments',
                                       ]
    self.measurement.slots.psfShape = "ext_shapeHSM_HsmPsfMoments"
    self.measurement.slots.shape = "ext_shapeHSM_HsmSourceMoments"
    self.measurement.plugins["base_NaiveCentroid"].maxDistToPeak = 5.0
    self.measurement.plugins["base_SdssCentroid"].maxDistToPeak = 5.0
    self.forcedMeasurement.plugins = ["base_TransformedCentroid", "base_PsfFlux"]
    self.forcedMeasurement.copyColumns = {
        "id": "objectId", "parent": "parentObjectId", "coord_ra": "coord_ra", "coord_dec": "coord_dec"}
    self.forcedMeasurement.slots.centroid = "base_TransformedCentroid"
    self.forcedMeasurement.slots.shape = None

    # Keep track of which footprints contain streaks
    self.measurement.plugins['base_PixelFlags'].masksFpAnywhere = ['STREAK']
    self.measurement.plugins['base_PixelFlags'].masksFpCenter = ['STREAK']


class DetectAndMeasureTask(lsst.pipe.base.PipelineTask):
ConfigClass = DetectAndMeasureConfig
_DefaultName = "detectAndMeasure"

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.schema = afwTable.SourceTable.makeMinimalSchema()
    # Add coordinate error fields:
    afwTable.CoordKey.addErrorFields(self.schema)

    self.algMetadata = dafBase.PropertyList()
    self.makeSubtask("detection", schema=self.schema)
    self.makeSubtask("measurement", schema=self.schema,
                     algMetadata=self.algMetadata)
    if self.config.doApCorr:
        self.makeSubtask("applyApCorr", schema=self.measurement.schema)
    if self.config.doForcedMeasurement:
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_instFlux", "D",
            "Forced PSF flux measured on the direct image.",
            units="count")
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_instFluxErr", "D",
            "Forced PSF flux error measured on the direct image.",
            units="count")
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_area", "F",
            "Forced PSF flux effective area of PSF.",
            units="pixel")
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_flag", "Flag",
            "Forced PSF flux general failure flag.")
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_flag_noGoodPixels", "Flag",
            "Forced PSF flux not enough non-rejected pixels in data to attempt the fit.")
        self.schema.addField(
            "ip_diffim_forced_PsfFlux_flag_edge", "Flag",
            "Forced PSF flux object was too close to the edge of the image to use the full PSF model.")
        self.makeSubtask("forcedMeasurement", refSchema=self.schema)

    self.schema.addField("refMatchId", "L", "unique id of reference catalog match")
    self.schema.addField("srcMatchId", "L", "unique id of source match")
    if self.config.doSkySources:
        self.makeSubtask("skySources")
        self.skySourceKey = self.schema.addField("sky_source", type="Flag", doc="Sky objects.")

    # initialize InitOutputs
    self.outputSchema = afwTable.SourceCatalog(self.schema)
    self.outputSchema.getTable().setMetadata(self.algMetadata)

# TODO: remove on DM-38687.
@staticmethod
@deprecated(
    reason=(
        "ID factory construction now depends on configuration; use the "
        "idGenerator config field. Will be removed after v26."
    ),
    version="v26.0",
    category=FutureWarning,
)
def makeIdFactory(expId, expBits):

Definition at line 243 of file detectAndMeasure.py.

◆ idFactory

lsst.ip.diffim.detectAndMeasure.idFactory : `lsst.afw.table.IdFactory`

Definition at line 257 of file detectAndMeasure.py.

◆ mask

lsst.ip.diffim.detectAndMeasure.mask : `lsst.afw.image.Mask`

Definition at line 383 of file detectAndMeasure.py.

◆ matchedTemplate

lsst.ip.diffim.detectAndMeasure.matchedTemplate : `lsst.afw.image.ExposureF`

Definition at line 287 of file detectAndMeasure.py.

◆ measurementResults

lsst.ip.diffim.detectAndMeasure.measurementResults : `lsst.pipe.base.Struct`

Definition at line 297 of file detectAndMeasure.py.

◆ negativeFootprints

lsst.ip.diffim.detectAndMeasure.negativeFootprints : `lsst.afw.detection.FootprintSet`, optional

Definition at line 329 of file detectAndMeasure.py.

◆ positiveFootprints

lsst.ip.diffim.detectAndMeasure.positiveFootprints : `lsst.afw.detection.FootprintSet`, optional

Definition at line 327 of file detectAndMeasure.py.

◆ science

lsst.ip.diffim.detectAndMeasure.science : `lsst.afw.image.ExposureF`
return ExposureIdInfo(expId, expBits).makeSourceIdFactory()

def runQuantum(self, butlerQC: pipeBase.ButlerQuantumContext,
           inputRefs: pipeBase.InputQuantizedConnection,
           outputRefs: pipeBase.OutputQuantizedConnection):
inputs = butlerQC.get(inputRefs)
idGenerator = self.config.idGenerator.apply(butlerQC.quantum.dataId)
idFactory = idGenerator.make_table_id_factory()
outputs = self.run(**inputs, idFactory=idFactory)
butlerQC.put(outputs, outputRefs)

@timeMethod
def run(self, science, matchedTemplate, difference,
    idFactory=None):
# Run forced psf photometry on the PVI at the diaSource locations.
# Copy the measured flux and error into the diaSource.
forcedSources = self.forcedMeasurement.generateMeasCat(
    science, diaSources, wcs)
self.forcedMeasurement.run(forcedSources, science, diaSources, wcs)
mapper = afwTable.SchemaMapper(forcedSources.schema, diaSources.schema)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_instFlux")[0],
                  "ip_diffim_forced_PsfFlux_instFlux", True)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_instFluxErr")[0],
                  "ip_diffim_forced_PsfFlux_instFluxErr", True)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_area")[0],
                  "ip_diffim_forced_PsfFlux_area", True)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag")[0],
                  "ip_diffim_forced_PsfFlux_flag", True)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag_noGoodPixels")[0],
                  "ip_diffim_forced_PsfFlux_flag_noGoodPixels", True)
mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag_edge")[0],
                  "ip_diffim_forced_PsfFlux_flag_edge", True)
for diaSource, forcedSource in zip(diaSources, forcedSources):
    diaSource.assign(forcedSource, mapper)


class DetectAndMeasureScoreConnections(DetectAndMeasureConnections):
scoreExposure = pipeBase.connectionTypes.Input(
doc="Maximum likelihood image for detection.",
dimensions=("instrument", "visit", "detector"),
storageClass="ExposureF",
name="{fakesType}{coaddName}Diff_scoreExp",
)


class DetectAndMeasureScoreConfig(DetectAndMeasureConfig,
                          pipelineConnections=DetectAndMeasureScoreConnections):
pass


class DetectAndMeasureScoreTask(DetectAndMeasureTask):
ConfigClass = DetectAndMeasureScoreConfig
_DefaultName = "detectAndMeasureScore"

@timeMethod
def run(self, science, matchedTemplate, difference, scoreExposure,
        idFactory=None):

Definition at line 285 of file detectAndMeasure.py.

◆ scoreExposure

lsst.ip.diffim.detectAndMeasure.scoreExposure : `lsst.afw.image.ExposureF`

Definition at line 500 of file detectAndMeasure.py.

◆ seed

lsst.ip.diffim.detectAndMeasure.seed : `int`

Definition at line 385 of file detectAndMeasure.py.

◆ sources

lsst.ip.diffim.detectAndMeasure.sources : `lsst.afw.table.SourceCatalog`
# Ensure that we start with an empty detection mask.
mask = difference.mask
mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE"))

table = afwTable.SourceTable.make(self.schema, idFactory)
table.setMetadata(self.algMetadata)
results = self.detection.run(
    table=table,
    exposure=difference,
    doSmooth=True,
)

return self.processResults(science, matchedTemplate, difference, results.sources, table,
                           positiveFootprints=results.positive, negativeFootprints=results.negative)

def processResults(self, science, matchedTemplate, difference, sources, table,
               positiveFootprints=None, negativeFootprints=None,):

Definition at line 325 of file detectAndMeasure.py.

◆ table

lsst.ip.diffim.detectAndMeasure.table : `lsst.afw.table.SourceTable`

Definition at line 331 of file detectAndMeasure.py.

◆ wcs

lsst.ip.diffim.detectAndMeasure.wcs : `lsst.afw.geom.SkyWcs`

Definition at line 432 of file detectAndMeasure.py.