28 from lsstDebug 
import getDebugFrame
 
   35 from lsst.utils.timer 
import timeMethod
 
   37 from .repair 
import RepairTask
 
   41     """!Describes the initial PSF used for detection and measurement before we do PSF determination.""" 
   43     model = pexConfig.ChoiceField(
 
   46         default=
"SingleGaussian",
 
   48             "SingleGaussian": 
"Single Gaussian model",
 
   49             "DoubleGaussian": 
"Double Gaussian model",
 
   52     pixelScale = pexConfig.Field(
 
   54         doc=
"Pixel size (arcsec).  Only needed if no Wcs is provided",
 
   57     fwhm = pexConfig.Field(
 
   59         doc=
"FWHM of PSF model (arcsec)",
 
   62     size = pexConfig.Field(
 
   64         doc=
"Size of PSF model (pixels)",
 
   70     doRepair = pexConfig.Field(
 
   72         doc=
"Repair images (CR reject and interpolate) before combining",
 
   75     repairPsfFwhm = pexConfig.Field(
 
   77         doc=
"Psf FWHM (pixels) used to detect CRs",
 
   80     doDiffIm = pexConfig.Field(
 
   82         doc=
"Perform difference imaging before combining",
 
   85     doPsfMatch = pexConfig.Field(
 
   87         doc=
"Perform PSF matching for difference imaging (ignored if doDiffIm false)",
 
   90     doMeasurement = pexConfig.Field(
 
   92         doc=
"Measure difference sources (ignored if doDiffIm false)",
 
   95     badMaskPlanes = pexConfig.ListField(
 
   97         doc=
"Mask planes that, if set, the associated pixels are not included in the combined exposure; " 
   98         "DETECTED excludes cosmic rays",
 
   99         default=(
"DETECTED",),
 
  101     averageKeys = pexConfig.ListField(
 
  103         doc=
"List of float metadata keys to average when combining snaps, e.g. float positions and dates; " 
  104         "non-float data must be handled by overriding the fixMetadata method",
 
  108     sumKeys = pexConfig.ListField(
 
  110         doc=
"List of float or int metadata keys to sum when combining snaps, e.g. exposure time; " 
  111         "non-float, non-int data must be handled by overriding the fixMetadata method",
 
  115     repair = pexConfig.ConfigurableField(target=RepairTask, doc=
"")
 
  116     diffim = pexConfig.ConfigurableField(target=SnapPsfMatchTask, doc=
"")
 
  117     detection = pexConfig.ConfigurableField(target=SourceDetectionTask, doc=
"")
 
  118     initialPsf = pexConfig.ConfigField(dtype=InitialPsfConfig, doc=
"")
 
  119     measurement = pexConfig.ConfigurableField(target=SingleFrameMeasurementTask, doc=
"")
 
  122         self.
detectiondetection.thresholdPolarity = 
"both" 
  125         if self.
detectiondetection.thresholdPolarity != 
"both":
 
  126             raise ValueError(
"detection.thresholdPolarity must be 'both' for SnapCombineTask")
 
  138     \anchor SnapCombineTask_ 
  140     \brief Combine snaps. 
  142     \section pipe_tasks_snapcombine_Contents Contents 
  144      - \ref pipe_tasks_snapcombine_Debug 
  146     \section pipe_tasks_snapcombine_Debug Debug variables 
  148     The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a 
  149     flag \c -d to import \b debug.py from your \c PYTHONPATH; see <a 
  150     href="https://developer.lsst.io/stack/debug.html">Debugging Tasks with lsstDebug</a> for more 
  151     about \b debug.py files. 
  153     The available variables in SnapCombineTask are: 
  156       <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are: 
  159           <DD> Display the first snap after repairing. 
  161           <DD> Display the second snap after repairing. 
  166     ConfigClass = SnapCombineConfig
 
  167     _DefaultName = 
"snapCombine" 
  170         pipeBase.Task.__init__(self, *args, **kwargs)
 
  171         self.makeSubtask(
"repair")
 
  172         self.makeSubtask(
"diffim")
 
  173         self.
schemaschema = afwTable.SourceTable.makeMinimalSchema()
 
  175         self.makeSubtask(
"detection", schema=self.
schemaschema)
 
  176         if self.config.doMeasurement:
 
  177             self.makeSubtask(
"measurement", schema=self.
schemaschema, algMetadata=self.
algMetadataalgMetadata)
 
  180     def run(self, snap0, snap1, defects=None):
 
  183         @param[in] snap0: snapshot exposure 0 
  184         @param[in] snap1: snapshot exposure 1 
  185         @defects[in] defect list (for repair task) 
  186         @return a pipe_base Struct with fields: 
  187         - exposure: snap-combined exposure 
  188         - sources: detected sources, or None if detection not performed 
  193         if self.config.doRepair:
 
  194             self.log.
info(
"snapCombine repair")
 
  195             psf = self.
makeInitialPsfmakeInitialPsf(snap0, fwhmPix=self.config.repairPsfFwhm)
 
  198             self.repair.
run(snap0, defects=defects, keepCRs=
False)
 
  199             self.repair.
run(snap1, defects=defects, keepCRs=
False)
 
  208         if self.config.doDiffIm:
 
  209             if self.config.doPsfMatch:
 
  210                 self.log.
info(
"snapCombine psfMatch")
 
  211                 diffRet = self.diffim.
run(snap0, snap1, 
"subtractExposures")
 
  212                 diffExp = diffRet.subtractedImage
 
  216                 diffKern = diffRet.psfMatchingKernel
 
  217                 width, height = diffKern.getDimensions()
 
  220                 diffExp = afwImage.ExposureF(snap0, 
True)
 
  221                 diffMi = diffExp.getMaskedImage()
 
  222                 diffMi -= snap1.getMaskedImage()
 
  226             table = afwTable.SourceTable.make(self.
schemaschema)
 
  228             detRet = self.detection.
run(table, diffExp)
 
  229             sources = detRet.sources
 
  230             fpSets = detRet.fpSets
 
  231             if self.config.doMeasurement:
 
  232                 self.measurement.
measure(diffExp, sources)
 
  234             mask0 = snap0.getMaskedImage().getMask()
 
  235             mask1 = snap1.getMaskedImage().getMask()
 
  236             fpSets.positive.setMask(mask0, 
"DETECTED")
 
  237             fpSets.negative.setMask(mask1, 
"DETECTED")
 
  239             maskD = diffExp.getMaskedImage().getMask()
 
  240             fpSets.positive.setMask(maskD, 
"DETECTED")
 
  241             fpSets.negative.setMask(maskD, 
"DETECTED_NEGATIVE")
 
  243         combinedExp = self.
addSnapsaddSnaps(snap0, snap1)
 
  245         return pipeBase.Struct(
 
  246             exposure=combinedExp,
 
  251         """Add two snap exposures together, returning a new exposure 
  253         @param[in] snap0 snap exposure 0 
  254         @param[in] snap1 snap exposure 1 
  255         @return combined exposure 
  257         self.log.
info(
"snapCombine addSnaps")
 
  259         combinedExp = snap0.Factory(snap0, 
True)
 
  260         combinedMi = combinedExp.getMaskedImage()
 
  263         weightMap = combinedMi.getImage().
Factory(combinedMi.getBBox())
 
  265         badPixelMask = afwImage.Mask.getPlaneBitMask(self.config.badMaskPlanes)
 
  266         addToCoadd(combinedMi, weightMap, snap0.getMaskedImage(), badPixelMask, weight)
 
  267         addToCoadd(combinedMi, weightMap, snap1.getMaskedImage(), badPixelMask, weight)
 
  272         combinedMi /= weightMap
 
  278         combinedMetadata = combinedExp.getMetadata()
 
  279         metadata0 = snap0.getMetadata()
 
  280         metadata1 = snap1.getMetadata()
 
  281         self.
fixMetadatafixMetadata(combinedMetadata, metadata0, metadata1)
 
  286         """Fix the metadata of the combined exposure (in place) 
  288         This implementation handles items specified by config.averageKeys and config.sumKeys, 
  289         which have data type restrictions. To handle other data types (such as sexagesimal 
  290         positions and ISO dates) you must supplement this method with your own code. 
  292         @param[in,out] combinedMetadata metadata of combined exposure; 
  293             on input this is a deep copy of metadata0 (a PropertySet) 
  294         @param[in] metadata0 metadata of snap0 (a PropertySet) 
  295         @param[in] metadata1 metadata of snap1 (a PropertySet) 
  297         @note the inputs are presently PropertySets due to ticket #2542. However, in some sense 
  298         they are just PropertyLists that are missing some methods. In particular: comments and order 
  299         are preserved if you alter an existing value with set(key, value). 
  302         if self.config.averageKeys:
 
  303             keyDoAvgList += [(key, 1) 
for key 
in self.config.averageKeys]
 
  304         if self.config.sumKeys:
 
  305             keyDoAvgList += [(key, 0) 
for key 
in self.config.sumKeys]
 
  306         for key, doAvg 
in keyDoAvgList:
 
  307             opStr = 
"average" if doAvg 
else "sum" 
  309                 val0 = metadata0.getScalar(key)
 
  310                 val1 = metadata1.getScalar(key)
 
  312                 self.log.
warning(
"Could not %s metadata %r: missing from one or both exposures", opStr, key)
 
  316                 combinedVal = val0 + val1
 
  320                 self.log.
warning(
"Could not %s metadata %r: value %r and/or %r not numeric",
 
  321                                  opStr, key, val0, val1)
 
  324             combinedMetadata.set(key, combinedVal)
 
  327         """Initialise the detection procedure by setting the PSF and WCS 
  329         @param exposure Exposure to process 
  332         assert exposure, 
"No exposure provided" 
  333         wcs = exposure.getWcs()
 
  334         assert wcs, 
"No wcs in exposure" 
  337             fwhmPix = self.config.initialPsf.fwhm / wcs.getPixelScale().asArcseconds()
 
  339         size = self.config.initialPsf.size
 
  340         model = self.config.initialPsf.model
 
  341         self.log.
info(
"installInitialPsf fwhm=%s pixels; size=%s pixels", fwhmPix, size)
 
  342         psfCls = getattr(measAlg, model + 
"Psf")
 
  343         psf = psfCls(size, size, fwhmPix/(2.0*num.sqrt(2*num.log(2.0))))
 
Class for storing ordered metadata with comments.
Describes the initial PSF used for detection and measurement before we do PSF determination.
def fixMetadata(self, combinedMetadata, metadata0, metadata1)
def makeInitialPsf(self, exposure, fwhmPix=None)
def run(self, snap0, snap1, defects=None)
def __init__(self, *args, **kwargs)
def addSnaps(self, snap0, snap1)
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def measure(mi, x, y, size, statistic, stats)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.
def getDebugFrame(debugDisplay, name)