LSST Applications g00274db5b6+edbf708997,g00d0e8bbd7+edbf708997,g199a45376c+5137f08352,g1fd858c14a+1d4b6db739,g262e1987ae+f4d9505c4f,g29ae962dfc+7156fb1a53,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3e17d7035e+5b3adc59f5,g3fd5ace14f+852fa6fbcb,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+9f17e571f4,g67b6fd64d1+6dc8069a4c,g74acd417e5+ae494d68d9,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+536efcc10a,g7cc15d900a+d121454f8d,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d7436a09f+28c28d8d6d,g8ea07a8fe4+db21c37724,g92c671f44c+9f17e571f4,g98df359435+b2e6376b13,g99af87f6a8+b0f4ad7b8d,gac66b60396+966efe6077,gb88ae4c679+7dec8f19df,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gc24b5d6ed1+9f17e571f4,gca7fc764a6+6dc8069a4c,gcc769fe2a4+97d0256649,gd7ef33dd92+6dc8069a4c,gdab6d2f7ff+ae494d68d9,gdbb4c4dda9+9f17e571f4,ge410e46f29+6dc8069a4c,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask Class Reference
Inheritance diagram for lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask:
lsst.ip.diffim.subtractImages.AlardLuptonPreconvolveSubtractTask lsst.ip.diffim.subtractImages.SimplifiedSubtractTask

Public Member Functions

 __init__ (self, **kwargs)
 
 runQuantum (self, butlerQC, inputRefs, outputRefs)
 
 run (self, template, science, sources, visitSummary=None)
 
 chooseConvolutionMethod (self, template, science)
 
 runMakeKernel (self, template, science, sources=None, convolveTemplate=True, runSourceDetection=False)
 
 runKernelSourceDetection (self, template, science)
 
 runConvolveTemplate (self, template, science, psfMatchingKernel, backgroundModel=None)
 
 runConvolveScience (self, template, science, psfMatchingKernel, backgroundModel=None)
 
 finalize (self, template, science, difference, kernel, templateMatched=True, preConvMode=False, preConvKernel=None, spatiallyVarying=False)
 
 updateMasks (self, template, science)
 

Public Attributes

 convolutionControl = lsst.afw.math.ConvolutionControl()
 
 templatePsfSize
 
 log
 
 sciencePsfSize = getPsfFwhm(science.psf)
 

Static Public Attributes

 ConfigClass = AlardLuptonSubtractConfig
 

Protected Member Functions

 _applyExternalCalibrations (self, exposure, visitSummary)
 
 _calculateMagLim (self, exposure, nsigma=5.0, fallbackPsfSize=None)
 
 _convolveExposure (self, exposure, kernel, convolutionControl, bbox=None, psf=None, photoCalib=None, interpolateBadMaskPlanes=False)
 
 _sourceSelector (self, template, science, sources, fallback=False, preconvolved=False)
 
 _prepareInputs (self, template, science, visitSummary=None)
 
 _clearMask (self, mask, clearMaskPlanes=None)
 

Static Protected Member Functions

 _validateExposures (template, science)
 
 _renameMaskPlanes (mask, maskPlane, newMaskPlane)
 

Static Protected Attributes

str _DefaultName = "alardLuptonSubtract"
 

Detailed Description

Compute the image difference of a science and template image using
the Alard & Lupton (1998) algorithm.

Definition at line 342 of file subtractImages.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.__init__ ( self,
** kwargs )

Definition at line 349 of file subtractImages.py.

349 def __init__(self, **kwargs):
350 super().__init__(**kwargs)
351 self.makeSubtask("decorrelate")
352 self.makeSubtask("makeKernel")
353 self.makeSubtask("sourceSelector")
354 self.makeSubtask("fallbackSourceSelector")
355 if self.config.doScaleVariance:
356 self.makeSubtask("scaleVariance")
357
358 self.convolutionControl = lsst.afw.math.ConvolutionControl()
359 # Normalization is an extra, unnecessary, calculation and will result
360 # in mis-subtraction of the images if there are calibration errors.
361 self.convolutionControl.setDoNormalize(False)
362 self.convolutionControl.setDoCopyEdge(True)
363
Parameters to control convolution.

Member Function Documentation

◆ _applyExternalCalibrations()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._applyExternalCalibrations ( self,
exposure,
visitSummary )
protected
Replace calibrations (psf, and ApCorrMap) on this exposure with
external ones.".

Parameters
----------
exposure : `lsst.afw.image.exposure.Exposure`
    Input exposure to adjust calibrations.
visitSummary : `lsst.afw.table.ExposureCatalog`
    Exposure catalog with external calibrations to be applied. Catalog
    uses the detector id for the catalog id, sorted on id for fast
    lookup.

Returns
-------
exposure : `lsst.afw.image.exposure.Exposure`
    Exposure with adjusted calibrations.

Definition at line 364 of file subtractImages.py.

364 def _applyExternalCalibrations(self, exposure, visitSummary):
365 """Replace calibrations (psf, and ApCorrMap) on this exposure with
366 external ones.".
367
368 Parameters
369 ----------
370 exposure : `lsst.afw.image.exposure.Exposure`
371 Input exposure to adjust calibrations.
372 visitSummary : `lsst.afw.table.ExposureCatalog`
373 Exposure catalog with external calibrations to be applied. Catalog
374 uses the detector id for the catalog id, sorted on id for fast
375 lookup.
376
377 Returns
378 -------
379 exposure : `lsst.afw.image.exposure.Exposure`
380 Exposure with adjusted calibrations.
381 """
382 detectorId = exposure.info.getDetector().getId()
383
384 row = visitSummary.find(detectorId)
385 if row is None:
386 self.log.warning("Detector id %s not found in external calibrations catalog; "
387 "Using original calibrations.", detectorId)
388 else:
389 psf = row.getPsf()
390 apCorrMap = row.getApCorrMap()
391 if psf is None:
392 self.log.warning("Detector id %s has None for psf in "
393 "external calibrations catalog; Using original psf and aperture correction.",
394 detectorId)
395 elif apCorrMap is None:
396 self.log.warning("Detector id %s has None for apCorrMap in "
397 "external calibrations catalog; Using original psf and aperture correction.",
398 detectorId)
399 else:
400 exposure.setPsf(psf)
401 exposure.info.setApCorrMap(apCorrMap)
402
403 return exposure
404

◆ _calculateMagLim()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._calculateMagLim ( self,
exposure,
nsigma = 5.0,
fallbackPsfSize = None )
protected
Calculate an exposure's limiting magnitude.

This method uses the photometric zeropoint together with the
PSF size from the average position of the exposure.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    The target exposure to calculate the limiting magnitude for.
nsigma : `float`, optional
    The detection threshold in sigma.
