def process(self): logging.Trace_setVerbosity("lsst.detection", 5) logging.Trace( "lsst.detection.DetectionStage", 3, 'Python DetectionStage process : _rank %i stageId %d' % (self._rank, self.stageId)) activeClipboard = self.inputQueue.getNextDataset() ########### # # Get objects from clipboard # triggerEvent = activeClipboard.get('triggerVisitEvent') filterNameItem = triggerEvent.findUnique('filterName') filterName = filterNameItem.getValueString() exposureIdItem = triggerEvent.findUnique('exposureId') exposureId = exposureIdItem.getValueInt() visitTimeItem = triggerEvent.findUnique('visitTime') visitTime = visitTimeItem.getValueDouble() ########### # # Log the beginning of Detection stage for this slice # LogRec(self.detectionLog, Log.INFO) \ << "Began detection stage" \ << DataProperty("exposureId", exposureId) \ << DataProperty("visitTime", visitTime) \ << DataProperty("filterName", filterName) \ << LogRec.endr # # Instantiate a Filter object to get the id of filterName # dbLocation = dafper.LogicalLocation( 'mysql://lsst10.ncsa.uiuc.edu:3306/test') filterDB = lsst.afw.image.Filter(dbLocation, filterName) filterId = filterDB.getId() logging.Trace("lsst.detection.DetectionStage", 3, 'FilterName %s FilterId %d' % (filterName, filterId)) differenceImageExposure = activeClipboard.get('DifferenceExposure') diaSourceCollection = Detection.detection( differenceImageExposure=differenceImageExposure, policy=self._policy, filterId=filterId, useLog=self.detectionLog, footprintList=None, ) ########### # # Post results to clipboard # activeClipboard.put('DiaSources', diaSourceCollection) self.outputQueue.addDataset(activeClipboard)
def stats(self, cid, diffim, core=5): self.dStats.apply(diffim) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Candidate %d : Residuals all (%d px): %.3f +/- %.3f" % (cid, self.dStats.getNpix(), self.dStats.getMean(), self.dStats.getRms())) self.dStats.apply(diffim, core) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Candidate %d : Residuals core (%d px): %.3f +/- %.3f" % (cid, self.dStats.getNpix(), self.dStats.getMean(), self.dStats.getRms()))
def _createPcaBasis(self, kernelCellSet, nStarPerCell, policy): """!Create Principal Component basis If a principal component analysis is requested, typically when using a delta function basis, perform the PCA here and return a new basis list containing the new principal components. @param kernelCellSet: a SpatialCellSet containing KernelCandidates, from which components are derived @param nStarPerCell: the number of stars per cell to visit when doing the PCA @param policy: input policy controlling the single kernel visitor @return - nRejectedPca: number of KernelCandidates rejected during PCA loop - spatialBasisList: basis list containing the principal shapes as Kernels """ nComponents = self.kConfig.numPrincipalComponents imagePca = diffimLib.KernelPcaD() importStarVisitor = diffimLib.KernelPcaVisitorF(imagePca) kernelCellSet.visitCandidates(importStarVisitor, nStarPerCell) if self.kConfig.subtractMeanForPca: importStarVisitor.subtractMean() imagePca.analyze() eigenValues = imagePca.getEigenValues() pcaBasisList = importStarVisitor.getEigenKernels() eSum = num.sum(eigenValues) if eSum == 0.0: raise RuntimeError("Eigenvalues sum to zero") for j in range(len(eigenValues)): pexLog.Trace( self.log.getName() + "._solve", 6, "Eigenvalue %d : %f (%f)" % (j, eigenValues[j], eigenValues[j] / eSum)) nToUse = min(nComponents, len(eigenValues)) trimBasisList = afwMath.KernelList() for j in range(nToUse): # Check for NaNs? kimage = afwImage.ImageD(pcaBasisList[j].getDimensions()) pcaBasisList[j].computeImage(kimage, False) if not (True in num.isnan(kimage.getArray())): trimBasisList.push_back(pcaBasisList[j]) # Put all the power in the first kernel, which will not vary spatially spatialBasisList = diffimLib.renormalizeKernelList(trimBasisList) # New Kernel visitor for this new basis list (no regularization explicitly) singlekvPca = diffimLib.BuildSingleKernelVisitorF( spatialBasisList, policy) singlekvPca.setSkipBuilt(False) kernelCellSet.visitCandidates(singlekvPca, nStarPerCell) singlekvPca.setSkipBuilt(True) nRejectedPca = singlekvPca.getNRejected() return nRejectedPca, spatialBasisList
def assess(self, cand, kFn1, bgFn1, kFn2, bgFn2, frame0): tmi = cand.getTemplateMaskedImage() smi = cand.getScienceMaskedImage() im1 = afwImage.ImageD(kFn1.getDimensions()) kFn1.computeImage(im1, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk1 = afwMath.FixedKernel(im1) bg1 = bgFn1(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d1 = ipDiffim.convolveAndSubtract(tmi, smi, fk1, bg1) #### im2 = afwImage.ImageD(kFn2.getDimensions()) kFn2.computeImage(im2, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk2 = afwMath.FixedKernel(im2) bg2 = bgFn2(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d2 = ipDiffim.convolveAndSubtract(tmi, smi, fk2, bg2) if display: ds9.mtv(tmi, frame=frame0+0) ds9.dot("Cand %d" % (cand.getId()), 0, 0, frame=frame0+0) ds9.mtv(smi, frame=frame0+1) ds9.mtv(im1, frame=frame0+2) ds9.mtv(d1, frame=frame0+3) ds9.mtv(im2, frame=frame0+4) ds9.mtv(d2, frame=frame0+5) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Full Spatial Model") self.stats(cand.getId(), d1) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "N-1 Spatial Model") self.stats(cand.getId(), d2)
def jackknifeResample(self, psfmatch, results): kernel = results.psfMatchingKernel bg = results.backgroundModel cellSet = results.kernelCellSet goodList = [] for cell in cellSet.getCellList(): print for cand in cell.begin(False): cand = ipDiffim.cast_KernelCandidateF(cand) if cand.getStatus() == afwMath.SpatialCellCandidate.GOOD: goodList.append(cand.getId()) else: # This is so that UNKNOWNs are not processed cand.setStatus(afwMath.SpatialCellCandidate.BAD) nStarPerCell = self.config.nStarPerCell policy = pexConfig.makePolicy(self.config) for idx in range(len(goodList)): cid = goodList[idx] print # clear the screen pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Removing candidate %d" % (cid)) cand = self.setStatus(cellSet, cid, afwMath.SpatialCellCandidate.BAD) # From _solve regionBBox = cellSet.getBBox() spatialkv = ipDiffim.BuildSpatialKernelVisitorF(kernel.getKernelList(), regionBBox, policy) cellSet.visitCandidates(spatialkv, nStarPerCell) spatialkv.solveLinearEquation() jkKernel, jkBg = spatialkv.getSolutionPair() #jkResults = psfmatch._solve(cellSet, kernel.getKernelList()) #jkKernel = jkResults[1] #jkBg = jkResults[2] # lots of windows # self.assess(cand, kernel, bg, jkKernel, jkBg, 6*idx+1) # only 6 windows self.assess(cand, kernel, bg, jkKernel, jkBg, 1) self.setStatus(cellSet, cid, afwMath.SpatialCellCandidate.GOOD)
def runTest(self, mode): pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Mode %s" % (mode)) if mode == "DF": self.config = self.subconfigDF elif mode == "DFr": self.config = self.subconfigDFr elif mode == "AL": self.config = self.subconfigAL else: raise psfmatch = ipDiffim.ImagePsfMatchTask(self.config) results = psfmatch.run(self.templateMaskedImage, self.scienceMaskedImage, "subtractMaskedImages") self.jackknifeResample(psfmatch, results)
def backgroundSubtract(config, maskedImages): backgrounds = [] t0 = time.time() algorithm = config.algorithm binsize = config.binSize undersample = config.undersampleStyle bctrl = afwMath.BackgroundControl(algorithm) bctrl.setUndersampleStyle(undersample) for maskedImage in maskedImages: bctrl.setNxSample(maskedImage.getWidth()//binsize + 1) bctrl.setNySample(maskedImage.getHeight()//binsize + 1) image = maskedImage.getImage() backobj = afwMath.makeBackground(image, bctrl) image -= backobj.getImageF() backgrounds.append(backobj.getImageF()) del backobj t1 = time.time() pexLog.Trace("lsst.ip.diffim.backgroundSubtract", 1, "Total time for background subtraction : %.2f s" % (t1-t0)) return backgrounds
def testTraceFromPython(self): pexLog.Trace.setVerbosity("lsst.afw", 3) pexLog.Trace("lsst.afw", 2, "Hello") pexLog.Trace("lsst.afw", 5, "world")
def EventFromInputFileList(inputfile, datatypePolicy, expTime=EXP_TIME, slewTime=SLEW_TIME, maxvisits=-1, rootTopicName=ROOT_EVENT_TOPIC, hostName=EVENT_BROKER, metadataPolicy=None): """ Generate events for the IPSD (and MOPS) pipeline by reading a list of visit directories and extracting the relevant information from the FITS files therein. The two optional parameters are the exposure time of each exposure in a visit (assumed constant) and the average slew time of the telescope. Both are in seconds. The default to 15 seconds and 5 seconds respecively. The script sends one event for the first visit exposure, waits <exp time> sec and then sends an event for the second exposure. At that point, it waits (<exp time> + <slew time>) sec before passing to the next visit. The input directory list is a simple text file listing visit directories one per line. Comments start with a '#' and are ignored. It is assumed that the name of each directory in the file is a valid visitId. Also it is assumed that each directory has the following structure: visitId/ 0/ raw-<visitId>-e000-c<ccdId>-a<ampId>.fits 1/ raw-<visitId>-e001-c<ccdId>-a<ampId>.fits @param inputfile name of the directory list file. @param datatypePolicy policy file for the input data. @param expTime assumed exposure per visit in seconds (defaults to 15 seconds for DC3). @param slewTime assumed average slew time in seconds (defaults to 5 seconds for DC3). @param rootTopicName root name for the event's topic. The final topic will be rootTopicName+'0' or rootTopicName+'1' depending on whether the event refers to the first or second image of the visit. @param hostName hostname of the event broker. @param metadataPolicy policy defining the event metadata types @return None """ global visitCount # Create a metadata policy object. if metadataPolicy is None: mpf = pexPolicy.DefaultPolicyFile("ctrl_dc3pipe", "dc3MetadataPolicy.paf", "pipeline") metadataPolicy = pexPolicy.Policy.createPolicy(mpf, mpf.getRepositoryPath()) # Covenience function. def sendEvent(f): return(eventFromFitsfile.EventFromInputfile(f, datatypePolicy, metadataPolicy, rootTopicName, hostName)) f = open(inputfile) for line in f: dirName = line.strip() if(line.startswith('#')): continue visitCount += 1 if maxvisits >= 0 and visitCount > maxvisits: logger.log(logger.INFO, "Maximum visit count reached (%s); quitting." % maxvisits) return # Get the list of amp FITS files in each dir. fileList0 = glob.glob(os.path.join(dirName, '0', '*.fits')) fileList1 = glob.glob(os.path.join(dirName, '1', '*.fits')) # Simple sanity check. if(len(fileList0) != len(fileList1)): pexLog.Trace('dc3pipe.eventfrominputfilelist', 1, 'Skipping %s: wrong file count in 0 and 1' \ %(dirName)) continue # Now we just trust that the i-th file in 0 corresponds to the i-th file # in 1... Fortunately, we only need to send one event per image # directory, since all images there are one MEF split into individual # amps. sendEvent(fileList0[0]) # Sleep some. time.sleep(expTime) # Next event. sendEvent(fileList1[0]) # Sleep expTime + slewTime. time.sleep(expTime + slewTime) f.close() return
def _solve(self, kernelCellSet, basisList, returnOnExcept=False): """!Solve for the PSF matching kernel @param kernelCellSet: a SpatialCellSet to use in determining the matching kernel (typically as provided by _buildCellSet) @param basisList: list of Kernels to be used in the decomposition of the spatially varying kernel (typically as provided by makeKernelBasisList) @param returnOnExcept: if True then return (None, None) if an error occurs, else raise the exception @return - psfMatchingKernel: PSF matching kernel - backgroundModel: differential background model Raise Exception if unable to determine PSF matching kernel and returnOnExcept False """ import lsstDebug display = lsstDebug.Info(__name__).display maxSpatialIterations = self.kConfig.maxSpatialIterations nStarPerCell = self.kConfig.nStarPerCell usePcaForSpatialKernel = self.kConfig.usePcaForSpatialKernel # Visitor for the single kernel fit policy = pexConfig.makePolicy(self.kConfig) if self.useRegularization: singlekv = diffimLib.BuildSingleKernelVisitorF( basisList, policy, self.hMat) else: singlekv = diffimLib.BuildSingleKernelVisitorF(basisList, policy) # Visitor for the kernel sum rejection ksv = diffimLib.KernelSumVisitorF(policy) # Main loop t0 = time.time() try: totalIterations = 0 thisIteration = 0 while (thisIteration < maxSpatialIterations): # Make sure there are no uninitialized candidates as active occupants of Cell nRejectedSkf = -1 while (nRejectedSkf != 0): pexLog.Trace(self.log.getName() + "._solve", 2, "Building single kernels...") kernelCellSet.visitCandidates(singlekv, nStarPerCell) nRejectedSkf = singlekv.getNRejected() pexLog.Trace( self.log.getName() + "._solve", 2, "Iteration %d, rejected %d candidates due to initial kernel fit" % (thisIteration, nRejectedSkf)) # Reject outliers in kernel sum ksv.resetKernelSum() ksv.setMode(diffimLib.KernelSumVisitorF.AGGREGATE) kernelCellSet.visitCandidates(ksv, nStarPerCell) ksv.processKsumDistribution() ksv.setMode(diffimLib.KernelSumVisitorF.REJECT) kernelCellSet.visitCandidates(ksv, nStarPerCell) nRejectedKsum = ksv.getNRejected() pexLog.Trace( self.log.getName() + "._solve", 2, "Iteration %d, rejected %d candidates due to kernel sum" % (thisIteration, nRejectedKsum)) # Do we jump back to the top without incrementing thisIteration? if nRejectedKsum > 0: totalIterations += 1 continue # At this stage we can either apply the spatial fit to # the kernels, or we run a PCA, use these as a *new* # basis set with lower dimensionality, and then apply # the spatial fit to these kernels if (usePcaForSpatialKernel): pexLog.Trace(self.log.getName() + "._solve", 1, "Building Pca basis") nRejectedPca, spatialBasisList = self._createPcaBasis( kernelCellSet, nStarPerCell, policy) pexLog.Trace( self.log.getName() + "._solve", 2, "Iteration %d, rejected %d candidates due to Pca kernel fit" % (thisIteration, nRejectedPca)) # We don't want to continue on (yet) with the # spatial modeling, because we have bad objects # contributing to the Pca basis. We basically # need to restart from the beginning of this loop, # since the cell-mates of those objects that were # rejected need their original Kernels built by # singleKernelFitter. # Don't count against thisIteration if (nRejectedPca > 0): totalIterations += 1 continue else: spatialBasisList = basisList # We have gotten on to the spatial modeling part regionBBox = kernelCellSet.getBBox() spatialkv = diffimLib.BuildSpatialKernelVisitorF( spatialBasisList, regionBBox, policy) kernelCellSet.visitCandidates(spatialkv, nStarPerCell) spatialkv.solveLinearEquation() pexLog.Trace( self.log.getName() + "._solve", 3, "Spatial kernel built with %d candidates" % (spatialkv.getNCandidates())) spatialKernel, spatialBackground = spatialkv.getSolutionPair() # Check the quality of the spatial fit (look at residuals) assesskv = diffimLib.AssessSpatialKernelVisitorF( spatialKernel, spatialBackground, policy) kernelCellSet.visitCandidates(assesskv, nStarPerCell) nRejectedSpatial = assesskv.getNRejected() nGoodSpatial = assesskv.getNGood() pexLog.Trace( self.log.getName() + "._solve", 2, "Iteration %d, rejected %d candidates due to spatial kernel fit" % (thisIteration, nRejectedSpatial)) pexLog.Trace(self.log.getName() + "._solve", 2, "%d candidates used in fit" % (nGoodSpatial)) # If only nGoodSpatial == 0, might be other candidates in the cells if nGoodSpatial == 0 and nRejectedSpatial == 0: raise RuntimeError("No kernel candidates for spatial fit") if nRejectedSpatial == 0: # Nothing rejected, finished with spatial fit break # Otherwise, iterate on... thisIteration += 1 # Final fit if above did not converge if (nRejectedSpatial > 0) and (thisIteration == maxSpatialIterations): pexLog.Trace(self.log.getName() + "._solve", 2, "Final spatial fit") if (usePcaForSpatialKernel): nRejectedPca, spatialBasisList = self._createPcaBasis( kernelCellSet, nStarPerCell, policy) regionBBox = kernelCellSet.getBBox() spatialkv = diffimLib.BuildSpatialKernelVisitorF( spatialBasisList, regionBBox, policy) kernelCellSet.visitCandidates(spatialkv, nStarPerCell) spatialkv.solveLinearEquation() pexLog.Trace( self.log.getName() + "._solve", 3, "Spatial kernel built with %d candidates" % (spatialkv.getNCandidates())) spatialKernel, spatialBackground = spatialkv.getSolutionPair() spatialSolution = spatialkv.getKernelSolution() except Exception as e: pexLog.Trace(self.log.getName() + "._solve", 1, "ERROR: Unable to calculate psf matching kernel") pexLog.Trace(self.log.getName() + "._solve", 2, str(e)) raise e t1 = time.time() pexLog.Trace( self.log.getName() + "._solve", 1, "Total time to compute the spatial kernel : %.2f s" % (t1 - t0)) if display: self._displayDebug(kernelCellSet, spatialKernel, spatialBackground) self._diagnostic(kernelCellSet, spatialSolution, spatialKernel, spatialBackground) return spatialSolution, spatialKernel, spatialBackground
def matchMaskedImages(self, templateMaskedImage, scienceMaskedImage, candidateList, templateFwhmPix=None, scienceFwhmPix=None): """!PSF-match a MaskedImage (templateMaskedImage) to a reference MaskedImage (scienceMaskedImage) Do the following, in order: - Determine a PSF matching kernel and differential background model that matches templateMaskedImage to scienceMaskedImage - Convolve templateMaskedImage by the PSF matching kernel @param templateMaskedImage: masked image to PSF-match to the reference masked image; must be warped to match the reference masked image @param scienceMaskedImage: maskedImage whose PSF is to be matched to @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve) @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image @param candidateList: a list of footprints/maskedImages for kernel candidates; if None then source detection is run. - Currently supported: list of Footprints or measAlg.PsfCandidateF @return a pipeBase.Struct containing these fields: - psfMatchedMaskedImage: the PSF-matched masked image = templateMaskedImage convolved with psfMatchingKernel. This has the same xy0, dimensions and wcs as scienceMaskedImage. - psfMatchingKernel: the PSF matching kernel - backgroundModel: differential background model - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel Raise a RuntimeError if input images have different dimensions """ import lsstDebug display = lsstDebug.Info(__name__).display displayTemplate = lsstDebug.Info(__name__).displayTemplate displaySciIm = lsstDebug.Info(__name__).displaySciIm displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells maskTransparency = lsstDebug.Info(__name__).maskTransparency if not maskTransparency: maskTransparency = 0 if display: ds9.setMaskTransparency(maskTransparency) if not candidateList: raise RuntimeError( "Candidate list must be populated by makeCandidateList") if not self._validateSize(templateMaskedImage, scienceMaskedImage): pexLog.Trace(self.log.getName(), 1, "ERROR: Input images different size") raise RuntimeError("Input images different size") if display and displayTemplate: ds9.mtv(templateMaskedImage, frame=lsstDebug.frame, title="Image to convolve") lsstDebug.frame += 1 if display and displaySciIm: ds9.mtv(scienceMaskedImage, frame=lsstDebug.frame, title="Image to not convolve") lsstDebug.frame += 1 kernelCellSet = self._buildCellSet(templateMaskedImage, scienceMaskedImage, candidateList) if display and displaySpatialCells: diUtils.showKernelSpatialCells(scienceMaskedImage, kernelCellSet, symb="o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, ctypeBad=ds9.RED, size=4, frame=lsstDebug.frame, title="Image to not convolve") lsstDebug.frame += 1 if templateFwhmPix and scienceFwhmPix: self.log.info("Matching Psf FWHM %.2f -> %.2f pix" % (templateFwhmPix, scienceFwhmPix)) if self.kConfig.useBicForKernelBasis: tmpKernelCellSet = self._buildCellSet(templateMaskedImage, scienceMaskedImage, candidateList) nbe = diffimTools.NbasisEvaluator(self.kConfig, templateFwhmPix, scienceFwhmPix) bicDegrees = nbe(tmpKernelCellSet, self.log) basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix, alardDegGauss=bicDegrees[0], metadata=self.metadata) del tmpKernelCellSet else: basisList = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix, metadata=self.metadata) spatialSolution, psfMatchingKernel, backgroundModel = self._solve( kernelCellSet, basisList) psfMatchedMaskedImage = afwImage.MaskedImageF( templateMaskedImage.getBBox()) doNormalize = False afwMath.convolve(psfMatchedMaskedImage, templateMaskedImage, psfMatchingKernel, doNormalize) return pipeBase.Struct( matchedImage=psfMatchedMaskedImage, psfMatchingKernel=psfMatchingKernel, backgroundModel=backgroundModel, kernelCellSet=kernelCellSet, )
def _buildCellSet(self, exposure, referencePsfModel): """!Build a SpatialCellSet for use with the solve method @param exposure: The science exposure that will be convolved; must contain a Psf @param referencePsfModel: Psf model to match to @return kernelCellSet: a SpatialCellSet to be used by self._solve Raise a RuntimeError if the reference Psf model and science Psf model have different dimensions """ scienceBBox = exposure.getBBox() sciencePsfModel = exposure.getPsf() # The Psf base class does not support getKernel() in general, as there are some Psf # classes for which this is not meaningful. # Many Psfs we use in practice are KernelPsfs, and this algorithm will work fine for them, # but someday it should probably be modified to support arbitrary Psfs. referencePsfModel = measAlg.KernelPsf.swigConvert(referencePsfModel) sciencePsfModel = measAlg.KernelPsf.swigConvert(sciencePsfModel) if referencePsfModel is None or sciencePsfModel is None: raise RuntimeError( "ERROR: Psf matching is only implemented for KernelPsfs") if (referencePsfModel.getKernel().getDimensions() != sciencePsfModel.getKernel().getDimensions()): pexLog.Trace( self.log.getName(), 1, "ERROR: Dimensions of reference Psf and science Psf different; exiting" ) raise RuntimeError, "ERROR: Dimensions of reference Psf and science Psf different; exiting" psfWidth, psfHeight = referencePsfModel.getKernel().getDimensions() maxKernelSize = min(psfWidth, psfHeight) - 1 if maxKernelSize % 2 == 0: maxKernelSize -= 1 if self.kConfig.kernelSize > maxKernelSize: raise ValueError, "Kernel size (%d) too big to match Psfs of size %d; reduce to at least %d" % ( self.kConfig.kernelSize, psfWidth, maxKernelSize) # Infer spatial order of Psf model! # # Infer from the number of spatial parameters. # (O + 1) * (O + 2) / 2 = N # O^2 + 3 * O + 2 * (1 - N) = 0 # # Roots are [-3 +/- sqrt(9 - 8 * (1 - N))] / 2 # nParameters = sciencePsfModel.getKernel().getNSpatialParameters() root = num.sqrt(9 - 8 * (1 - nParameters)) if (root != root // 1): # We know its an integer solution pexLog.Trace(self.log.getName(), 3, "Problem inferring spatial order of image's Psf") else: order = (root - 3) / 2 if (order != order // 1): pexLog.Trace(self.log.getName(), 3, "Problem inferring spatial order of image's Psf") else: pexLog.Trace( self.log.getName(), 2, "Spatial order of Psf = %d; matching kernel order = %d" % (order, self.kConfig.spatialKernelOrder)) regionSizeX, regionSizeY = scienceBBox.getDimensions() scienceX0, scienceY0 = scienceBBox.getMin() sizeCellX = self.kConfig.sizeCellX sizeCellY = self.kConfig.sizeCellY kernelCellSet = afwMath.SpatialCellSet( afwGeom.Box2I(afwGeom.Point2I(scienceX0, scienceY0), afwGeom.Extent2I(regionSizeX, regionSizeY)), sizeCellX, sizeCellY) nCellX = regionSizeX // sizeCellX nCellY = regionSizeY // sizeCellY dimenR = referencePsfModel.getKernel().getDimensions() dimenS = sciencePsfModel.getKernel().getDimensions() policy = pexConfig.makePolicy(self.kConfig) for row in range(nCellY): # place at center of cell posY = sizeCellY * row + sizeCellY // 2 + scienceY0 for col in range(nCellX): # place at center of cell posX = sizeCellX * col + sizeCellX // 2 + scienceX0 pexLog.Trace( self.log.getName(), 5, "Creating Psf candidate at %.1f %.1f" % (posX, posY)) # reference kernel image, at location of science subimage kernelImageR = referencePsfModel.computeImage( afwGeom.Point2D(posX, posY)).convertF() kernelMaskR = afwImage.MaskU(dimenR) kernelMaskR.set(0) kernelVarR = afwImage.ImageF(dimenR) kernelVarR.set(1.0) referenceMI = afwImage.MaskedImageF(kernelImageR, kernelMaskR, kernelVarR) # kernel image we are going to convolve kernelImageS = sciencePsfModel.computeImage( afwGeom.Point2D(posX, posY)).convertF() kernelMaskS = afwImage.MaskU(dimenS) kernelMaskS.set(0) kernelVarS = afwImage.ImageF(dimenS) kernelVarS.set(1.0) scienceMI = afwImage.MaskedImageF(kernelImageS, kernelMaskS, kernelVarS) # The image to convolve is the science image, to the reference Psf. kc = diffimLib.makeKernelCandidate(posX, posY, scienceMI, referenceMI, policy) kernelCellSet.insertCandidate(kc) import lsstDebug display = lsstDebug.Info(__name__).display displaySpatialCells = lsstDebug.Info(__name__).displaySpatialCells maskTransparency = lsstDebug.Info(__name__).maskTransparency if not maskTransparency: maskTransparency = 0 if display: ds9.setMaskTransparency(maskTransparency) if display and displaySpatialCells: diUtils.showKernelSpatialCells(exposure.getMaskedImage(), kernelCellSet, symb="o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, ctypeBad=ds9.RED, size=4, frame=lsstDebug.frame, title="Image to be convolved") lsstDebug.frame += 1 return kernelCellSet
def applyVisitor(self, invert=False, xloc=397, yloc=580): print '# %.2f %.2f' % (xloc, yloc) #if xloc != 1312 and yloc != 160: # return imsize = int(3 * self.subconfig1.kernelSize) # chop out a region around a known object bbox = afwGeom.Box2I( afwGeom.Point2I(xloc - imsize / 2, yloc - imsize / 2), afwGeom.Point2I(xloc + imsize / 2, yloc + imsize / 2)) # sometimes the box goes off the image; no big deal... try: if invert: tmi = afwImage.MaskedImageF( self.scienceExposure.getMaskedImage(), bbox, afwImage.LOCAL) smi = afwImage.MaskedImageF( self.templateExposure.getMaskedImage(), bbox, afwImage.LOCAL) else: smi = afwImage.MaskedImageF( self.scienceExposure.getMaskedImage(), bbox, afwImage.LOCAL) tmi = afwImage.MaskedImageF( self.templateExposure.getMaskedImage(), bbox, afwImage.LOCAL) except Exception: return None # delta function kernel logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, 'DF run') results1 = self.apply(pexConfig.makePolicy(self.subconfig1), self.bskv1, xloc, yloc, tmi, smi) kSum1, bg1, dmean1, dstd1, vmean1, kImageOut1, diffIm1, kc1 = results1 res = 'DF residuals : %.3f +/- %.3f; %.2f, %.2f; %.2f %.2f, %.2f' % ( self.dStats.getMean(), self.dStats.getRms(), kSum1, bg1, dmean1, dstd1, vmean1) logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, res) if display: ds9.mtv(tmi, frame=1) # ds9 switches frame 0 and 1 for some reason ds9.mtv(smi, frame=0) ds9.mtv(kImageOut1, frame=2) ds9.mtv(diffIm1, frame=3) if writefits: tmi.writeFits('t.fits') smi.writeFits('s.fits') kImageOut1.writeFits('k1.fits') diffIm1.writeFits('d1.fits') # regularized delta function kernel logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, 'DFrC5 run') results2 = self.apply(pexConfig.makePolicy(self.subconfig2), self.bskv2, xloc, yloc, tmi, smi) kSum2, bg2, dmean2, dstd2, vmean2, kImageOut2, diffIm2, kc2 = results2 res = 'DFrC5 residuals : %.3f +/- %.3f; %.2f, %.2f; %.2f %.2f, %.2f' % ( self.dStats.getMean(), self.dStats.getRms(), kSum2, bg2, dmean2, dstd2, vmean2) logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, res) if display: ds9.mtv(tmi, frame=4) ds9.mtv(smi, frame=5) ds9.mtv(kImageOut2, frame=6) ds9.mtv(diffIm2, frame=7) if writefits: kImageOut2.writeFits('k2.fits') diffIm2.writeFits('d2') # regularized delta function kernel logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, 'DFrC9 run') results3 = self.apply(pexConfig.makePolicy(self.subconfig3), self.bskv3, xloc, yloc, tmi, smi) kSum3, bg3, dmean3, dstd3, vmean3, kImageOut3, diffIm3, kc3 = results3 res = 'DFrC9 residuals : %.3f +/- %.3f; %.2f, %.2f; %.2f %.2f, %.2f' % ( self.dStats.getMean(), self.dStats.getRms(), kSum3, bg3, dmean3, dstd3, vmean3) logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, res) if display: ds9.mtv(tmi, frame=8) ds9.mtv(smi, frame=9) ds9.mtv(kImageOut3, frame=10) ds9.mtv(diffIm3, frame=11) if writefits: kImageOut2.writeFits('k3.fits') diffIm2.writeFits('d3') # regularized delta function kernel logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, 'DFrF12 run') results4 = self.apply(pexConfig.makePolicy(self.subconfig4), self.bskv4, xloc, yloc, tmi, smi) kSum4, bg4, dmean4, dstd4, vmean4, kImageOut4, diffIm4, kc4 = results4 res = 'DFrF12 residuals : %.3f +/- %.3f; %.2f, %.2f; %.2f %.2f, %.2f' % ( self.dStats.getMean(), self.dStats.getRms(), kSum4, bg4, dmean4, dstd4, vmean4) logging.Trace("lsst.ip.diffim.compareLambdaTypes", 1, res) if display: ds9.mtv(tmi, frame=12) ds9.mtv(smi, frame=13) ds9.mtv(kImageOut4, frame=14) ds9.mtv(diffIm4, frame=15) if writefits: kImageOut2.writeFits('k4.fits') diffIm2.writeFits('d4') raw_input('Next: ')
def detection(differenceImageExposure, policy, filterId, useLog=None, footprintList=None): """Detect and measure objects in an incoming difference image Exposure Inputs: - differenceImageExposure: an lsst.afw.image.Exposure containing a difference MaskedImage and WCS - policy: the policy; required elements are...? - footprintList: a sequence of detection footprints on which to force measurement Returns: - an lsst.afw.detection.SourceVector """ if not (useLog): useLog = ScreenLog() useLog.setScreenVerbose(True) logging.Trace("lsst.detection.detection", 3, "filterId = %d" % (filterId)) ########### # # Get directives from policy # thresh = policy.get('thresholdSigma') nPixMin = policy.get('numPixMinFootprint') ########### # # Unpack the MaskedImage from the Exposure # img = differenceImageExposure.getMaskedImage() ########### # # Crudely estimate noise from mean of variance image - should do sigma clipping # varImg = img.getVariance() noise = math.sqrt(afwImage.mean_channel_value(varImg)) logging.Trace( "lsst.detection.detection", 3, "thresholdSigma = %r; noise = %r PixMin = %r" % (thresh, noise, nPixMin)) LogRec(useLog, Log.INFO) \ << "Threshold computation" \ << DataProperty("thresholdSigma", thresh) \ << DataProperty("noise", noise) \ << DataProperty("threshold", thresh*noise) \ << LogRec.endr ########### # # Build the DetectionSet for positive sources # dsPositive = det.DetectionSetF( img, det.Threshold(thresh * noise, det.Threshold.VALUE, True), "FP+", nPixMin) fpVecPositive = dsPositive.getFootprints() print "Positive detections: ", len(fpVecPositive) LogRec(useLog, Log.INFO) \ << "Positive detections" \ << DataProperty("nPositive", len(fpVecPositive)) \ << LogRec.endr ########### # # Build the DetectionSet for negative sources # dsNegative = det.DetectionSetF( img, det.Threshold(thresh * noise, det.Threshold.VALUE, False), "FP-", nPixMin) fpVecNegative = dsNegative.getFootprints() print "Negative detections: ", len(fpVecNegative) LogRec(useLog, Log.INFO) \ << "Negative detections" \ << DataProperty("nNegative", len(fpVecNegative)) \ << LogRec.endr ########### # # Measure the FootPrints # imgWCS = differenceImageExposure.getWcs() outputDiaSources = afwDet.DiaSourceVec() imgMeasure = det.MeasureF(img, "FP+") id = 0 for i in range(len(fpVecPositive)): diaPtr = afwDet.DiaSourcePtr() diaPtr.setId(id) diaPtr.setFilterId(filterId) imgMeasure.measureSource( diaPtr, fpVecPositive[i], 0.0) # NOTE explicit background of zero used for difference image pixCoord = afwImage.Coord2D(diaPtr.getColc(), diaPtr.getRowc()) skyCoord = imgWCS.colRowToRaDec(pixCoord) diaPtr.setRa(skyCoord.x()) diaPtr.setDec(skyCoord.y()) outputDiaSources.push_back(diaPtr.get()) id += 1 imgMeasure = det.MeasureF(img, "FP-") for i in range(len(fpVecNegative)): diaPtr = afwDet.DiaSourcePtr() diaPtr.setId(id) diaPtr.setFilterId(filterId) imgMeasure.measureSource( diaPtr, fpVecNegative[i], 0.0) # NOTE explicit background of zero used for difference image pixCoord = afwImage.Coord2D(diaPtr.getColc(), diaPtr.getRowc()) skyCoord = imgWCS.colRowToRaDec(pixCoord) diaPtr.setRa(skyCoord.x()) diaPtr.setDec(skyCoord.y()) outputDiaSources.push_back(diaPtr.get()) id += 1 ########### # # Return the DiaSources # return outputDiaSources
def matchExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True): """!Warp and PSF-match an exposure to the reference Do the following, in order: - Warp templateExposure to match scienceExposure, if doWarping True and their WCSs do not already match - Determine a PSF matching kernel and differential background model that matches templateExposure to scienceExposure - Convolve templateExposure by PSF matching kernel @param templateExposure: Exposure to warp and PSF-match to the reference masked image @param scienceExposure: Exposure whose WCS and PSF are to be matched to @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve) @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image @param candidateList: a list of footprints/maskedImages for kernel candidates; if None then source detection is run. - Currently supported: list of Footprints or measAlg.PsfCandidateF @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match: - if True then warp templateExposure to match scienceExposure - if False then raise an Exception @param convolveTemplate: convolve the template image or the science image - if True, templateExposure is warped if doWarping, templateExposure is convolved - if False, templateExposure is warped if doWarping, scienceExposure is convolved @return a pipeBase.Struct containing these fields: - matchedImage: the PSF-matched exposure = warped templateExposure convolved by psfMatchingKernel. This has: - the same parent bbox, Wcs and Calib as scienceExposure - the same filter as templateExposure - no Psf (because the PSF-matching process does not compute one) - psfMatchingKernel: the PSF matching kernel - backgroundModel: differential background model - kernelCellSet: SpatialCellSet used to solve for the PSF matching kernel Raise a RuntimeError if doWarping is False and templateExposure's and scienceExposure's WCSs do not match """ if not self._validateWcs(templateExposure, scienceExposure): if doWarping: self.log.info( "Astrometrically registering template to science image") templatePsf = templateExposure.getPsf() templateExposure = self._warper.warpExposure( scienceExposure.getWcs(), templateExposure, destBBox=scienceExposure.getBBox()) templateExposure.setPsf(templatePsf) else: pexLog.Trace(self.log.getName(), 1, "ERROR: Input images not registered") raise RuntimeError("Input images not registered") if templateFwhmPix is None: if not templateExposure.hasPsf(): self.log.warn("No estimate of Psf FWHM for template image") else: templateFwhmPix = self.getFwhmPix(templateExposure.getPsf()) if scienceFwhmPix is None: if not scienceExposure.hasPsf(): self.log.warn("No estimate of Psf FWHM for science image") else: scienceFwhmPix = self.getFwhmPix(scienceExposure.getPsf()) kernelSize = makeKernelBasisList(self.kConfig, templateFwhmPix, scienceFwhmPix)[0].getWidth() candidateList = self.makeCandidateList(templateExposure, scienceExposure, kernelSize, candidateList) if convolveTemplate: results = self.matchMaskedImages(templateExposure.getMaskedImage(), scienceExposure.getMaskedImage(), candidateList, templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix) else: results = self.matchMaskedImages(scienceExposure.getMaskedImage(), templateExposure.getMaskedImage(), candidateList, templateFwhmPix=scienceFwhmPix, scienceFwhmPix=templateFwhmPix) psfMatchedExposure = afwImage.makeExposure(results.matchedImage, scienceExposure.getWcs()) psfMatchedExposure.setFilter(templateExposure.getFilter()) psfMatchedExposure.setCalib(scienceExposure.getCalib()) results.warpedExposure = templateExposure results.matchedExposure = psfMatchedExposure return results
def generateAlardLuptonBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None): """Generate an Alard-Lupton kernel basis based upon the Config and the input FWHM of the science and template images""" if config.kernelBasisSet != "alard-lupton": raise RuntimeError( "Cannot generate %s basis within generateAlardLuptonBasisList" % config.kernelBasisSet) kernelSize = config.kernelSize fwhmScaling = config.kernelSizeFwhmScaling basisNGauss = config.alardNGauss basisSigmaGauss = config.alardSigGauss basisGaussBeta = config.alardGaussBeta basisMinSigma = config.alardMinSig if basisDegGauss is None: basisDegGauss = config.alardDegGauss if len(basisDegGauss) != basisNGauss: raise ValueError("len(basisDegGauss) != basisNGauss : %d vs %d" % (len(basisDegGauss), basisNGauss)) if len(basisSigmaGauss) != basisNGauss: raise ValueError("len(basisSigmaGauss) != basisNGauss : %d vs %d" % (len(basisSigmaGauss), basisNGauss)) if (kernelSize % 2) != 1: raise ValueError("Only odd-sized Alard-Lupton bases allowed") if (targetFwhmPix is None) or (referenceFwhmPix is None) or (not config.scaleByFwhm): if metadata is not None: metadata.add("ALBasisNGauss", basisNGauss) metadata.add("ALBasisDegGauss", basisDegGauss) metadata.add("ALBasisSigGauss", basisSigmaGauss) metadata.add("ALKernelSize", kernelSize) return diffimLib.makeAlardLuptonBasisList(kernelSize // 2, basisNGauss, basisSigmaGauss, basisDegGauss) targetSigma = targetFwhmPix / sigma2fwhm referenceSigma = referenceFwhmPix / sigma2fwhm pexLog.Trace( "lsst.ip.diffim.generateAlardLuptonBasisList", 2, "Generating matching bases for sigma %.2f pix -> %.2f pix" % (targetSigma, referenceSigma)) # Modify the size of Alard Lupton kernels based upon the images FWHM # # Note the operation is : template.x.kernel = science # # Assuming the template and science image Psfs are Gaussians with # the Fwhm above, Fwhm_T **2 + Fwhm_K **2 = Fwhm_S **2 # if targetSigma == referenceSigma: # Leave defaults as-is pass elif referenceSigma > targetSigma: # Normal convolution # First Gaussian has the sigma that comes from the convolution # of two Gaussians : Sig_S**2 = Sig_T**2 + Sig_K**2 # # If it's larger than basisMinSigma * basisGaussBeta, make it the # second kernel. Else make it the smallest kernel. Unless # only 1 kernel is asked for. kernelSigma = np.sqrt(referenceSigma**2 - targetSigma**2) if kernelSigma < basisMinSigma: kernelSigma = basisMinSigma basisSigmaGauss = [] if basisNGauss == 1: basisSigmaGauss.append(kernelSigma) nAppended = 1 else: if (kernelSigma / basisGaussBeta) > basisMinSigma: basisSigmaGauss.append(kernelSigma / basisGaussBeta) basisSigmaGauss.append(kernelSigma) nAppended = 2 else: basisSigmaGauss.append(kernelSigma) nAppended = 1 # Any other Gaussians above basisNGauss=1 come from a scaling # relationship: Sig_i+1 / Sig_i = basisGaussBeta for i in range(nAppended, basisNGauss): basisSigmaGauss.append(basisSigmaGauss[-1] * basisGaussBeta) kernelSize = int(fwhmScaling * basisSigmaGauss[-1]) kernelSize += 0 if kernelSize % 2 else 1 # Make sure it's odd kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin)) else: # Deconvolution; Define the progression of Gaussians using a # method to derive a deconvolution sum-of-Gaussians from it's # convolution counterpart. Only use 3 since the algorithm # assumes 3 components. # # http://iopscience.iop.org/0266-5611/26/8/085002 Equation 40 # Use specializations for deconvolution basisNGauss = config.alardNGaussDeconv basisMinSigma = config.alardMinSigDeconv kernelSigma = np.sqrt(targetSigma**2 - referenceSigma**2) if kernelSigma < basisMinSigma: kernelSigma = basisMinSigma basisSigmaGauss = [] if (kernelSigma / basisGaussBeta) > basisMinSigma: basisSigmaGauss.append(kernelSigma / basisGaussBeta) basisSigmaGauss.append(kernelSigma) nAppended = 2 else: basisSigmaGauss.append(kernelSigma) nAppended = 1 for i in range(nAppended, basisNGauss): basisSigmaGauss.append(basisSigmaGauss[-1] * basisGaussBeta) kernelSize = int(fwhmScaling * basisSigmaGauss[-1]) kernelSize += 0 if kernelSize % 2 else 1 # Make sure it's odd kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin)) # Now build a deconvolution set from these sigmas sig0 = basisSigmaGauss[0] sig1 = basisSigmaGauss[1] sig2 = basisSigmaGauss[2] basisSigmaGauss = [] for n in range(1, 3): for j in range(n): sigma2jn = (n - j) * sig1**2 sigma2jn += j * sig2**2 sigma2jn -= (n + 1) * sig0**2 sigmajn = np.sqrt(sigma2jn) basisSigmaGauss.append(sigmajn) basisSigmaGauss.sort() basisNGauss = len(basisSigmaGauss) basisDegGauss = [config.alardDegGaussDeconv for x in basisSigmaGauss] if metadata is not None: metadata.add("ALBasisNGauss", basisNGauss) metadata.add("ALBasisDegGauss", basisDegGauss) metadata.add("ALBasisSigGauss", basisSigmaGauss) metadata.add("ALKernelSize", kernelSize) return diffimLib.makeAlardLuptonBasisList(kernelSize // 2, basisNGauss, basisSigmaGauss, basisDegGauss)
def testSource(self, source, subMi): imArr, maArr, varArr = subMi.getArrays() flux = source.getApFlux() nPixels = subMi.getWidth() * subMi.getHeight() nPos, nNeg, fPos, fNeg = self.countPolarity(maArr, imArr) nDetPos, nDetNeg = self.countDetected(maArr) nMasked = self.countMasked(maArr) assert (nPixels == (nMasked + nPos + nNeg)) # 1) Too many pixels in the detection are masked fMasked = (nMasked / nPixels) fMaskedTol = self.config.fBadPixels if fMasked > fMaskedTol: pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : BAD fBadPixels %.2f > %.2f" % (source.getId(), fMasked, fMaskedTol)) return False if flux > 0: # positive-going source fluxRatio = fPos / (fPos + abs(fNeg)) ngoodRatio = nPos / nPixels maskRatio = nPos / (nPos + nMasked) npolRatio = nPos / (nPos + nNeg) else: # negative-going source fluxRatio = abs(fNeg) / (fPos + abs(fNeg)) ngoodRatio = nNeg / nPixels maskRatio = nNeg / (nNeg + nMasked) npolRatio = nNeg / (nNeg + nPos) # 2) Not enough flux in unmasked correct-polarity pixels fluxRatioTolerance = self.config.fluxPolarityRatio if fluxRatio < fluxRatioTolerance: pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : BAD flux polarity %.2f < %.2f (pos=%.2f neg=%.2f)" % (source.getId(), fluxRatio, fluxRatioTolerance, fPos, fNeg)) return False # 3) Not enough unmasked pixels of correct polarity polarityTolerance = self.config.nPolarityRatio if npolRatio < polarityTolerance: pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : BAD polarity count %.2f < %.2f (pos=%d neg=%d)" % (source.getId(), npolRatio, polarityTolerance, nPos, nNeg)) return False # 4) Too many masked vs. correct polarity pixels maskedTolerance = self.config.nMaskedRatio if maskRatio < maskedTolerance: pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : BAD unmasked count %.2f < %.2f (pos=%d neg=%d mask=%d)" % (source.getId(), maskRatio, maskedTolerance, nPos, nNeg, nMasked)) return False # 5) Too few unmasked, correct polarity pixels ngoodTolerance = self.config.nGoodRatio if ngoodRatio < ngoodTolerance: pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : BAD good pixel count %.2f < %.2f (pos=%d neg=%d tot=%d)" % (source.getId(), ngoodRatio, ngoodTolerance, nPos, nNeg, nPixels)) return False pexLog.Trace( "lsst.ip.diffim.DiaSourceAnalysis", 1, "Candidate %d : OK flux=%.2f nPos=%d nNeg=%d nTot=%d nDetPos=%d nDetNeg=%d fPos=%.2f fNeg=%2f" % (source.getId(), flux, nPos, nNeg, nPixels, nDetPos, nDetNeg, fPos, fNeg)) return True