LSST Applications g0da5cf3356+25b44625d0,g17e5ecfddb+50a5ac4092,g1c76d35bf8+585f0f68a2,g295839609d+8ef6456700,g2e2c1a68ba+cc1f6f037e,g38293774b4+62d12e78cb,g3b44f30a73+2891c76795,g48ccf36440+885b902d19,g4b2f1765b6+0c565e8f25,g5320a0a9f6+bd4bf1dc76,g56364267ca+403c24672b,g56b687f8c9+585f0f68a2,g5c4744a4d9+78cd207961,g5ffd174ac0+bd4bf1dc76,g6075d09f38+3075de592a,g667d525e37+cacede5508,g6f3e93b5a3+da81c812ee,g71f27ac40c+cacede5508,g7212e027e3+eb621d73aa,g774830318a+18d2b9fa6c,g7985c39107+62d12e78cb,g79ca90bc5c+fa2cc03294,g881bdbfe6c+cacede5508,g91fc1fa0cf+82a115f028,g961520b1fb+2534687f64,g96f01af41f+f2060f23b6,g9ca82378b8+cacede5508,g9d27549199+78cd207961,gb065e2a02a+ad48cbcda4,gb1df4690d6+585f0f68a2,gb35d6563ee+62d12e78cb,gbc3249ced9+bd4bf1dc76,gbec6a3398f+bd4bf1dc76,gd01420fc67+bd4bf1dc76,gd59336e7c4+c7bb92e648,gf46e8334de+81c9a61069,gfed783d017+bd4bf1dc76,v25.0.1.rc3
LSST Data Management Base Package
Loading...
Searching...
No Matches
Classes | Variables
lsst.pipe.tasks.imageDifference Namespace Reference

Classes

class  ImageDifferenceFromTemplateConfig
 
class  ImageDifferenceFromTemplateTask
 
class  ImageDifferenceTaskConnections
 

Variables

int FwhmPerSigma = 2*math.sqrt(2*math.log(2))
 
float IqrToSigma = 0.741
 
 doApplyFinalizedPsf
 

Variable Documentation

◆ doApplyFinalizedPsf

lsst.pipe.tasks.imageDifference.doApplyFinalizedPsf
doAddCalexpBackground = pexConfig.Field(dtype=bool, default=False,
                                        doc="Add background to calexp before processing it.  "
                                            "Useful as ipDiffim does background matching.")
doUseRegister = pexConfig.Field(dtype=bool, default=False,
                                doc="Re-compute astrometry on the template. "
                                "Use image-to-image registration to align template with "
                                "science image (AL only).")
doDebugRegister = pexConfig.Field(dtype=bool, default=False,
                                  doc="Writing debugging data for doUseRegister")
doSelectSources = pexConfig.Field(dtype=bool, default=False,
                                  doc="Select stars to use for kernel fitting (AL only)")
doSelectDcrCatalog = pexConfig.Field(dtype=bool, default=False,
                                     doc="Select stars of extreme color as part "
                                     "of the control sample (AL only)")
doSelectVariableCatalog = pexConfig.Field(dtype=bool, default=False,
                                          doc="Select stars that are variable to be part "
                                              "of the control sample (AL only)")
doSubtract = pexConfig.Field(dtype=bool, default=True, doc="Compute subtracted exposure?")
doPreConvolve = pexConfig.Field(dtype=bool, default=False,
                                doc="Not in use. Superseded by useScoreImageDetection.",
                                deprecated="This option superseded by useScoreImageDetection."
                                " Will be removed after v22.")
useScoreImageDetection = pexConfig.Field(
    dtype=bool, default=False, doc="Calculate the pre-convolved AL likelihood or "
    "the Zogy score image. Use it for source detection (if doDetection=True).")
doWriteScoreExp = pexConfig.Field(
    dtype=bool, default=False, doc="Write AL likelihood or Zogy score exposure?")
doScaleTemplateVariance = pexConfig.Field(dtype=bool, default=False,
                                          doc="Scale variance of the template before PSF matching")
doScaleDiffimVariance = pexConfig.Field(dtype=bool, default=True,
                                        doc="Scale variance of the diffim before PSF matching. "
                                            "You may do either this or template variance scaling, "
                                            "or neither. (Doing both is a waste of CPU.)")
useGaussianForPreConvolution = pexConfig.Field(
    dtype=bool, default=False, doc="Use a simple gaussian PSF model for pre-convolution "
    "(oherwise use exposure PSF)? (AL and if useScoreImageDetection=True only)")