fallbackPsfSize : `float`, optional
    PSF FWHM to use in the event the exposure PSF cannot be retrieved.

Returns
-------
maglim : `astropy.units.Quantity`
    The limiting magnitude of the exposure, or np.nan.

Definition at line 788 of file subtractImages.py.

788 def _calculateMagLim(self, exposure, nsigma=5.0, fallbackPsfSize=None):
789 """Calculate an exposure's limiting magnitude.
790
791 This method uses the photometric zeropoint together with the
792 PSF size from the average position of the exposure.
793
794 Parameters
795 ----------
796 exposure : `lsst.afw.image.Exposure`
797 The target exposure to calculate the limiting magnitude for.
798 nsigma : `float`, optional
799 The detection threshold in sigma.
800 fallbackPsfSize : `float`, optional
801 PSF FWHM to use in the event the exposure PSF cannot be retrieved.
802
803 Returns
804 -------
805 maglim : `astropy.units.Quantity`
806 The limiting magnitude of the exposure, or np.nan.
807 """
808 if exposure.photoCalib is None:
809 return np.nan
810 # Set maglim to nan upfront in case on an unexpected RuntimeError
811 maglim = np.nan
812 try:
813 psf = exposure.getPsf()
814 psf_shape = psf.computeShape(psf.getAveragePosition())
816 afwDetection.InvalidPsfError,
818 if fallbackPsfSize is not None:
819 self.log.info("Unable to evaluate PSF, using fallback FWHM %f", fallbackPsfSize)
820 psf_area = np.pi*(fallbackPsfSize/2)**2
821 zeropoint = exposure.photoCalib.instFluxToMagnitude(1)
822 maglim = zeropoint - 2.5*np.log10(nsigma*np.sqrt(psf_area))
823 else:
824 self.log.info("Unable to evaluate PSF, setting maglim to nan")
825 maglim = np.nan
826 else:
827 # Get a more accurate area than `psf_shape.getArea()` via moments
828 psf_area = np.pi*np.sqrt(psf_shape.getIxx()*psf_shape.getIyy())
829 zeropoint = exposure.photoCalib.instFluxToMagnitude(1)
830 maglim = zeropoint - 2.5*np.log10(nsigma*np.sqrt(psf_area))
831 finally:
832 return maglim
833
Reports invalid arguments.
Definition Runtime.h:66
Reports when the result of an operation cannot be represented by the destination type.
Definition Runtime.h:115

◆ _clearMask()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._clearMask ( self,
mask,
clearMaskPlanes = None )
protected
Clear the mask plane of an exposure.

Parameters
----------
mask : `lsst.afw.image.Mask`
    The mask plane to erase, which will be modified in place.
clearMaskPlanes : `list` of `str`, optional
    Erase the specified mask planes.
    If not supplied, the entire mask will be erased.

Definition at line 1154 of file subtractImages.py.

1154 def _clearMask(self, mask, clearMaskPlanes=None):
1155 """Clear the mask plane of an exposure.
1156
1157 Parameters
1158 ----------
1159 mask : `lsst.afw.image.Mask`
1160 The mask plane to erase, which will be modified in place.
1161 clearMaskPlanes : `list` of `str`, optional
1162 Erase the specified mask planes.
1163 If not supplied, the entire mask will be erased.
1164 """
1165 if clearMaskPlanes is None:
1166 clearMaskPlanes = list(mask.getMaskPlaneDict().keys())
1167
1168 bitMaskToClear = mask.getPlaneBitMask(clearMaskPlanes)
1169 mask &= ~bitMaskToClear
1170
1171

◆ _convolveExposure()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._convolveExposure ( self,
exposure,
kernel,
convolutionControl,
bbox = None,
psf = None,
photoCalib = None,
interpolateBadMaskPlanes = False )
protected
Convolve an exposure with the given kernel.

Parameters
----------
exposure : `lsst.afw.Exposure`
    exposure to convolve.
kernel : `lsst.afw.math.LinearCombinationKernel`
    PSF matching kernel computed in the ``makeKernel`` subtask.
convolutionControl : `lsst.afw.math.ConvolutionControl`
    Configuration for convolve algorithm.
bbox : `lsst.geom.Box2I`, optional
    Bounding box to trim the convolved exposure to.
psf : `lsst.afw.detection.Psf`, optional
    Point spread function (PSF) to set for the convolved exposure.
photoCalib : `lsst.afw.image.PhotoCalib`, optional
    Photometric calibration of the convolved exposure.
interpolateBadMaskPlanes : `bool`, optional
    If set, interpolate over mask planes specified in
    ``config.badMaskPlanes`` before convolving the image.

Returns
-------
convolvedExp : `lsst.afw.Exposure`
    The convolved image.

Definition at line 864 of file subtractImages.py.

869 ):
870 """Convolve an exposure with the given kernel.
871
872 Parameters
873 ----------
874 exposure : `lsst.afw.Exposure`
875 exposure to convolve.
876 kernel : `lsst.afw.math.LinearCombinationKernel`
877 PSF matching kernel computed in the ``makeKernel`` subtask.
878 convolutionControl : `lsst.afw.math.ConvolutionControl`
879 Configuration for convolve algorithm.
880 bbox : `lsst.geom.Box2I`, optional
881 Bounding box to trim the convolved exposure to.
882 psf : `lsst.afw.detection.Psf`, optional
883 Point spread function (PSF) to set for the convolved exposure.
884 photoCalib : `lsst.afw.image.PhotoCalib`, optional
885 Photometric calibration of the convolved exposure.
886 interpolateBadMaskPlanes : `bool`, optional
887 If set, interpolate over mask planes specified in
888 ``config.badMaskPlanes`` before convolving the image.
889
890 Returns
891 -------
892 convolvedExp : `lsst.afw.Exposure`
893 The convolved image.
894 """
895 convolvedExposure = exposure.clone()
896 if psf is not None:
897 convolvedExposure.setPsf(psf)
898 if photoCalib is not None:
899 convolvedExposure.setPhotoCalib(photoCalib)
900 if interpolateBadMaskPlanes and self.config.badMaskPlanes is not None:
901 nInterp = _interpolateImage(convolvedExposure.maskedImage,
902 self.config.badMaskPlanes)
903 self.metadata["nInterpolated"] = nInterp
904 convolvedImage = lsst.afw.image.MaskedImageF(convolvedExposure.getBBox())
905 lsst.afw.math.convolve(convolvedImage, convolvedExposure.maskedImage, kernel, convolutionControl)
906 convolvedExposure.setMaskedImage(convolvedImage)
907 if bbox is None:
908 return convolvedExposure
909 else:
910 return convolvedExposure[bbox]
911
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image.

