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