doDetection = pexConfig.Field(dtype=bool, default=True, doc="Detect sources?")
doDecorrelation = pexConfig.Field(dtype=bool, default=True,
                                  doc="Perform diffim decorrelation to undo pixel correlation due to A&L "
                                  "kernel convolution (AL only)? If True, also update the diffim PSF.")
doMerge = pexConfig.Field(dtype=bool, default=True,
                          doc="Merge positive and negative diaSources with grow radius "
                              "set by growFootprint")
doMatchSources = pexConfig.Field(dtype=bool, default=False,
                                 doc="Match diaSources with input calexp sources and ref catalog sources")
doMeasurement = pexConfig.Field(dtype=bool, default=True, doc="Measure diaSources?")
doDipoleFitting = pexConfig.Field(dtype=bool, default=True, doc="Measure dipoles using new algorithm?")
doForcedMeasurement = pexConfig.Field(
    dtype=bool,
    default=True,
    doc="Force photometer diaSource locations on PVI?")
doWriteSubtractedExp = pexConfig.Field(
    dtype=bool, default=True, doc="Write difference exposure (AL and Zogy) ?")
doWriteWarpedExp = pexConfig.Field(
    dtype=bool, default=False, doc="Write WCS, warped template coadd exposure?")
doWriteMatchedExp = pexConfig.Field(dtype=bool, default=False,
                                    doc="Write warped and PSF-matched template coadd exposure?")
doWriteSources = pexConfig.Field(dtype=bool, default=True, doc="Write sources?")
doAddMetrics = pexConfig.Field(dtype=bool, default=False,
                               doc="Add columns to the source table to hold analysis metrics?")
doApplyFinalizedPsf = pexConfig.Field(
    doc="Whether to apply finalized psf models and aperture correction map.",
    dtype=bool,
    default=False,
)

coaddName = pexConfig.Field(
    doc="coadd name: typically one of deep, goodSeeing, or dcr",
    dtype=str,
    default="deep",
)
convolveTemplate = pexConfig.Field(
    doc="Which image gets convolved (default = template)",
    dtype=bool,
    default=True
)
refObjLoader = pexConfig.ConfigField(
    dtype=LoadReferenceObjectsConfig,
    doc="reference object loader",
)
astrometer = pexConfig.ConfigurableField(
    target=AstrometryTask,
    doc="astrometry task; used to match sources to reference objects, but not to fit a WCS",
)
sourceSelector = pexConfig.ConfigurableField(
    target=ObjectSizeStarSelectorTask,
    doc="Source selection algorithm",
)
subtract = subtractAlgorithmRegistry.makeField("Subtraction Algorithm", default="al")
decorrelate = pexConfig.ConfigurableField(
    target=DecorrelateALKernelSpatialTask,
    doc="Decorrelate effects of A&L kernel convolution on image difference, only if doSubtract is True. "
    "If this option is enabled, then detection.thresholdValue should be set to 5.0 (rather than the "
    "default of 5.5).",
)
# Old style ImageMapper grid. ZogyTask has its own grid option
doSpatiallyVarying = pexConfig.Field(
    dtype=bool,
    default=False,
    doc="Perform A&L decorrelation on a grid across the "
    "image in order to allow for spatial variations. Zogy does not use this option."
)
detection = pexConfig.ConfigurableField(
    target=SourceDetectionTask,
    doc="Low-threshold detection for final measurement",
)
measurement = pexConfig.ConfigurableField(
    target=DipoleFitTask,
    doc="Enable updated dipole fitting method",
)
doApCorr = lsst.pex.config.Field(
    dtype=bool,
    default=True,
    doc="Run subtask to apply aperture corrections"
)
applyApCorr = lsst.pex.config.ConfigurableField(
    target=ApplyApCorrTask,
    doc="Subtask to apply aperture corrections"
)
forcedMeasurement = pexConfig.ConfigurableField(
    target=ForcedMeasurementTask,
    doc="Subtask to force photometer PVI at diaSource location.",
)
getTemplate = pexConfig.ConfigurableField(
    target=GetCoaddAsTemplateTask,
    doc="Subtask to retrieve template exposure and sources",
)
scaleVariance = pexConfig.ConfigurableField(
    target=ScaleVarianceTask,
    doc="Subtask to rescale the variance of the template "
        "to the statistically expected level"
)
controlStepSize = pexConfig.Field(
    doc="What step size (every Nth one) to select a control sample from the kernelSources",
    dtype=int,
    default=5
)
controlRandomSeed = pexConfig.Field(
    doc="Random seed for shuffing the control sample",
    dtype=int,
    default=10
)
register = pexConfig.ConfigurableField(
    target=RegisterTask,
    doc="Task to enable image-to-image image registration (warping)",
)
kernelSourcesFromRef = pexConfig.Field(
    doc="Select sources to measure kernel from reference catalog if True, template if false",
    dtype=bool,
    default=False
)
templateSipOrder = pexConfig.Field(
    dtype=int, default=2,
    doc="Sip Order for fitting the Template Wcs (default is too high, overfitting)"
)
growFootprint = pexConfig.Field(
    dtype=int, default=2,
    doc="Grow positive and negative footprints by this amount before merging"
)
diaSourceMatchRadius = pexConfig.Field(
    dtype=float, default=0.5,
    doc="Match radius (in arcseconds) for DiaSource to Source association"
)
requiredTemplateFraction = pexConfig.Field(
    dtype=float, default=0.1,
    doc="Do not attempt to run task if template covers less than this fraction of pixels."
    "Setting to 0 will always attempt image subtraction"
)
doSkySources = pexConfig.Field(
    dtype=bool,
    default=False,
    doc="Generate sky sources?",
)
skySources = pexConfig.ConfigurableField(
    target=SkyObjectsTask,
    doc="Generate sky sources",
)