◆ _prepareInputs()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._prepareInputs ( self,
template,
science,
visitSummary = None )
protected
Perform preparatory calculations common to all Alard&Lupton Tasks.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure. The
    variance plane of the template image is modified in place.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template. The variance plane
    of the science image is modified in place.
visitSummary : `lsst.afw.table.ExposureCatalog`, optional
    Exposure catalog with external calibrations to be applied.  Catalog
    uses the detector id for the catalog id, sorted on id for fast
    lookup.

Definition at line 995 of file subtractImages.py.

995 def _prepareInputs(self, template, science, visitSummary=None):
996 """Perform preparatory calculations common to all Alard&Lupton Tasks.
997
998 Parameters
999 ----------
1000 template : `lsst.afw.image.ExposureF`
1001 Template exposure, warped to match the science exposure. The
1002 variance plane of the template image is modified in place.
1003 science : `lsst.afw.image.ExposureF`
1004 Science exposure to subtract from the template. The variance plane
1005 of the science image is modified in place.
1006 visitSummary : `lsst.afw.table.ExposureCatalog`, optional
1007 Exposure catalog with external calibrations to be applied. Catalog
1008 uses the detector id for the catalog id, sorted on id for fast
1009 lookup.
1010 """
1011 self._validateExposures(template, science)
1012 if visitSummary is not None:
1013 self._applyExternalCalibrations(science, visitSummary=visitSummary)
1014 templateCoverageFraction = checkTemplateIsSufficient(
1015 template[science.getBBox()], science, self.log,
1016 requiredTemplateFraction=self.config.requiredTemplateFraction,
1017 exceptionMessage="Not attempting subtraction. To force subtraction,"
1018 " set config requiredTemplateFraction=0"
1019 )
1020 self.metadata["templateCoveragePercent"] = 100*templateCoverageFraction
1021
1022 if self.config.doScaleVariance:
1023 # Scale the variance of the template and science images before
1024 # convolution, subtraction, or decorrelation so that they have the
1025 # correct ratio.
1026 templateVarFactor = self.scaleVariance.run(template.maskedImage)
1027 sciVarFactor = self.scaleVariance.run(science.maskedImage)
1028 self.log.info("Template variance scaling factor: %.2f", templateVarFactor)
1029 self.metadata["scaleTemplateVarianceFactor"] = templateVarFactor
1030 self.log.info("Science variance scaling factor: %.2f", sciVarFactor)
1031 self.metadata["scaleScienceVarianceFactor"] = sciVarFactor
1032
1033 # Erase existing detection mask planes.
1034 # We don't want the detection mask from the science image
1035 self.updateMasks(template, science)
1036
1037 # Calling getPsfFwhm on template.psf fails on some rare occasions when
1038 # the template has no input exposures at the average position of the
1039 # stars. So we try getPsfFwhm first on template, and if that fails we
1040 # evaluate the PSF on a grid specified by fwhmExposure* fields.
1041 # To keep consistent definitions for PSF size on the template and
1042 # science images, we use the same method for both.
1043 # In the try block below, we catch two exceptions:
1044 # 1. InvalidParameterError, in case the point where we are evaluating
1045 # the PSF lands in a gap in the template.
1046 # 2. RangeError, in case the template coverage is so poor that we end
1047 # up near a region with no data.
1048 try:
1049 self.templatePsfSize = getPsfFwhm(template.psf)
1050 self.sciencePsfSize = getPsfFwhm(science.psf)
1052 # Catch a broad range of exceptions, since some are C++ only
1053 # Catching:
1054 # - lsst::geom::SingularTransformException
1055 # - lsst.pex.exceptions.InvalidParameterError
1056 # - lsst.pex.exceptions.RangeError
1057 self.log.info("Unable to evaluate PSF at the average position. "
1058 "Evaluting PSF on a grid of points."
1059 )
1060 self.templatePsfSize = evaluateMeanPsfFwhm(
1061 template,
1062 fwhmExposureBuffer=self.config.makeKernel.fwhmExposureBuffer,
1063 fwhmExposureGrid=self.config.makeKernel.fwhmExposureGrid
1064 )
1065 self.sciencePsfSize = evaluateMeanPsfFwhm(
1066 science,
1067 fwhmExposureBuffer=self.config.makeKernel.fwhmExposureBuffer,
1068 fwhmExposureGrid=self.config.makeKernel.fwhmExposureGrid
1069 )
1070 self.log.info("Science PSF FWHM: %f pixels", self.sciencePsfSize)
1071 self.log.info("Template PSF FWHM: %f pixels", self.templatePsfSize)
1072 self.metadata["sciencePsfSize"] = self.sciencePsfSize
1073 self.metadata["templatePsfSize"] = self.templatePsfSize
1074
1075 # Calculate estimated image depths, i.e., limiting magnitudes
1076 maglim_science = self._calculateMagLim(science, fallbackPsfSize=self.sciencePsfSize)
1077 if np.isnan(maglim_science):
1078 self.log.warning("Limiting magnitude of the science image is NaN!")
1079 fluxlim_science = (maglim_science*u.ABmag).to_value(u.nJy)
1080 maglim_template = self._calculateMagLim(template, fallbackPsfSize=self.templatePsfSize)
1081 if np.isnan(maglim_template):
1082 self.log.info("Cannot evaluate template limiting mag; adopting science limiting mag for diffim")
1083 maglim_diffim = maglim_science
1084 else:
1085 fluxlim_template = (maglim_template*u.ABmag).to_value(u.nJy)
1086 maglim_diffim = (np.sqrt(fluxlim_science**2 + fluxlim_template**2)*u.nJy).to(u.ABmag).value
1087 self.metadata["scienceLimitingMagnitude"] = maglim_science
1088 self.metadata["templateLimitingMagnitude"] = maglim_template
1089 self.metadata["diffimLimitingMagnitude"] = maglim_diffim
1090
Provides consistent interface for LSST exceptions.
Definition Exception.h:107

◆ _renameMaskPlanes()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._renameMaskPlanes ( mask,
maskPlane,
newMaskPlane )
staticprotected
Rename a mask plane by adding the new name and copying the data.

Parameters
----------
mask : `lsst.afw.image.Mask`
    The mask image to update in place.
maskPlane : `str`
    The name of the existing mask plane to copy.
newMaskPlane : `str`
    The new name of the mask plane that will be added.
    If the mask plane already exists, it will be updated in place.

Definition at line 1136 of file subtractImages.py.

