def makePsfCandidates(self, starCat, exposure): """Make a list of PSF candidates from a star catalog. Parameters ---------- starCat : `lsst.afw.table.SourceCatalog` Catalog of stars, as returned by ``lsst.meas.algorithms.starSelector.run()``. exposure : `lsst.afw.image.Exposure` The exposure containing the sources. Returns ------- struct : `lsst.pipe.base.Struct` Results struct containing: - ``psfCandidates`` : List of PSF candidates (`list` of `lsst.meas.algorithms.PsfCandidate`). - ``goodStarCat`` : Subset of ``starCat`` that was successfully made into PSF candidates (`lsst.afw.table.SourceCatalog`). """ goodStarCat = SourceCatalog(starCat.schema) psfCandidateList = [] didSetSize = False for star in starCat: try: psfCandidate = makePsfCandidate(star, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know exposures's pixel type # (and hence psfCandidate's exact type) if not didSetSize: psfCandidate.setBorderWidth(self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2 * self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2 * self.config.borderWidth) didSetSize = True im = psfCandidate.getMaskedImage().getImage() except lsst.pex.exceptions.Exception as err: self.log.warning( "Failed to make a psfCandidate from star %d: %s", star.getId(), err) continue vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not np.isfinite(vmax): continue psfCandidateList.append(psfCandidate) goodStarCat.append(star) return pipeBase.Struct( psfCandidates=psfCandidateList, goodStarCat=goodStarCat, )
def makePsfCandidates(self, starCat, exposure): """Make a list of PSF candidates from a star catalog. Parameters ---------- starCat : `lsst.afw.table.SourceCatalog` Catalog of stars, as returned by ``lsst.meas.algorithms.starSelector.run()``. exposure : `lsst.afw.image.Exposure` The exposure containing the sources. Returns ------- struct : `lsst.pipe.base.Struct` Results struct containing: - ``psfCandidates`` : List of PSF candidates (`list` of `lsst.meas.algorithms.PsfCandidate`). - ``goodStarCat`` : Subset of ``starCat`` that was successfully made into PSF candidates (`lsst.afw.table.SourceCatalog`). """ goodStarCat = SourceCatalog(starCat.schema) psfCandidateList = [] didSetSize = False for star in starCat: try: psfCandidate = makePsfCandidate(star, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know exposures's pixel type # (and hence psfCandidate's exact type) if not didSetSize: psfCandidate.setBorderWidth(self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2*self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2*self.config.borderWidth) didSetSize = True im = psfCandidate.getMaskedImage().getImage() except lsst.pex.exceptions.Exception as err: self.log.warn("Failed to make a psfCandidate from star %d: %s", star.getId(), err) continue vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not np.isfinite(vmax): continue psfCandidateList.append(psfCandidate) goodStarCat.append(star) return pipeBase.Struct( psfCandidates=psfCandidateList, goodStarCat=goodStarCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches a match vector as produced by meas_astrom; required (defaults to None to match the StarSelector API and improve error handling) @return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug debugInfo = lsstDebug.Info(__name__) display = debugInfo.display pauseAtEnd = debugInfo.pauseAtEnd # pause when done if matches is None: raise RuntimeError("CatalogStarSelectorTask requires matches") mi = exposure.getMaskedImage() if display: frame = 1 ds9.mtv(mi, frame=frame, title="PSF candidates") isGoodSource = CheckSource(sourceCat, self.config.fluxLim, self.config.fluxMax, self.config.badFlags) starCat = SourceCatalog(sourceCat.schema) with ds9.Buffering(): for ref, source, d in matches: if not ref.get("resolved"): if not isGoodSource(source): symb, ctype = "+", ds9.RED else: starCat.append(source) symb, ctype = "+", ds9.GREEN if display: ds9.dot(symb, source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, frame=frame, ctype=ctype) if display and pauseAtEnd: input("Continue? y[es] p[db] ") return Struct(starCat=starCat, )
def makePsfCandidates(self, exposure, starCat): """!Make a list of PSF candidates from a star catalog @param[in] exposure the exposure containing the sources @param[in] starCat catalog of stars (an lsst.afw.table.SourceCatalog), e.g. as returned by the run or selectStars method @return an lsst.pipe.base.Struct with fields: - psfCandidates list of PSF candidates (lsst.meas.algorithms.PsfCandidate) - goodStarCat catalog of stars that were successfully made into PSF candidates (a subset of starCat) """ goodStarCat = SourceCatalog(starCat.schema) psfCandidateList = [] didSetSize = False for star in starCat: try: psfCandidate = algorithmsLib.makePsfCandidate(star, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type # (and hence psfCandidate's exact type) if not didSetSize: psfCandidate.setBorderWidth(self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2 * self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2 * self.config.borderWidth) didSetSize = True im = psfCandidate.getMaskedImage().getImage() except Exception as err: self.log.debug( "Failed to make a psfCandidate from star %d: %s", star.getId(), err) continue vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not np.isfinite(vmax): continue psfCandidateList.append(psfCandidate) goodStarCat.append(star) return pipeBase.Struct( psfCandidates=psfCandidateList, goodStarCat=goodStarCat, )
def makePsfCandidates(self, exposure, starCat): """!Make a list of PSF candidates from a star catalog @param[in] exposure the exposure containing the sources @param[in] starCat catalog of stars (an lsst.afw.table.SourceCatalog), e.g. as returned by the run or selectStars method @return an lsst.pipe.base.Struct with fields: - psfCandidates list of PSF candidates (lsst.meas.algorithms.PsfCandidate) - goodStarCat catalog of stars that were successfully made into PSF candidates (a subset of starCat) """ goodStarCat = SourceCatalog(starCat.schema) psfCandidateList = [] for star in starCat: try: psfCandidate = algorithmsLib.makePsfCandidate(star, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type # (and hence psfCandidate's exact type) if psfCandidate.getWidth() == 0: psfCandidate.setBorderWidth(self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2*self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2*self.config.borderWidth) im = psfCandidate.getMaskedImage().getImage() except Exception as err: self.log.warn("Failed to make a psfCandidate from star %d: %s" % (star.getId(), err)) continue vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not np.isfinite(vmax): continue psfCandidateList.append(psfCandidate) goodStarCat.append(star) return pipeBase.Struct( psfCandidates = psfCandidateList, goodStarCat = goodStarCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. \param[in] exposure the exposure containing the sources \param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) \param[in] matches astrometric matches; ignored by this star selector \return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info( __name__).displayExposure # display the Exposure + spatialCells plotMagSize = lsstDebug.Info( __name__).plotMagSize # display the magnitude-size relation dumpData = lsstDebug.Info( __name__).dumpData # dump data to pickle file? detector = exposure.getDetector() pixToTanXYTransform = None if detector is not None: tanSys = detector.makeCameraSys(TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap().get(tanSys) # # Look at the distribution of stars in the magnitude-size plane # flux = sourceCat.get(self.config.sourceFluxField) xx = numpy.empty(len(sourceCat)) xy = numpy.empty_like(xx) yy = numpy.empty_like(xx) for i, source in enumerate(sourceCat): Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if pixToTanXYTransform: p = afwGeom.Point2D(source.getX(), source.getY()) linTransform = pixToTanXYTransform.linearizeForwardTransform( p).getLinear() m = Quadrupole(Ixx, Iyy, Ixy) m.transform(linTransform) Ixx, Iyy, Ixy = m.getIxx(), m.getIyy(), m.getIxy() xx[i], xy[i], yy[i] = Ixx, Ixy, Iyy width = numpy.sqrt(0.5 * (xx + yy)) bad = reduce(lambda x, y: numpy.logical_or(x, sourceCat.get(y)), self.config.badFlags, False) bad = numpy.logical_or(bad, flux < self.config.fluxMin) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(width))) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(flux))) bad = numpy.logical_or(bad, width < self.config.widthMin) bad = numpy.logical_or(bad, width > self.config.widthMax) if self.config.fluxMax > 0: bad = numpy.logical_or(bad, flux > self.config.fluxMax) good = numpy.logical_not(bad) if not numpy.any(good): raise RuntimeError( "No objects passed our cuts for consideration as psf stars") mag = -2.5 * numpy.log10(flux[good]) width = width[good] # # Look for the maximum in the size histogram, then search upwards for the minimum that separates # the initial peak (of, we presume, stars) from the galaxies # if dumpData: import os import pickle as pickle _ii = 0 while True: pickleFile = os.path.expanduser( os.path.join("~", "widths-%d.pkl" % _ii)) if not os.path.exists(pickleFile): break _ii += 1 with open(pickleFile, "wb") as fd: pickle.dump(mag, fd, -1) pickle.dump(width, fd, -1) centers, clusterId = _kcenters( width, nCluster=4, useMedian=True, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize: fig = plot( mag, width, centers, clusterId, magType=self.config.sourceFluxField.split(".")[-1].title(), marker="+", markersize=3, markeredgewidth=None, ltype=':', clear=True) else: fig = None clusterId = _improveCluster( width, centers, clusterId, nsigma=self.config.nSigmaClip, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize: plot(mag, width, centers, clusterId, marker="x", markersize=3, markeredgewidth=None, clear=False) stellar = (clusterId == 0) # # We know enough to plot, if so requested # frame = 0 if fig: if display and displayExposure: ds9.mtv(exposure.getMaskedImage(), frame=frame, title="PSF candidates") global eventHandler eventHandler = EventHandler(fig.get_axes()[0], mag, width, sourceCat.getX()[good], sourceCat.getY()[good], frames=[frame]) fig.show() while True: try: reply = input("continue? [c h(elp) q(uit) p(db)] ").strip() except EOFError: reply = None if not reply: reply = "c" if reply: if reply[0] == "h": print("""\ We cluster the points; red are the stellar candidates and the other colours are other clusters. Points labelled + are rejects from the cluster (only for cluster 0). At this prompt, you can continue with almost any key; 'p' enters pdb, and 'h' prints this text If displayExposure is true, you can put the cursor on a point and hit 'p' to see it in ds9. """) elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break if display and displayExposure: mi = exposure.getMaskedImage() with ds9.Buffering(): for i, source in enumerate(sourceCat): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) starCat = SourceCatalog(sourceCat.table) goodSources = [s for g, s in zip(good, sourceCat) if g] for isStellar, source in zip(stellar, goodSources): if isStellar: starCat.append(source) return Struct(starCat=starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches astrometric matches; ignored by this star selector @return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug display = lsstDebug.Info(__name__).display isGoodSource = CheckSource(sourceCat.getTable(), self.config.badFlags, self.config.fluxLim, self.config.fluxMax) detector = exposure.getDetector() mi = exposure.getMaskedImage() # # Create an Image of Ixx v. Iyy, i.e. a 2-D histogram # # Use stats on our Ixx/yy values to determine the xMax/yMax range for clump image iqqList = [] for s in sourceCat: ixx, iyy = s.getIxx(), s.getIyy() # ignore NaN and unrealistically large values if (ixx == ixx and ixx < self.config.histMomentMax and iyy == iyy and iyy < self.config.histMomentMax and isGoodSource(s)): iqqList.append(s.getIxx()) iqqList.append(s.getIyy()) stat = afwMath.makeStatistics( iqqList, afwMath.MEANCLIP | afwMath.STDEVCLIP | afwMath.MAX) iqqMean = stat.getValue(afwMath.MEANCLIP) iqqStd = stat.getValue(afwMath.STDEVCLIP) iqqMax = stat.getValue(afwMath.MAX) iqqLimit = max(iqqMean + self.config.histMomentClip * iqqStd, self.config.histMomentMaxMultiplier * iqqMean) # if the max value is smaller than our range, use max as the limit, but don't go below N*mean if iqqLimit > iqqMax: iqqLimit = max(self.config.histMomentMinMultiplier * iqqMean, iqqMax) psfHist = _PsfShapeHistogram(detector=detector, xSize=self.config.histSize, ySize=self.config.histSize, ixxMax=iqqLimit, iyyMax=iqqLimit) if display: frame = 0 ds9.mtv(mi, frame=frame, title="PSF candidates") ctypes = [] for source in sourceCat: good = isGoodSource(source) if good: notRejected = psfHist.insert(source) if display: if good: if notRejected: ctypes.append(ds9.GREEN) # good else: ctypes.append(ds9.MAGENTA) # rejected else: ctypes.append(ds9.RED) # bad if display: with ds9.Buffering(): for source, ctype in zip(sourceCat, ctypes): ds9.dot("o", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) clumps = psfHist.getClumps(display=display) # # Go through and find all the PSF-like objects # # We'll split the image into a number of cells, each of which contributes only # one PSF candidate star # starCat = SourceCatalog(sourceCat.table) pixToTanXYTransform = None if detector is not None: tanSys = detector.makeCameraSys(TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap().get(tanSys) # psf candidate shapes must lie within this many RMS of the average shape # N.b. if Ixx == Iyy, Ixy = 0 the criterion is # dx^2 + dy^2 < self.config.clumpNSigma*(Ixx + Iyy) == 2*self.config.clumpNSigma*Ixx for source in sourceCat: if not isGoodSource(source): continue Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if pixToTanXYTransform: p = afwGeom.Point2D(source.getX(), source.getY()) linTransform = pixToTanXYTransform.linearizeForwardTransform( p).getLinear() m = Quadrupole(Ixx, Iyy, Ixy) m.transform(linTransform) Ixx, Iyy, Ixy = m.getIxx(), m.getIyy(), m.getIxy() x, y = psfHist.momentsToPixel(Ixx, Iyy) for clump in clumps: dx, dy = (x - clump.x), (y - clump.y) if math.sqrt(clump.a * dx * dx + 2 * clump.b * dx * dy + clump.c * dy * dy) < 2 * self.config.clumpNSigma: # A test for > would be confused by NaN if not isGoodSource(source): continue try: psfCandidate = algorithmsLib.makePsfCandidate( source, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type # (and hence psfCandidate's exact type) if psfCandidate.getWidth() == 0: psfCandidate.setBorderWidth( self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2 * self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2 * self.config.borderWidth) im = psfCandidate.getMaskedImage().getImage() if not numpy.isfinite( afwMath.makeStatistics( im, afwMath.MAX).getValue()): continue starCat.append(source) if display: ds9.dot("o", source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, frame=frame, ctype=ds9.CYAN) except Exception as err: self.log.error("Failed on source %s: %s" % (source.getId(), err)) break return Struct(starCat=starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. \param[in] exposure the exposure containing the sources \param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) \param[in] matches astrometric matches; ignored by this star selector \return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells plotMagSize = lsstDebug.Info(__name__).plotMagSize # display the magnitude-size relation dumpData = lsstDebug.Info(__name__).dumpData # dump data to pickle file? detector = exposure.getDetector() pixToTanXYTransform = None if detector is not None: tanSys = detector.makeCameraSys(TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap().get(tanSys) # # Look at the distribution of stars in the magnitude-size plane # flux = sourceCat.get(self.config.sourceFluxField) xx = numpy.empty(len(sourceCat)) xy = numpy.empty_like(xx) yy = numpy.empty_like(xx) for i, source in enumerate(sourceCat): Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if pixToTanXYTransform: p = afwGeom.Point2D(source.getX(), source.getY()) linTransform = pixToTanXYTransform.linearizeForwardTransform(p).getLinear() m = Quadrupole(Ixx, Iyy, Ixy) m.transform(linTransform) Ixx, Iyy, Ixy = m.getIxx(), m.getIyy(), m.getIxy() xx[i], xy[i], yy[i] = Ixx, Ixy, Iyy width = numpy.sqrt(0.5*(xx + yy)) bad = reduce(lambda x, y: numpy.logical_or(x, sourceCat.get(y)), self.config.badFlags, False) bad = numpy.logical_or(bad, flux < self.config.fluxMin) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(width))) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(flux))) bad = numpy.logical_or(bad, width < self.config.widthMin) bad = numpy.logical_or(bad, width > self.config.widthMax) if self.config.fluxMax > 0: bad = numpy.logical_or(bad, flux > self.config.fluxMax) good = numpy.logical_not(bad) if not numpy.any(good): raise RuntimeError("No objects passed our cuts for consideration as psf stars") mag = -2.5*numpy.log10(flux[good]) width = width[good] # # Look for the maximum in the size histogram, then search upwards for the minimum that separates # the initial peak (of, we presume, stars) from the galaxies # if dumpData: import os import cPickle as pickle _ii = 0 while True: pickleFile = os.path.expanduser(os.path.join("~", "widths-%d.pkl" % _ii)) if not os.path.exists(pickleFile): break _ii += 1 with open(pickleFile, "wb") as fd: pickle.dump(mag, fd, -1) pickle.dump(width, fd, -1) centers, clusterId = _kcenters(width, nCluster=4, useMedian=True, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize and pyplot: fig = plot(mag, width, centers, clusterId, magType=self.config.sourceFluxField.split(".")[-1].title(), marker="+", markersize=3, markeredgewidth=None, ltype=':', clear=True) else: fig = None clusterId = _improveCluster(width, centers, clusterId, nsigma = self.config.nSigmaClip, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize and pyplot: plot(mag, width, centers, clusterId, marker="x", markersize=3, markeredgewidth=None, clear=False) stellar = (clusterId == 0) # # We know enough to plot, if so requested # frame = 0 if fig: if display and displayExposure: ds9.mtv(exposure.getMaskedImage(), frame=frame, title="PSF candidates") global eventHandler eventHandler = EventHandler(fig.get_axes()[0], mag, width, sourceCat.getX()[good], sourceCat.getY()[good], frames=[frame]) fig.show() #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- while True: try: reply = raw_input("continue? [c h(elp) q(uit) p(db)] ").strip() except EOFError: reply = None if not reply: reply = "c" if reply: if reply[0] == "h": print """\ We cluster the points; red are the stellar candidates and the other colours are other clusters. Points labelled + are rejects from the cluster (only for cluster 0). At this prompt, you can continue with almost any key; 'p' enters pdb, and 'h' prints this text If displayExposure is true, you can put the cursor on a point and hit 'p' to see it in ds9. """ elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break if display and displayExposure: mi = exposure.getMaskedImage() with ds9.Buffering(): for i, source in enumerate(sourceCat): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) starCat = SourceCatalog(sourceCat.table) goodSources = [s for g, s in zip(good, sourceCat) if g] for isStellar, source in zip(stellar, goodSources): if isStellar: starCat.append(source) return Struct( starCat = starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """Select sources for Kernel candidates @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches a match vector as produced by meas_astrom; required (defaults to None to match the StarSelector API and improve error handling) @return an lsst.pipe.base.Struct containing: - starCat a list of sources to be used as kernel candidates """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info(__name__).displayExposure pauseAtEnd = lsstDebug.Info(__name__).pauseAtEnd if matches is None: raise RuntimeError("DiaCatalogSourceSelector requires matches") mi = exposure.getMaskedImage() if display: if displayExposure: ds9.mtv(mi, title="Kernel candidates", frame=lsstDebug.frame) # # Look for flags in each Source # isGoodSource = CheckSource(sourceCat, self.config.fluxLim, self.config.fluxMax, self.config.badFlags) # # Go through and find all the acceptable candidates in the catalogue # starCat = SourceCatalog(sourceCat.schema) if display and displayExposure: symbs = [] ctypes = [] doColorCut = True refSchema = matches[0][0].schema rRefFluxField = measAlg.getRefFluxField(refSchema, "r") gRefFluxField = measAlg.getRefFluxField(refSchema, "g") for ref, source, d in matches: if not isGoodSource(source): if display and displayExposure: symbs.append("+") ctypes.append(ds9.RED) else: isStar = not ref.get("resolved") isVar = not ref.get("photometric") gMag = None rMag = None if doColorCut: try: gMag = -2.5 * np.log10(ref.get(gRefFluxField)) rMag = -2.5 * np.log10(ref.get(rRefFluxField)) except KeyError: self.log.warn("Cannot cut on color info; fields 'g' and 'r' do not exist") doColorCut = False isRightColor = True else: isRightColor = (gMag-rMag) >= self.config.grMin and (gMag-rMag) <= self.config.grMax isRightType = (self.config.selectStar and isStar) or (self.config.selectGalaxy and not isStar) isRightVar = (self.config.includeVariable) or (self.config.includeVariable is isVar) if isRightType and isRightVar and isRightColor: starCat.append(source) if display and displayExposure: symbs.append("+") ctypes.append(ds9.GREEN) elif display and displayExposure: symbs.append("o") ctypes.append(ds9.BLUE) if display and displayExposure: with ds9.Buffering(): for (ref, source, d), symb, ctype in zip(matches, symbs, ctypes): if display and displayExposure: ds9.dot(symb, source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, ctype=ctype, frame=lsstDebug.frame) if display: lsstDebug.frame += 1 if pauseAtEnd: input("Continue? y[es] p[db] ") return Struct( starCat=starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches astrometric matches; ignored by this star selector @return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug display = lsstDebug.Info(__name__).display isGoodSource = CheckSource(sourceCat.getTable(), self.config.badFlags, self.config.fluxLim, self.config.fluxMax) detector = exposure.getDetector() mi = exposure.getMaskedImage() # # Create an Image of Ixx v. Iyy, i.e. a 2-D histogram # # Use stats on our Ixx/yy values to determine the xMax/yMax range for clump image iqqList = [] for s in sourceCat: ixx, iyy = s.getIxx(), s.getIyy() # ignore NaN and unrealistically large values if (ixx == ixx and ixx < self.config.histMomentMax and iyy == iyy and iyy < self.config.histMomentMax and isGoodSource(s)): iqqList.append(s.getIxx()) iqqList.append(s.getIyy()) stat = afwMath.makeStatistics(iqqList, afwMath.MEANCLIP | afwMath.STDEVCLIP | afwMath.MAX) iqqMean = stat.getValue(afwMath.MEANCLIP) iqqStd = stat.getValue(afwMath.STDEVCLIP) iqqMax = stat.getValue(afwMath.MAX) iqqLimit = max(iqqMean + self.config.histMomentClip*iqqStd, self.config.histMomentMaxMultiplier*iqqMean) # if the max value is smaller than our range, use max as the limit, but don't go below N*mean if iqqLimit > iqqMax: iqqLimit = max(self.config.histMomentMinMultiplier*iqqMean, iqqMax) psfHist = _PsfShapeHistogram(detector=detector, xSize=self.config.histSize, ySize=self.config.histSize, ixxMax=iqqLimit, iyyMax=iqqLimit) if display: frame = 0 ds9.mtv(mi, frame=frame, title="PSF candidates") with ds9.Buffering(): for source in sourceCat: if isGoodSource(source): if psfHist.insert(source): # n.b. this call has the side effect of inserting ctype = ds9.GREEN # good else: ctype = ds9.MAGENTA # rejected else: ctype = ds9.RED # bad if display: ds9.dot("o", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) clumps = psfHist.getClumps(display=display) # # Go through and find all the PSF-like objects # # We'll split the image into a number of cells, each of which contributes only # one PSF candidate star # starCat = SourceCatalog(sourceCat.table) pixToTanXYTransform = None if detector is not None: tanSys = detector.makeCameraSys(TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap().get(tanSys) # psf candidate shapes must lie within this many RMS of the average shape # N.b. if Ixx == Iyy, Ixy = 0 the criterion is # dx^2 + dy^2 < self.config.clumpNSigma*(Ixx + Iyy) == 2*self.config.clumpNSigma*Ixx for source in sourceCat: if not isGoodSource(source): continue Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if pixToTanXYTransform: p = afwGeom.Point2D(source.getX(), source.getY()) linTransform = pixToTanXYTransform.linearizeForwardTransform(p).getLinear() m = Quadrupole(Ixx, Iyy, Ixy) m.transform(linTransform) Ixx, Iyy, Ixy = m.getIxx(), m.getIyy(), m.getIxy() x, y = psfHist.momentsToPixel(Ixx, Iyy) for clump in clumps: dx, dy = (x - clump.x), (y - clump.y) if math.sqrt(clump.a*dx*dx + 2*clump.b*dx*dy + clump.c*dy*dy) < 2*self.config.clumpNSigma: # A test for > would be confused by NaN if not isGoodSource(source): continue try: psfCandidate = algorithmsLib.makePsfCandidate(source, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type # (and hence psfCandidate's exact type) if psfCandidate.getWidth() == 0: psfCandidate.setBorderWidth(self.config.borderWidth) psfCandidate.setWidth(self.config.kernelSize + 2*self.config.borderWidth) psfCandidate.setHeight(self.config.kernelSize + 2*self.config.borderWidth) im = psfCandidate.getMaskedImage().getImage() if not numpy.isfinite(afwMath.makeStatistics(im, afwMath.MAX).getValue()): continue starCat.append(source) if display: ds9.dot("o", source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, frame=frame, ctype=ds9.CYAN) except Exception as err: self.log.error("Failed on source %s: %s" % (source.getId(), err)) break return Struct( starCat = starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """Select sources for Kernel candidates @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches a match vector as produced by meas_astrom; required (defaults to None to match the StarSelector API and improve error handling) @return an lsst.pipe.base.Struct containing: - starCat a list of sources to be used as kernel candidates """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info(__name__).displayExposure pauseAtEnd = lsstDebug.Info(__name__).pauseAtEnd if matches is None: raise RuntimeError("DiaCatalogSourceSelector requires matches") mi = exposure.getMaskedImage() if display: if displayExposure: ds9.mtv(mi, title="Kernel candidates", frame=lsstDebug.frame) # # Look for flags in each Source # isGoodSource = CheckSource(sourceCat, self.config.fluxLim, self.config.fluxMax, self.config.badFlags) # # Go through and find all the acceptable candidates in the catalogue # starCat = SourceCatalog(sourceCat.schema) doColorCut = True with ds9.Buffering(): refSchema = matches[0][0].schema print "-----------------" print refSchema print "-----------------" rRefFluxField = measAlg.getRefFluxField(refSchema, "r") gRefFluxField = measAlg.getRefFluxField(refSchema, "g") for ref, source, d in matches: if not isGoodSource(source): symb, ctype = "+", ds9.RED else: isStar = not ref.get("resolved") isVar = not ref.get("photometric") gMag = None rMag = None if doColorCut: try: gMag = -2.5 * np.log10(ref.get(gRefFluxField)) rMag = -2.5 * np.log10(ref.get(rRefFluxField)) except KeyError: self.log.warn("Cannot cut on color info; fields 'g' and 'r' do not exist") doColorCut = False isRightColor = True else: isRightColor = (gMag-rMag) >= self.config.grMin and (gMag-rMag) <= self.config.grMax isRightType = (self.config.selectStar and isStar) or (self.config.selectGalaxy and not isStar) isRightVar = (self.config.includeVariable) or (self.config.includeVariable is isVar) if isRightType and isRightVar and isRightColor: starCat.append(source) symb, ctype = "+", ds9.GREEN else: symb, ctype = "o", ds9.BLUE if display and displayExposure: ds9.dot(symb, source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, ctype=ctype, frame=lsstDebug.frame) if display: lsstDebug.frame += 1 if pauseAtEnd: raw_input("Continue? y[es] p[db] ") return Struct( starCat = starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Select stars from source catalog @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches astrometric matches; ignored by this star selector @return a Struct containing: - starCat a subset of sourceCat containing the selected stars """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = display and \ lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells plotFwhmHistogram = display and plt and \ lsstDebug.Info(__name__).plotFwhmHistogram # Plot histogram of FWHM plotFlags = display and plt and \ lsstDebug.Info(__name__).plotFlags # Plot the sources coloured by their flags plotRejection = display and plt and \ lsstDebug.Info(__name__).plotRejection # Plot why sources are rejected #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # fluxName = self.config.fluxName fluxErrName = self.config.fluxErrName minFwhm = self.config.minFwhm maxFwhm = self.config.maxFwhm maxFwhmVariability = self.config.maxFwhmVariability maxbad = self.config.maxbad maxbadflag = self.config.maxbadflag maxellip = self.config.maxellip minsn = self.config.minsn maxelong = (maxellip + 1.0) / (1.0 - maxellip) if maxellip < 1.0 else 100 # Unpack the catalogue shape = sourceCat.getShapeDefinition() ixx = sourceCat.get("%s.xx" % shape) iyy = sourceCat.get("%s.yy" % shape) fwhm = 2 * np.sqrt(2 * np.log(2)) * np.sqrt(0.5 * (ixx + iyy)) elong = 0.5 * (ixx - iyy) / (ixx + iyy) flux = sourceCat.get(fluxName) fluxErr = sourceCat.get(fluxErrName) sn = flux / np.where(fluxErr > 0, fluxErr, 1) sn[fluxErr <= 0] = -psfexLib.BIG flags = 0x0 for i, f in enumerate(self.config.badFlags): flags = np.bitwise_or(flags, np.where(sourceCat.get(f), 1 << i, 0)) # # Estimate the acceptable range of source widths # good = np.logical_and(sn > minsn, np.logical_not(flags)) good = np.logical_and(good, elong < maxelong) good = np.logical_and(good, fwhm >= minFwhm) good = np.logical_and(good, fwhm < maxFwhm) fwhmMode, fwhmMin, fwhmMax = compute_fwhmrange( fwhm[good], maxFwhmVariability, minFwhm, maxFwhm, plot=dict(fwhmHistogram=plotFwhmHistogram)) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # # Here's select_candidates # #---- Apply some selection over flags, fluxes... bad = (flags != 0) # set.setBadFlags(int(sum(bad))) if plotRejection: selectionVectors = [] selectionVectors.append((bad, "flags %d" % sum(bad))) dbad = sn < minsn # set.setBadSN(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "S/N %d" % sum(dbad))) dbad = fwhm < fwhmMin # set.setBadFrmin(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "fwhmMin %d" % sum(dbad))) dbad = fwhm > fwhmMax # set.setBadFrmax(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "fwhmMax %d" % sum(dbad))) dbad = elong > maxelong # set.setBadElong(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "elong %d" % sum(dbad))) #-- ... and check the integrity of the sample if maxbadflag: nbad = np.array([(v <= -psfexLib.BIG).sum() for v in vignet]) dbad = nbad > maxbad # set.setBadPix(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "badpix %d" % sum(dbad))) good = np.logical_not(bad) # # We know enough to plot, if so requested # frame = 0 if displayExposure: mi = exposure.getMaskedImage() ds9.mtv(mi, frame=frame, title="PSF candidates") with ds9.Buffering(): for i, source in enumerate(sourceCat): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) if plotFlags or plotRejection: imag = -2.5 * np.log10(flux) plt.clf() alpha = 0.5 if plotFlags: isSet = np.where(flags == 0x0)[0] plt.plot(imag[isSet], fwhm[isSet], 'o', alpha=alpha, label="good") for i, f in enumerate(self.config.badFlags): mask = 1 << i isSet = np.where(np.bitwise_and(flags, mask))[0] if isSet.any(): if np.isfinite(imag[isSet] + fwhm[isSet]).any(): label = re.sub( r"\_flag", "", re.sub( r"^base\_", "", re.sub(r"^.*base\_PixelFlags\_flag\_", "", f))) plt.plot(imag[isSet], fwhm[isSet], 'o', alpha=alpha, label=label) else: for bad, label in selectionVectors: plt.plot(imag[bad], fwhm[bad], 'o', alpha=alpha, label=label) plt.plot(imag[good], fwhm[good], 'o', color="black", label="selected") [plt.axhline(_, color='red') for _ in [fwhmMin, fwhmMax]] plt.xlim(np.median(imag[good]) + 5 * np.array([-1, 1])) plt.ylim(fwhm[np.where(np.isfinite(fwhm + imag))].min(), 2 * fwhmMax) plt.legend(loc=2) plt.xlabel("Instrumental %s Magnitude" % fluxName.split(".")[-1].title()) plt.ylabel("fwhm") title = "PSFEX Star Selection" plt.title("%s %d selected" % (title, sum(good))) if displayExposure: global eventHandler eventHandler = EventHandler(plt.axes(), imag, fwhm, sourceCat.getX(), sourceCat.getY(), frames=[frame]) if plotFlags or plotRejection: while True: try: reply = input( "continue? [y[es] h(elp) p(db) q(uit)] ").strip() except EOFError: reply = "y" if not reply: reply = "y" if reply[0] == "h": print("""\ At this prompt, you can continue with almost any key; 'p' enters pdb, 'q' returns to the shell, and 'h' prints this text """, end=' ') if displayExposure: print(""" If you put the cursor on a point in the matplotlib scatter plot and hit 'p' you'll see it in ds9.""" ) elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break starCat = SourceCatalog(sourceCat.schema) for source, isGood in zip(sourceCat, good): if isGood: starCat.append(source) return Struct(starCat=starCat, )
def selectStars(self, exposure, sourceCat, matches=None): """!Select stars from source catalog @param[in] exposure the exposure containing the sources @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) @param[in] matches astrometric matches; ignored by this star selector @return a Struct containing: - starCat a subset of sourceCat containing the selected stars """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = display and \ lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells plotFwhmHistogram = display and plt and \ lsstDebug.Info(__name__).plotFwhmHistogram # Plot histogram of FWHM plotFlags = display and plt and \ lsstDebug.Info(__name__).plotFlags # Plot the sources coloured by their flags plotRejection = display and plt and \ lsstDebug.Info(__name__).plotRejection # Plot why sources are rejected #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # fluxName = self.config.fluxName fluxErrName = self.config.fluxErrName minFwhm = self.config.minFwhm maxFwhm = self.config.maxFwhm maxFwhmVariability = self.config.maxFwhmVariability maxbad = self.config.maxbad maxbadflag = self.config.maxbadflag maxellip = self.config.maxellip minsn = self.config.minsn maxelong = (maxellip + 1.0)/(1.0 - maxellip) if maxellip < 1.0 else 100 # Unpack the catalogue shape = sourceCat.getShapeDefinition() ixx = sourceCat.get("%s.xx" % shape) iyy = sourceCat.get("%s.yy" % shape) fwhm = 2*np.sqrt(2*np.log(2))*np.sqrt(0.5*(ixx + iyy)) elong = 0.5*(ixx - iyy)/(ixx + iyy) flux = sourceCat.get(fluxName) fluxErr = sourceCat.get(fluxErrName) sn = flux/np.where(fluxErr > 0, fluxErr, 1) sn[fluxErr <= 0] = -psfexLib.cvar.BIG flags = 0x0 for i, f in enumerate(self.config.badFlags): flags = np.bitwise_or(flags, np.where(sourceCat.get(f), 1 << i, 0)) # # Estimate the acceptable range of source widths # good = np.logical_and(sn > minsn, np.logical_not(flags)) good = np.logical_and(good, elong < maxelong) good = np.logical_and(good, fwhm >= minFwhm) good = np.logical_and(good, fwhm < maxFwhm) fwhmMode, fwhmMin, fwhmMax = compute_fwhmrange(fwhm[good], maxFwhmVariability, minFwhm, maxFwhm, plot=dict(fwhmHistogram=plotFwhmHistogram)) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # # Here's select_candidates # #---- Apply some selection over flags, fluxes... bad = (flags != 0) # set.setBadFlags(int(sum(bad))) if plotRejection: selectionVectors = [] selectionVectors.append((bad, "flags %d" % sum(bad))) dbad = sn < minsn # set.setBadSN(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "S/N %d" % sum(dbad))) dbad = fwhm < fwhmMin # set.setBadFrmin(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "fwhmMin %d" % sum(dbad))) dbad = fwhm > fwhmMax # set.setBadFrmax(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "fwhmMax %d" % sum(dbad))) dbad = elong > maxelong # set.setBadElong(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "elong %d" % sum(dbad))) #-- ... and check the integrity of the sample if maxbadflag: nbad = np.array([(v <= -psfexLib.cvar.BIG).sum() for v in vignet]) dbad = nbad > maxbad # set.setBadPix(int(sum(dbad))) bad = np.logical_or(bad, dbad) if plotRejection: selectionVectors.append((dbad, "badpix %d" % sum(dbad))) good = np.logical_not(bad) # # We know enough to plot, if so requested # frame = 0 if displayExposure: mi = exposure.getMaskedImage() ds9.mtv(mi, frame=frame, title="PSF candidates") with ds9.Buffering(): for i, source in enumerate(sourceCat): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) if plotFlags or plotRejection: imag = -2.5*np.log10(flux) plt.clf() alpha = 0.5 if plotFlags: isSet = np.where(flags == 0x0)[0] plt.plot(imag[isSet], fwhm[isSet], 'o', alpha=alpha, label="good") for i, f in enumerate(self.config.badFlags): mask = 1 << i isSet = np.where(np.bitwise_and(flags, mask))[0] if isSet.any(): if np.isfinite(imag[isSet] + fwhm[isSet]).any(): label = re.sub(r"\_flag", "", re.sub(r"^base\_", "", re.sub(r"^.*base\_PixelFlags\_flag\_", "", f))) plt.plot(imag[isSet], fwhm[isSet], 'o', alpha=alpha, label=label) else: for bad, label in selectionVectors: plt.plot(imag[bad], fwhm[bad], 'o', alpha=alpha, label=label) plt.plot(imag[good], fwhm[good], 'o', color="black", label="selected") [plt.axhline(_, color='red') for _ in [fwhmMin, fwhmMax]] plt.xlim(np.median(imag[good]) + 5*np.array([-1, 1])) plt.ylim(fwhm[np.where(np.isfinite(fwhm + imag))].min(), 2*fwhmMax) plt.legend(loc=2) plt.xlabel("Instrumental %s Magnitude" % fluxName.split(".")[-1].title()) plt.ylabel("fwhm") title = "PSFEX Star Selection" plt.title("%s %d selected" % (title, sum(good))) if displayExposure: global eventHandler eventHandler = EventHandler(plt.axes(), imag, fwhm, sourceCat.getX(), sourceCat.getY(), frames=[frame]) if plotFlags or plotRejection: while True: try: reply = input("continue? [y[es] h(elp) p(db) q(uit)] ").strip() except EOFError: reply = "y" if not reply: reply = "y" if reply[0] == "h": print("""\ At this prompt, you can continue with almost any key; 'p' enters pdb, 'q' returns to the shell, and 'h' prints this text """, end=' ') if displayExposure: print(""" If you put the cursor on a point in the matplotlib scatter plot and hit 'p' you'll see it in ds9.""") elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break starCat = SourceCatalog(sourceCat.schema) for source, isGood in zip(sourceCat, good): if isGood: starCat.append(source) return Struct( starCat=starCat, )