def setDefaults(self):
    # defaults are OK for catalog and diacatalog

    self.subtract['al'].kernel.name = "AL"
    self.subtract['al'].kernel.active.fitForBackground = True
    self.subtract['al'].kernel.active.spatialKernelOrder = 1
    self.subtract['al'].kernel.active.spatialBgOrder = 2

    # DiaSource Detection
    self.detection.thresholdPolarity = "both"
    self.detection.thresholdValue = 5.0
    self.detection.reEstimateBackground = False
    self.detection.thresholdType = "pixel_stdev"

    # Add filtered flux measurement, the correct measurement for pre-convolved images.
    # Enable all measurements, regardless of doPreConvolve, as it makes data harvesting easier.
    # To change that you must modify algorithms.names in the task's applyOverrides method,
    # after the user has set doPreConvolve.
    self.measurement.algorithms.names.add('base_PeakLikelihoodFlux')
    self.measurement.plugins.names |= ['ext_trailedSources_Naive',
                                       'base_LocalPhotoCalib',
                                       'base_LocalWcs']

    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

    # For shuffling the control sample
    random.seed(self.controlRandomSeed)

def validate(self):
    pexConfig.Config.validate(self)
    if not self.doSubtract and not self.doDetection:
        raise ValueError("Either doSubtract or doDetection must be enabled.")
    if self.doMeasurement and not self.doDetection:
        raise ValueError("Cannot run source measurement without source detection.")
    if self.doMerge and not self.doDetection:
        raise ValueError("Cannot run source merging without source detection.")
    if self.doSkySources and not self.doDetection:
        raise ValueError("Cannot run sky source creation without source detection.")
    if self.doUseRegister and not self.doSelectSources:
        raise ValueError("doUseRegister=True and doSelectSources=False. "
                         "Cannot run RegisterTask without selecting sources.")
    if self.doScaleDiffimVariance and self.doScaleTemplateVariance:
        raise ValueError("Scaling the diffim variance and scaling the template variance "
                         "are both set. Please choose one or the other.")
    # We cannot allow inconsistencies that would lead to None or not available output products
    if self.subtract.name == 'zogy':
        if self.doWriteMatchedExp:
            raise ValueError("doWriteMatchedExp=True Matched exposure is not "
                             "calculated in zogy subtraction.")
        if self.doAddMetrics:
            raise ValueError("doAddMetrics=True Kernel metrics does not exist in zogy subtraction.")
        if self.doDecorrelation:
            raise ValueError(
                "doDecorrelation=True The decorrelation afterburner does not exist in zogy subtraction.")
        if self.doSelectSources:
            raise ValueError(
                "doSelectSources=True Selecting sources for PSF matching is not a zogy option.")
        if self.useGaussianForPreConvolution:
            raise ValueError(
                "useGaussianForPreConvolution=True This is an AL subtraction only option.")
    else:
        # AL only consistency checks
        if self.useScoreImageDetection and not self.convolveTemplate:
            raise ValueError(
                "convolveTemplate=False and useScoreImageDetection=True "
                "Pre-convolution and matching of the science image is not a supported operation.")
        if self.doWriteSubtractedExp and self.useScoreImageDetection:
            raise ValueError(
                "doWriteSubtractedExp=True and useScoreImageDetection=True "
                "Regular difference image is not calculated. "
                "AL subtraction calculates either the regular difference image or the score image.")
        if self.doWriteScoreExp and not self.useScoreImageDetection:
            raise ValueError(
                "doWriteScoreExp=True and useScoreImageDetection=False "
                "Score image is not calculated. "
                "AL subtraction calculates either the regular difference image or the score image.")
        if self.doAddMetrics and not self.doSubtract:
            raise ValueError("Subtraction must be enabled for kernel metrics calculation.")
        if self.useGaussianForPreConvolution and not self.useScoreImageDetection:
            raise ValueError(
                "useGaussianForPreConvolution=True and useScoreImageDetection=False "
                "Gaussian PSF approximation exists only for AL subtraction w/ pre-convolution.")