1136 def _renameMaskPlanes(mask, maskPlane, newMaskPlane):
1137 """Rename a mask plane by adding the new name and copying the data.
1138
1139 Parameters
1140 ----------
1141 mask : `lsst.afw.image.Mask`
1142 The mask image to update in place.
1143 maskPlane : `str`
1144 The name of the existing mask plane to copy.
1145 newMaskPlane : `str`
1146 The new name of the mask plane that will be added.
1147 If the mask plane already exists, it will be updated in place.
1148 """
1149 mask.addMaskPlane(newMaskPlane)
1150 originBitMask = mask.getPlaneBitMask(maskPlane)
1151 destinationBitMask = mask.getPlaneBitMask(newMaskPlane)
1152 mask.array |= ((mask.array & originBitMask) > 0)*destinationBitMask
1153

◆ _sourceSelector()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._sourceSelector ( self,
template,
science,
sources,
fallback = False,
preconvolved = False )
protected
Select sources from a catalog that meet the selection criteria.
The selection criteria include any configured parameters of the
`sourceSelector` subtask, as well as checking the science and template
mask planes.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
sources : `lsst.afw.table.SourceCatalog`
    Input source catalog to select sources from.
fallback : `bool`, optional
    Switch indicating the source selector is being called after
    running the fallback source detection subtask, which does not run a
    full set of measurement plugins and can't use the same settings for
    the source selector.
preconvolved : `bool`, optional
    If set, exclude a wider buffer around the edge of the image to
    account for an extra convolution.

Returns
-------
kernelSources : `lsst.afw.table.SourceCatalog`
    The input source catalog, with flagged and low signal-to-noise
    sources removed and footprints added.

Raises
------
InsufficientKernelSourcesError
    An AlgorithmError that is raised if there are not enough PSF
    candidates to construct the PSF matching kernel.

Definition at line 912 of file subtractImages.py.

912 def _sourceSelector(self, template, science, sources, fallback=False, preconvolved=False):
913 """Select sources from a catalog that meet the selection criteria.
914 The selection criteria include any configured parameters of the
915 `sourceSelector` subtask, as well as checking the science and template
916 mask planes.
917
918 Parameters
919 ----------
920 template : `lsst.afw.image.ExposureF`
921 Template exposure, warped to match the science exposure.
922 science : `lsst.afw.image.ExposureF`
923 Science exposure to subtract from the template.
924 sources : `lsst.afw.table.SourceCatalog`
925 Input source catalog to select sources from.
926 fallback : `bool`, optional
927 Switch indicating the source selector is being called after
928 running the fallback source detection subtask, which does not run a
929 full set of measurement plugins and can't use the same settings for
930 the source selector.
931 preconvolved : `bool`, optional
932 If set, exclude a wider buffer around the edge of the image to
933 account for an extra convolution.
934
935 Returns
936 -------
937 kernelSources : `lsst.afw.table.SourceCatalog`
938 The input source catalog, with flagged and low signal-to-noise
939 sources removed and footprints added.
940
941 Raises
942 ------
943 InsufficientKernelSourcesError
944 An AlgorithmError that is raised if there are not enough PSF
945 candidates to construct the PSF matching kernel.
946 """
947 if fallback:
948 selected = self.fallbackSourceSelector.selectSources(sources).selected
949 else:
950 selected = self.sourceSelector.selectSources(sources).selected
951 sciencePsfSize = self.sciencePsfSize*np.sqrt(2) if preconvolved else self.sciencePsfSize
952 kSize = self.makeKernel.makeKernelBasisList(self.templatePsfSize, sciencePsfSize)[0].getWidth()
953 selectSources = sources[selected].copy(deep=True)
954 # Set the footprints, to be used in `makeKernel` and `checkMask`.
955 kernelSources = setSourceFootprints(selectSources, kernelSize=kSize)
956 bbox = science.getBBox()
957 if preconvolved:
958 bbox.grow(-kSize)
959 if self.config.restrictKernelEdgeSources:
960 bbox.grow(-kSize)
961 # Remove sources that land on masked pixels
962 scienceSelected = checkMask(science.mask[bbox], kernelSources, self.config.excludeMaskPlanes)
963 templateSelected = checkMask(template.mask[bbox], kernelSources, self.config.excludeMaskPlanes)
964 maskSelected = scienceSelected & templateSelected
965 kernelSources = kernelSources[maskSelected].copy(deep=True)
966 # Trim kernelSources if they exceed ``maxKernelSources``.
967 # Keep the highest signal-to-noise sources of those selected.
968 if (len(kernelSources) > self.config.maxKernelSources) & (self.config.maxKernelSources > 0):
969 signalToNoise = kernelSources.getPsfInstFlux()/kernelSources.getPsfInstFluxErr()
970 indices = np.argsort(signalToNoise)
971 indices = indices[-self.config.maxKernelSources:]
972 selected = np.zeros(len(kernelSources), dtype=bool)
973 selected[indices] = True
974 kernelSources = kernelSources[selected].copy(deep=True)
975
976 self.log.info("%i/%i=%.1f%% of sources selected for PSF matching from the input catalog",
977 len(kernelSources), len(sources), 100*len(kernelSources)/len(sources))
978 if len(kernelSources) < self.config.minKernelSources:
979 self.log.error("Too few sources to calculate the PSF matching kernel: "
980 "%i selected but %i needed for the calculation.",
981 len(kernelSources), self.config.minKernelSources)
982 if self.config.allowKernelSourceDetection and not fallback:
983 # The fallback source detection pipeline calls this method, so
984 # allowing source detection in that case would create an endless
985 # loop
986 kernelSources = self.runKernelSourceDetection(template, science)
987 else:
988 raise InsufficientKernelSourcesError(nSources=len(kernelSources),
989 nRequired=self.config.minKernelSources)
990
991 self.metadata["nPsfSources"] = len(kernelSources)
992
993 return kernelSources
994

◆ _validateExposures()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._validateExposures ( template,
science )
staticprotected
Check that the WCS of the two Exposures match, the template bbox
contains the science bbox, and that the bands match.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.

Raises
------
AssertionError
    Raised if the WCS of the template is not equal to the science WCS,
    if the science image is not fully contained in the template
    bounding box, or if the bands do not match.

Definition at line 835 of file subtractImages.py.

835 def _validateExposures(template, science):
836 """Check that the WCS of the two Exposures match, the template bbox
837 contains the science bbox, and that the bands match.
838
839 Parameters
840 ----------
841 template : `lsst.afw.image.ExposureF`
842 Template exposure, warped to match the science exposure.
843 science : `lsst.afw.image.ExposureF`
844 Science exposure to subtract from the template.
845
846 Raises
847 ------
848 AssertionError
849 Raised if the WCS of the template is not equal to the science WCS,
850 if the science image is not fully contained in the template
851 bounding box, or if the bands do not match.
852 """
853 assert template.wcs == science.wcs, \
854 "Template and science exposure WCS are not identical."
855 templateBBox = template.getBBox()
856 scienceBBox = science.getBBox()
857 assert science.filter.bandLabel == template.filter.bandLabel, \
858 "Science and template exposures have different bands: %s, %s" % \
859 (science.filter, template.filter)
860
861 assert templateBBox.contains(scienceBBox), \
862 "Template bbox does not contain all of the science image."
863

