23 __all__ = [
"SnapPsfMatchConfigDF",
"SnapPsfMatchConfigAL",
"SnapPsfMatchConfig",
"SnapPsfMatchTask"]
26 from .psfMatch
import PsfMatchConfigDF, PsfMatchConfigAL
27 from .imagePsfMatch
import ImagePsfMatchTask, ImagePsfMatchConfig
31 """Delta-function Psf-matching config optimized for snap subtraction""" 34 PsfMatchConfigDF.setDefaults(self)
46 """Sum-of-Gaussian (Alard-Lupton) Psf-matching config optimized for snap subtraction""" 49 PsfMatchConfigAL.setDefaults(self)
58 kernel = pexConfig.ConfigChoiceField(
61 AL=SnapPsfMatchConfigAL,
62 DF=SnapPsfMatchConfigDF
67 doWarping = pexConfig.Field(
69 doc=
"Warp the snaps?",
74 ImagePsfMatchConfig.setDefaults(self)
77 self.
kernel.active.spatialKernelOrder = 0
80 self.
kernel.active.fitForBackground =
False 83 self.
kernel.active.kernelSize = 7
86 self.
kernel.active.spatialKernelClipping =
False 90 """Image-based Psf-matching of two subsequent snaps from the same visit 94 This Task differs from ImagePsfMatchTask in that it matches two Exposures assuming that the images have 95 been acquired very closely in time. Under this assumption, the astrometric misalignments and/or 96 relative distortions should be within a pixel, and the Psf-shapes should be very similar. As a 97 consequence, the default configurations for this class assume a very simple solution. 99 - The spatial variation in the kernel (SnapPsfMatchConfig.spatialKernelOrder) is assumed to be zero 101 - With no spatial variation, we turn of the spatial 102 clipping loops (SnapPsfMatchConfig.spatialKernelClipping) 104 - The differential background is not fit for (SnapPsfMatchConfig.fitForBackground) 106 - The kernel is expected to be appx. 107 a delta function, and has a small size (SnapPsfMatchConfig.kernelSize) 109 The sub-configurations for the Alard-Lupton (SnapPsfMatchConfigAL) 110 and delta-function (SnapPsfMatchConfigDF) 111 bases also are designed to generate a small, simple kernel. 115 Initialization is the same as base class ImagePsfMatch.__init__, 116 with the difference being that the Task's 117 ConfigClass is SnapPsfMatchConfig. 121 The Task is only configured to have a subtractExposures method, which in turn calls 122 ImagePsfMatchTask.subtractExposures. 124 Configuration parameters 126 See SnapPsfMatchConfig, which uses either SnapPsfMatchConfigDF and SnapPsfMatchConfigAL 127 as its active configuration. 131 The lsst.pipe.base.cmdLineTask.CmdLineTask command line task interface supports a 132 flag -d/--debug to importdebug.py from your PYTHONPATH. The relevant contents of debug.py 133 for this Task include: 140 di = lsstDebug.getInfo(name) 141 if name == "lsst.ip.diffim.psfMatch": 142 di.display = True # enable debug output 143 di.maskTransparency = 80 # ds9 mask transparency 144 di.displayCandidates = True # show all the candidates and residuals 145 di.displayKernelBasis = False # show kernel basis functions 146 di.displayKernelMosaic = True # show kernel realized across the image 147 di.plotKernelSpatialModel = False # show coefficients of spatial model 148 di.showBadCandidates = True # show the bad candidates (red) along with good (green) 149 elif name == "lsst.ip.diffim.imagePsfMatch": 150 di.display = True # enable debug output 151 di.maskTransparency = 30 # ds9 mask transparency 152 di.displayTemplate = True # show full (remapped) template 153 di.displaySciIm = True # show science image to match to 154 di.displaySpatialCells = True # show spatial cells 155 di.displayDiffIm = True # show difference image 156 di.showBadCandidates = True # show the bad candidates (red) along with good (green) 157 elif name == "lsst.ip.diffim.diaCatalogSourceSelector": 158 di.display = False # enable debug output 159 di.maskTransparency = 30 # ds9 mask transparency 160 di.displayExposure = True # show exposure with candidates indicated 161 di.pauseAtEnd = False # pause when done 163 lsstDebug.Info = DebugInfo 166 Note that if you want addional logging info, you may add to your scripts: 170 import lsst.log.utils as logUtils 171 logUtils.traceSetAt("ip.diffim", 4) 175 This code is snapPsfMatchTask.py in the examples directory, and can be run as e.g. 179 examples/snapPsfMatchTask.py 180 examples/snapPsfMatchTask.py --debug 181 examples/snapPsfMatchTask.py --debug --template /path/to/templateExp.fits 182 --science /path/to/scienceExp.fits 184 First, create a subclass of SnapPsfMatchTask that accepts two exposures. 185 Ideally these exposures would have been taken back-to-back, 186 such that the pointing/background/Psf does not vary substantially between the two: 190 class MySnapPsfMatchTask(SnapPsfMatchTask): 191 def __init__(self, *args, **kwargs): 192 SnapPsfMatchTask.__init__(self, *args, **kwargs) 193 def run(self, templateExp, scienceExp): 194 return self.subtractExposures(templateExp, scienceExp) 196 And allow the user the freedom to either run the script in default mode, 197 or point to their own images on disk. Note that these images must be 198 readable as an lsst.afw.image.Exposure 202 if __name__ == "__main__": 204 parser = argparse.ArgumentParser(description="Demonstrate the use of ImagePsfMatchTask") 205 parser.add_argument("--debug", "-d", action="store_true", help="Load debug.py?", default=False) 206 parser.add_argument("--template", "-t", help="Template Exposure to use", default=None) 207 parser.add_argument("--science", "-s", help="Science Exposure to use", default=None) 208 args = parser.parse_args() 210 We have enabled some minor display debugging in this script via the –debug option. However, 211 if you have an lsstDebug debug.in your PYTHONPATH you will get additional debugging displays. 212 The following block checks for this script 219 # Since I am displaying 2 images here, set the starting frame number for the LSST debug LSST 220 debug.lsstDebug.frame = 3 221 except ImportError as e: 222 print(e, file=sys.stderr) 224 Finally, we call a run method that we define below. 225 First set up a Config and choose the basis set to use: 231 # Create the Config and use sum of gaussian basis 233 config = SnapPsfMatchTask.ConfigClass() 234 config.doWarping = True 235 config.kernel.name = "AL" 237 Make sure the images (if any) that were sent to the script exist on disk and are readable. 238 If no images are sent, make some fake data up for the sake of this example script 239 (have a look at the code if you want more details on generateFakeImages; 240 as a detail of how the fake images were made, you do have to fit for a differential background): 244 # Run the requested method of the Task 245 if args.template is not None and args.science is not None: 246 if not os.path.isfile(args.template): 247 raise Exception("Template image %s does not exist" % (args.template)) 248 if not os.path.isfile(args.science): 249 raise Exception("Science image %s does not exist" % (args.science)) 251 templateExp = afwImage.ExposureF(args.template) 252 except Exception as e: 253 raise Exception("Cannot read template image %s" % (args.template)) 255 scienceExp = afwImage.ExposureF(args.science) 256 except Exception as e: 257 raise Exception("Cannot read science image %s" % (args.science)) 259 templateExp, scienceExp = generateFakeImages() 260 config.kernel.active.fitForBackground = True 261 config.kernel.active.spatialBgOrder = 0 262 config.kernel.active.sizeCellX = 128 263 config.kernel.active.sizeCellY = 128 265 Display the two images if -debug 270 ds9.mtv(templateExp, frame=1, title="Example script: Input Template") 271 ds9.mtv(scienceExp, frame=2, title="Example script: Input Science Image") 273 Create and run the Task 278 psfMatchTask = MySnapPsfMatchTask(config=config) 280 result = psfMatchTask.run(templateExp, scienceExp) 282 And finally provide optional debugging display of the Psf-matched (via the Psf models) science image: 287 # See if the LSST debug has incremented the frame number; if not start with frame 3 289 frame = debug.lsstDebug.frame + 1 292 ds9.mtv(result.matchedExposure, frame=frame, title="Example script: Matched Template Image") 293 if "subtractedExposure" in result.getDict(): 294 ds9.mtv(result.subtractedExposure, frame=frame+1, title="Example script: Subtracted Image") 298 ConfigClass = SnapPsfMatchConfig
302 templateFwhmPix=None, scienceFwhmPix=None,
304 return ImagePsfMatchTask.subtractExposures(self,
305 templateExposure=templateExposure,
306 scienceExposure=scienceExposure,
307 templateFwhmPix=templateFwhmPix,
308 scienceFwhmPix=scienceFwhmPix,
309 candidateList=candidateList,
310 doWarping=self.config.doWarping,
def subtractExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None)