@deprecated(reason="This Task has been replaced with lsst.ip.diffim.subtractImages"
        " and lsst.ip.diffim.detectAndMeasure. Will be removed after v25.",
        version="v24.0", category=FutureWarning)
class ImageDifferenceTask(pipeBase.PipelineTask):
ConfigClass = ImageDifferenceConfig
_DefaultName = "imageDifference"

def __init__(self, butler=None, **kwargs):
    super().__init__(**kwargs)
    self.makeSubtask("getTemplate")

    self.makeSubtask("subtract")

    if self.config.subtract.name == 'al' and self.config.doDecorrelation:
        self.makeSubtask("decorrelate")

    if self.config.doScaleTemplateVariance or self.config.doScaleDiffimVariance:
        self.makeSubtask("scaleVariance")

    if self.config.doUseRegister:
        self.makeSubtask("register")
    self.schema = afwTable.SourceTable.makeMinimalSchema()

    if self.config.doSelectSources:
        self.makeSubtask("sourceSelector")
        if self.config.kernelSourcesFromRef:
            self.makeSubtask('refObjLoader', butler=butler)
            self.makeSubtask("astrometer", refObjLoader=self.refObjLoader)

    self.algMetadata = dafBase.PropertyList()
    if self.config.doDetection:
        self.makeSubtask("detection", schema=self.schema)
    if self.config.doMeasurement:
        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)
    if self.config.doMatchSources:
        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)

@staticmethod
def makeIdFactory(expId, expBits):
return ExposureIdInfo(expId, expBits).makeSourceIdFactory()

@lsst.utils.inheritDoc(pipeBase.PipelineTask)
def runQuantum(self, butlerQC: pipeBase.ButlerQuantumContext,
           inputRefs: pipeBase.InputQuantizedConnection,
           outputRefs: pipeBase.OutputQuantizedConnection):
inputs = butlerQC.get(inputRefs)
self.log.info("Processing %s", butlerQC.quantum.dataId)

finalizedPsfApCorrCatalog = inputs.get("finalizedPsfApCorrCatalog", None)
exposure = self.prepareCalibratedExposure(
    inputs["exposure"],
    finalizedPsfApCorrCatalog=finalizedPsfApCorrCatalog
)

expId, expBits = butlerQC.quantum.dataId.pack("visit_detector",
                                              returnMaxBits=True)
idFactory = self.makeIdFactory(expId=expId, expBits=expBits)
if self.config.coaddName == 'dcr':
    templateExposures = inputRefs.dcrCoadds
else:
    templateExposures = inputRefs.coaddExposures
templateStruct = self.getTemplate.runQuantum(
    exposure, butlerQC, inputRefs.skyMap, templateExposures
)

self.checkTemplateIsSufficient(templateStruct.exposure)

outputs = self.run(exposure=exposure,
                   templateExposure=templateStruct.exposure,
                   idFactory=idFactory)
# Consistency with runDataref gen2 handling
if outputs.diaSources is None:
    del outputs.diaSources
butlerQC.put(outputs, outputRefs)

def prepareCalibratedExposure(self, exposure, finalizedPsfApCorrCatalog=None):

Definition at line 589 of file imageDifference.py.

◆ FwhmPerSigma

int lsst.pipe.tasks.imageDifference.FwhmPerSigma = 2*math.sqrt(2*math.log(2))

Definition at line 55 of file imageDifference.py.

◆ IqrToSigma

float lsst.pipe.tasks.imageDifference.IqrToSigma = 0.741

Definition at line 56 of file imageDifference.py.