◆ chooseConvolutionMethod()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.chooseConvolutionMethod ( self,
template,
science )
Determine whether the template should be convolved with the PSF
matching kernel.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.

Returns
-------
convolveTemplate : `bool`
    Convolve the template to match the two images?

Raises
------
RuntimeError
    If an unsupported convolution mode is supplied.

Definition at line 485 of file subtractImages.py.

485 def chooseConvolutionMethod(self, template, science):
486 """Determine whether the template should be convolved with the PSF
487 matching kernel.
488
489 Parameters
490 ----------
491 template : `lsst.afw.image.ExposureF`
492 Template exposure, warped to match the science exposure.
493 science : `lsst.afw.image.ExposureF`
494 Science exposure to subtract from the template.
495
496 Returns
497 -------
498 convolveTemplate : `bool`
499 Convolve the template to match the two images?
500
501 Raises
502 ------
503 RuntimeError
504 If an unsupported convolution mode is supplied.
505 """
506 if self.config.mode == "auto":
507 convolveTemplate = _shapeTest(template,
508 science,
509 fwhmExposureBuffer=self.config.makeKernel.fwhmExposureBuffer,
510 fwhmExposureGrid=self.config.makeKernel.fwhmExposureGrid)
511 if convolveTemplate:
512 if self.sciencePsfSize < self.templatePsfSize:
513 self.log.info("Average template PSF size is greater, "
514 "but science PSF greater in one dimension: convolving template image.")
515 else:
516 self.log.info("Science PSF size is greater: convolving template image.")
517 else:
518 self.log.info("Template PSF size is greater: convolving science image.")
519 elif self.config.mode == "convolveTemplate":
520 self.log.info("`convolveTemplate` is set: convolving template image.")
521 convolveTemplate = True
522 elif self.config.mode == "convolveScience":
523 self.log.info("`convolveScience` is set: convolving science image.")
524 convolveTemplate = False
525 else:
526 raise RuntimeError("Cannot handle AlardLuptonSubtract mode: %s", self.config.mode)
527 return convolveTemplate
528

◆ finalize()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.finalize ( self,
template,
science,
difference,
kernel,
templateMatched = True,
preConvMode = False,
preConvKernel = None,
spatiallyVarying = False )
Decorrelate the difference image to undo the noise correlations
caused by convolution.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
difference : `lsst.afw.image.ExposureF`
    Result of subtracting template and science.
kernel : `lsst.afw.math.Kernel`
    An (optionally spatially-varying) PSF matching kernel
templateMatched : `bool`, optional
    Was the template PSF-matched to the science image?
preConvMode : `bool`, optional
    Was the science image preconvolved with its own PSF
    before PSF matching the template?
preConvKernel : `lsst.afw.detection.Psf`, optional
    If not `None`, then the science image was pre-convolved with
    (the reflection of) this kernel. Must be normalized to sum to 1.
spatiallyVarying : `bool`, optional
    Compute the decorrelation kernel spatially varying across the image?

Returns
-------
correctedExposure : `lsst.afw.image.ExposureF`
    The decorrelated image difference.

Definition at line 739 of file subtractImages.py.

743 spatiallyVarying=False):
744 """Decorrelate the difference image to undo the noise correlations
745 caused by convolution.
746
747 Parameters
748 ----------
749 template : `lsst.afw.image.ExposureF`
750 Template exposure, warped to match the science exposure.
751 science : `lsst.afw.image.ExposureF`
752 Science exposure to subtract from the template.
753 difference : `lsst.afw.image.ExposureF`
754 Result of subtracting template and science.
755 kernel : `lsst.afw.math.Kernel`
756 An (optionally spatially-varying) PSF matching kernel
757 templateMatched : `bool`, optional
758 Was the template PSF-matched to the science image?
759 preConvMode : `bool`, optional
760 Was the science image preconvolved with its own PSF
761 before PSF matching the template?
762 preConvKernel : `lsst.afw.detection.Psf`, optional
763 If not `None`, then the science image was pre-convolved with
764 (the reflection of) this kernel. Must be normalized to sum to 1.
765 spatiallyVarying : `bool`, optional
766 Compute the decorrelation kernel spatially varying across the image?
767
768 Returns
769 -------
770 correctedExposure : `lsst.afw.image.ExposureF`
771 The decorrelated image difference.
772 """
773 if self.config.doDecorrelation:
774 self.log.info("Decorrelating image difference.")
775 # We have cleared the template mask plane, so copy the mask plane of
776 # the image difference so that we can calculate correct statistics
777 # during decorrelation
778 correctedExposure = self.decorrelate.run(science, template[science.getBBox()], difference, kernel,
779 templateMatched=templateMatched,
780 preConvMode=preConvMode,
781 preConvKernel=preConvKernel,
782 spatiallyVarying=spatiallyVarying).correctedExposure
783 else:
784 self.log.info("NOT decorrelating image difference.")
785 correctedExposure = difference
786 return correctedExposure
787

◆ run()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.run ( self,
template,
science,
sources,
visitSummary = None )
PSF match, subtract, and decorrelate two images.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
sources : `lsst.afw.table.SourceCatalog`
    Identified sources on the science exposure. This catalog is used to
    select sources in order to perform the AL PSF matching on stamp
    images around them.
visitSummary : `lsst.afw.table.ExposureCatalog`, optional
    Exposure catalog with external calibrations to be applied. Catalog
    uses the detector id for the catalog id, sorted on id for fast
    lookup.

Returns
-------
results : `lsst.pipe.base.Struct`
    ``difference`` : `lsst.afw.image.ExposureF`
        Result of subtracting template and science.
    ``matchedTemplate`` : `lsst.afw.image.ExposureF`
        Warped and PSF-matched template exposure.
    ``backgroundModel`` : `lsst.afw.math.Function2D`
        Background model that was fit while solving for the
        PSF-matching kernel
    ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
        Kernel used to PSF-match the convolved image.
    ``kernelSources` : `lsst.afw.table.SourceCatalog`
        Sources from the input catalog that were used to construct the
        PSF-matching kernel.

Reimplemented in lsst.ip.diffim.subtractImages.AlardLuptonPreconvolveSubtractTask, and lsst.ip.diffim.subtractImages.SimplifiedSubtractTask.

Definition at line 418 of file subtractImages.py.

418 def run(self, template, science, sources, visitSummary=None):
419 """PSF match, subtract, and decorrelate two images.
420
421 Parameters
422 ----------
423 template : `lsst.afw.image.ExposureF`
424 Template exposure, warped to match the science exposure.
425 science : `lsst.afw.image.ExposureF`
426 Science exposure to subtract from the template.
427 sources : `lsst.afw.table.SourceCatalog`
428 Identified sources on the science exposure. This catalog is used to
429 select sources in order to perform the AL PSF matching on stamp
430 images around them.
431 visitSummary : `lsst.afw.table.ExposureCatalog`, optional
432 Exposure catalog with external calibrations to be applied. Catalog
433 uses the detector id for the catalog id, sorted on id for fast
434 lookup.
435
436 Returns
437 -------
438 results : `lsst.pipe.base.Struct`
439 ``difference`` : `lsst.afw.image.ExposureF`
440 Result of subtracting template and science.
441 ``matchedTemplate`` : `lsst.afw.image.ExposureF`
442 Warped and PSF-matched template exposure.
443 ``backgroundModel`` : `lsst.afw.math.Function2D`
444 Background model that was fit while solving for the
445 PSF-matching kernel
446 ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
447 Kernel used to PSF-match the convolved image.
448 ``kernelSources` : `lsst.afw.table.SourceCatalog`
449 Sources from the input catalog that were used to construct the
450 PSF-matching kernel.
451 """
452 self._prepareInputs(template, science, visitSummary=visitSummary)
453
454 convolveTemplate = self.chooseConvolutionMethod(template, science)
455
456 kernelResult = self.runMakeKernel(template, science, sources=sources,
457 convolveTemplate=convolveTemplate,
458 runSourceDetection=False)
459
460 if self.config.doSubtractBackground:
461 backgroundModel = kernelResult.backgroundModel
462 else:
463 backgroundModel = None
464 if convolveTemplate:
465 subtractResults = self.runConvolveTemplate(template, science, kernelResult.psfMatchingKernel,
466 backgroundModel=backgroundModel)
467 else:
468 subtractResults = self.runConvolveScience(template, science, kernelResult.psfMatchingKernel,
469 backgroundModel=backgroundModel)
470 subtractResults.kernelSources = kernelResult.kernelSources
471
472 metrics = computeDifferenceImageMetrics(science, subtractResults.difference, sources)
473
474 self.metadata["differenceFootprintRatioMean"] = metrics.differenceFootprintRatioMean
475 self.metadata["differenceFootprintRatioStdev"] = metrics.differenceFootprintRatioStdev
476 self.metadata["differenceFootprintSkyRatioMean"] = metrics.differenceFootprintSkyRatioMean
477 self.metadata["differenceFootprintSkyRatioStdev"] = metrics.differenceFootprintSkyRatioStdev
478 self.log.info("Mean, stdev of ratio of difference to science "
479 "pixels in star footprints: %5.4f, %5.4f",
480 self.metadata["differenceFootprintRatioMean"],
481 self.metadata["differenceFootprintRatioStdev"])
482
483 return subtractResults
484

◆ runConvolveScience()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.runConvolveScience ( self,
template,
science,
psfMatchingKernel,
backgroundModel = None )
Convolve the science image with a PSF-matching kernel and subtract
the template image.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
psfMatchingKernel : `lsst.afw.math.Kernel`
    Kernel to be used to PSF-match the science image to the template.
backgroundModel : `lsst.afw.math.Function2D`, optional
    Background model that was fit while solving for the PSF-matching
    kernel.

Returns
-------
results : `lsst.pipe.base.Struct`

    ``difference`` : `lsst.afw.image.ExposureF`
        Result of subtracting template and science.
    ``matchedTemplate`` : `lsst.afw.image.ExposureF`
        Warped template exposure. Note that in this case, the template
        is not PSF-matched to the science image.
    ``backgroundModel`` : `lsst.afw.math.Function2D`
        Background model that was fit while solving for the PSF-matching kernel
    ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
       Kernel used to PSF-match the science image to the template.

Definition at line 676 of file subtractImages.py.

676 def runConvolveScience(self, template, science, psfMatchingKernel, backgroundModel=None):
677 """Convolve the science image with a PSF-matching kernel and subtract
678 the template image.
679
680 Parameters
681 ----------
682 template : `lsst.afw.image.ExposureF`
683 Template exposure, warped to match the science exposure.
684 science : `lsst.afw.image.ExposureF`
685 Science exposure to subtract from the template.
686 psfMatchingKernel : `lsst.afw.math.Kernel`
687 Kernel to be used to PSF-match the science image to the template.
688 backgroundModel : `lsst.afw.math.Function2D`, optional
689 Background model that was fit while solving for the PSF-matching
690 kernel.
691
692 Returns
693 -------
694 results : `lsst.pipe.base.Struct`
695
696 ``difference`` : `lsst.afw.image.ExposureF`
697 Result of subtracting template and science.
698 ``matchedTemplate`` : `lsst.afw.image.ExposureF`
699 Warped template exposure. Note that in this case, the template
700 is not PSF-matched to the science image.
701 ``backgroundModel`` : `lsst.afw.math.Function2D`
702 Background model that was fit while solving for the PSF-matching kernel
703 ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
704 Kernel used to PSF-match the science image to the template.
705 """
706 self.metadata["convolvedExposure"] = "Science"
707 bbox = science.getBBox()
708
709 kernelImage = lsst.afw.image.ImageD(psfMatchingKernel.getDimensions())
710 norm = psfMatchingKernel.computeImage(kernelImage, doNormalize=False)
711
712 matchedScience = self._convolveExposure(science, psfMatchingKernel,
713 self.convolutionControl,
714 psf=template.psf)
715
716 # Place back on native photometric scale
717 matchedScience.maskedImage /= norm
718 matchedTemplate = template.clone()[bbox]
719 matchedTemplate.maskedImage /= norm
720 matchedTemplate.setPhotoCalib(science.photoCalib)
721
722 if backgroundModel is not None:
723 modelParams = backgroundModel.getParameters()
724 # We must invert the background model if the matching kernel is solved for the science image.
725 backgroundModel.setParameters([-p for p in modelParams])
726
727 difference = _subtractImages(matchedScience, matchedTemplate, backgroundModel=backgroundModel)
728
729 correctedExposure = self.finalize(template, science, difference,
730 psfMatchingKernel,
731 templateMatched=False)
732
733 return lsst.pipe.base.Struct(difference=correctedExposure,
734 matchedTemplate=matchedTemplate,
735 matchedScience=matchedScience,
736 backgroundModel=backgroundModel,
737 psfMatchingKernel=psfMatchingKernel)
738

◆ runConvolveTemplate()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.runConvolveTemplate ( self,
template,
science,
psfMatchingKernel,
backgroundModel = None )
Convolve the template image with a PSF-matching kernel and subtract
from the science image.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
psfMatchingKernel : `lsst.afw.math.Kernel`
    Kernel to be used to PSF-match the science image to the template.
backgroundModel : `lsst.afw.math.Function2D`, optional
    Background model that was fit while solving for the PSF-matching
    kernel.

Returns
-------
results : `lsst.pipe.base.Struct`

    ``difference`` : `lsst.afw.image.ExposureF`
        Result of subtracting template and science.
    ``matchedTemplate`` : `lsst.afw.image.ExposureF`
        Warped and PSF-matched template exposure.
    ``backgroundModel`` : `lsst.afw.math.Function2D`
        Background model that was fit while solving for the PSF-matching kernel
    ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
        Kernel used to PSF-match the template to the science image.

Definition at line 628 of file subtractImages.py.

628 def runConvolveTemplate(self, template, science, psfMatchingKernel, backgroundModel=None):
629 """Convolve the template image with a PSF-matching kernel and subtract
630 from the science image.
631
632 Parameters
633 ----------
634 template : `lsst.afw.image.ExposureF`
635 Template exposure, warped to match the science exposure.
636 science : `lsst.afw.image.ExposureF`
637 Science exposure to subtract from the template.
638 psfMatchingKernel : `lsst.afw.math.Kernel`
639 Kernel to be used to PSF-match the science image to the template.
640 backgroundModel : `lsst.afw.math.Function2D`, optional
641 Background model that was fit while solving for the PSF-matching
642 kernel.
643
644 Returns
645 -------
646 results : `lsst.pipe.base.Struct`
647
648 ``difference`` : `lsst.afw.image.ExposureF`
649 Result of subtracting template and science.
650 ``matchedTemplate`` : `lsst.afw.image.ExposureF`
651 Warped and PSF-matched template exposure.
652 ``backgroundModel`` : `lsst.afw.math.Function2D`
653 Background model that was fit while solving for the PSF-matching kernel
654 ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
655 Kernel used to PSF-match the template to the science image.
656 """
657 self.metadata["convolvedExposure"] = "Template"
658
659 matchedTemplate = self._convolveExposure(template, psfMatchingKernel,
660 self.convolutionControl,
661 bbox=science.getBBox(),
662 psf=science.psf,
663 photoCalib=science.photoCalib)
664
665 difference = _subtractImages(science, matchedTemplate, backgroundModel=backgroundModel)
666 correctedExposure = self.finalize(template, science, difference,
667 psfMatchingKernel,
668 templateMatched=True)
669
670 return lsst.pipe.base.Struct(difference=correctedExposure,
671 matchedTemplate=matchedTemplate,
672 matchedScience=science,
673 backgroundModel=backgroundModel,
674 psfMatchingKernel=psfMatchingKernel)
675

◆ runKernelSourceDetection()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.runKernelSourceDetection ( self,
template,
science )
Run detection on the science image and use the template mask plane
to reject candidate sources.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.

Returns
-------
kernelSources : `lsst.afw.table.SourceCatalog`
        Sources from the input catalog to use to construct the
        PSF-matching kernel.

Definition at line 596 of file subtractImages.py.

596 def runKernelSourceDetection(self, template, science):
597 """Run detection on the science image and use the template mask plane
598 to reject candidate sources.
599
600 Parameters
601 ----------
602 template : `lsst.afw.image.ExposureF`
603 Template exposure, warped to match the science exposure.
604 science : `lsst.afw.image.ExposureF`
605 Science exposure to subtract from the template.
606
607 Returns
608 -------
609 kernelSources : `lsst.afw.table.SourceCatalog`
610 Sources from the input catalog to use to construct the
611 PSF-matching kernel.
612 """
613 kernelSize = self.makeKernel.makeKernelBasisList(
614 self.templatePsfSize, self.sciencePsfSize)[0].getWidth()
615 sigmaToFwhm = 2*np.log(2*np.sqrt(2))
616 candidateList = self.makeKernel.makeCandidateList(template, science, kernelSize,
617 candidateList=None,
618 sigma=self.sciencePsfSize/sigmaToFwhm)
619 sources = self.makeKernel.selectKernelSources(template, science,
620 candidateList=candidateList,
621 preconvolved=False,
622 templateFwhmPix=self.templatePsfSize,
623 scienceFwhmPix=self.sciencePsfSize)
624
625 # return sources
626 return self._sourceSelector(template, science, sources, fallback=True)
627

◆ runMakeKernel()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.runMakeKernel ( self,
template,
science,
sources = None,
convolveTemplate = True,
runSourceDetection = False )
Construct the PSF-matching kernel.

Parameters
----------
template : `lsst.afw.image.ExposureF`
    Template exposure, warped to match the science exposure.
science : `lsst.afw.image.ExposureF`
    Science exposure to subtract from the template.
sources : `lsst.afw.table.SourceCatalog`
    Identified sources on the science exposure. This catalog is used to
    select sources in order to perform the AL PSF matching on stamp
    images around them.
    Not used if ``runSourceDetection`` is set.
convolveTemplate : `bool`, optional
    Construct the matching kernel to convolve the template?
runSourceDetection : `bool`, optional
    Run a minimal version of source detection to determine kernel
    candidates? If False, a source list to select kernel candidates
    from must be supplied.

Returns
-------
results : `lsst.pipe.base.Struct`
    ``backgroundModel`` : `lsst.afw.math.Function2D`
        Background model that was fit while solving for the
        PSF-matching kernel
    ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
        Kernel used to PSF-match the convolved image.
    ``kernelSources` : `lsst.afw.table.SourceCatalog`
        Sources from the input catalog that were used to construct the
        PSF-matching kernel.

Definition at line 529 of file subtractImages.py.

529 def runMakeKernel(self, template, science, sources=None, convolveTemplate=True, runSourceDetection=False):
530 """Construct the PSF-matching kernel.
531
532 Parameters
533 ----------
534 template : `lsst.afw.image.ExposureF`
535 Template exposure, warped to match the science exposure.
536 science : `lsst.afw.image.ExposureF`
537 Science exposure to subtract from the template.
538 sources : `lsst.afw.table.SourceCatalog`
539 Identified sources on the science exposure. This catalog is used to
540 select sources in order to perform the AL PSF matching on stamp
541 images around them.
542 Not used if ``runSourceDetection`` is set.
543 convolveTemplate : `bool`, optional
544 Construct the matching kernel to convolve the template?
545 runSourceDetection : `bool`, optional
546 Run a minimal version of source detection to determine kernel
547 candidates? If False, a source list to select kernel candidates
548 from must be supplied.
549
550 Returns
551 -------
552 results : `lsst.pipe.base.Struct`
553 ``backgroundModel`` : `lsst.afw.math.Function2D`
554 Background model that was fit while solving for the
555 PSF-matching kernel
556 ``psfMatchingKernel`` : `lsst.afw.math.Kernel`
557 Kernel used to PSF-match the convolved image.
558 ``kernelSources` : `lsst.afw.table.SourceCatalog`
559 Sources from the input catalog that were used to construct the
560 PSF-matching kernel.
561 """
562
563 if convolveTemplate:
564 reference = template
565 target = science
566 referenceFwhmPix = self.templatePsfSize
567 targetFwhmPix = self.sciencePsfSize
568 else:
569 reference = science
570 target = template
571 referenceFwhmPix = self.sciencePsfSize
572 targetFwhmPix = self.templatePsfSize
573 try:
574 if runSourceDetection:
575 kernelSources = self.runKernelSourceDetection(template, science)
576 else:
577 kernelSources = self._sourceSelector(template, science, sources)
578 kernelResult = self.makeKernel.run(reference, target, kernelSources,
579 preconvolved=False,
580 templateFwhmPix=referenceFwhmPix,
581 scienceFwhmPix=targetFwhmPix)
582 except (RuntimeError, lsst.pex.exceptions.Exception) as e:
583 self.log.warning("Failed to match template. Checking coverage")
584 # Raise NoWorkFound if template fraction is insufficient
585 checkTemplateIsSufficient(template[science.getBBox()], science, self.log,
586 self.config.minTemplateFractionForExpectedSuccess,
587 exceptionMessage="Template coverage lower than expected to succeed."
588 f" Failure is tolerable: {e}")
589 # checkTemplateIsSufficient did not raise NoWorkFound, so raise original exception
590 raise e
591
592 return lsst.pipe.base.Struct(backgroundModel=kernelResult.backgroundModel,
593 psfMatchingKernel=kernelResult.psfMatchingKernel,
594 kernelSources=kernelSources)
595

◆ runQuantum()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.runQuantum ( self,
butlerQC,
inputRefs,
outputRefs )

Definition at line 405 of file subtractImages.py.

405 def runQuantum(self, butlerQC, inputRefs, outputRefs):
406 inputs = butlerQC.get(inputRefs)
407
408 try:
409 results = self.run(**inputs)
410 except lsst.pipe.base.AlgorithmError as e:
411 error = lsst.pipe.base.AnnotatedPartialOutputsError.annotate(e, self, log=self.log)
412 # No partial outputs for butler to put
413 raise error from e
414
415 butlerQC.put(results, outputRefs)
416

◆ updateMasks()

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.updateMasks ( self,
template,
science )
Update the science and template mask planes before differencing.

Parameters
----------
template : `lsst.afw.image.Exposure`
    Template exposure, warped to match the science exposure.
    The template mask planes will be erased, except for a few specified
    in the task config.
science : `lsst.afw.image.Exposure`
    Science exposure to subtract from the template.
    The DETECTED and DETECTED_NEGATIVE mask planes of the science image
    will be erased.

Definition at line 1091 of file subtractImages.py.

1091 def updateMasks(self, template, science):
1092 """Update the science and template mask planes before differencing.
1093
1094 Parameters
1095 ----------
1096 template : `lsst.afw.image.Exposure`
1097 Template exposure, warped to match the science exposure.
1098 The template mask planes will be erased, except for a few specified
1099 in the task config.
1100 science : `lsst.afw.image.Exposure`
1101 Science exposure to subtract from the template.
1102 The DETECTED and DETECTED_NEGATIVE mask planes of the science image
1103 will be erased.
1104 """
1105 self._clearMask(science.mask, clearMaskPlanes=["DETECTED", "DETECTED_NEGATIVE"])
1106
1107 # We will clear ALL template mask planes, except for those specified
1108 # via the `preserveTemplateMask` config. Mask planes specified via
1109 # the `renameTemplateMask` config will be copied to new planes with
1110 # "_TEMPLATE" appended to their names, and the original mask plane will
1111 # be cleared.
1112 clearMaskPlanes = [mp for mp in template.mask.getMaskPlaneDict().keys()
1113 if mp not in self.config.preserveTemplateMask]
1114 renameMaskPlanes = [mp for mp in self.config.renameTemplateMask
1115 if mp in template.mask.getMaskPlaneDict().keys()]
1116
1117 # propagate the mask plane related to Fake source injection
1118 # NOTE: the fake source injection sets FAKE plane, but it should be INJECTED
1119 # NOTE: This can be removed in DM-40796
1120 if "FAKE" in science.mask.getMaskPlaneDict().keys():
1121 self.log.info("Adding injected mask plane to science image")
1122 self._renameMaskPlanes(science.mask, "FAKE", "INJECTED")
1123 if "FAKE" in template.mask.getMaskPlaneDict().keys():
1124 self.log.info("Adding injected mask plane to template image")
1125 self._renameMaskPlanes(template.mask, "FAKE", "INJECTED_TEMPLATE")
1126 if "INJECTED" in renameMaskPlanes:
1127 renameMaskPlanes.remove("INJECTED")
1128 if "INJECTED_TEMPLATE" in clearMaskPlanes:
1129 clearMaskPlanes.remove("INJECTED_TEMPLATE")
1130
1131 for maskPlane in renameMaskPlanes:
1132 self._renameMaskPlanes(template.mask, maskPlane, maskPlane + "_TEMPLATE")
1133 self._clearMask(template.mask, clearMaskPlanes=clearMaskPlanes)
1134

Member Data Documentation

◆ _DefaultName

str lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask._DefaultName = "alardLuptonSubtract"
staticprotected

Definition at line 347 of file subtractImages.py.

◆ ConfigClass

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.ConfigClass = AlardLuptonSubtractConfig
static

Definition at line 346 of file subtractImages.py.

◆ convolutionControl

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.convolutionControl = lsst.afw.math.ConvolutionControl()

Definition at line 358 of file subtractImages.py.

◆ log

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.log

Definition at line 585 of file subtractImages.py.

◆ sciencePsfSize

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.sciencePsfSize = getPsfFwhm(science.psf)

Definition at line 1050 of file subtractImages.py.

◆ templatePsfSize

lsst.ip.diffim.subtractImages.AlardLuptonSubtractTask.templatePsfSize

Definition at line 512 of file subtractImages.py.


The documentation for this class was generated from the following file: