Beispiel #1
0
def showDiaSources(sources, exposure, isFlagged, isDipole, frame=None):
    """Display Dia Sources
    """
    #
    # Show us the ccandidates
    #
    # Too many mask planes in diffims
    for plane in ("BAD", "CR", "EDGE", "INTERPOlATED", "INTRP", "SAT",
                  "SATURATED"):
        ds9.setMaskPlaneVisibility(plane, False)

    mos = displayUtils.Mosaic()
    for i in range(len(sources)):
        source = sources[i]
        badFlag = isFlagged[i]
        dipoleFlag = isDipole[i]
        bbox = source.getFootprint().getBBox()
        stamp = exposure.Factory(exposure, bbox, True)
        im = displayUtils.Mosaic(gutter=1, background=0, mode="x")
        im.append(stamp.getMaskedImage())
        lab = "%.1f,%.1f:" % (source.getX(), source.getY())
        if badFlag:
            ctype = ds9.RED
            lab += "BAD"
        if dipoleFlag:
            ctype = ds9.YELLOW
            lab += "DIPOLE"
        if not badFlag and not dipoleFlag:
            ctype = ds9.GREEN
            lab += "OK"
        mos.append(im.makeMosaic(), lab, ctype)
    title = "Dia Sources"
    mosaicImage = mos.makeMosaic(frame=frame, title=title)
    return mosaicImage
Beispiel #2
0
    def testPca(self):
        """Test calculating PCA"""

        random.seed(0)
        width, height = 200, 100
        numBases = 3
        numInputs = 3

        bases = []
        for i in range(numBases):
            im = afwImage.ImageF(width, height)
            array = im.getArray()
            x, y = np.indices(array.shape)
            period = 5 * (i + 1)
            fx = np.sin(2 * math.pi / period * x + 2 * math.pi / numBases * i)
            fy = np.sin(2 * math.pi / period * y + 2 * math.pi / numBases * i)
            array[x, y] = fx + fy
            bases.append(im)

        if display:
            mos = displayUtils.Mosaic(background=-10)
            ds9.mtv(mos.makeMosaic(bases), title="Basis functions", frame=1)

        inputs = []
        for i in range(numInputs):
            im = afwImage.ImageF(afwGeom.Extent2I(width, height))
            im.set(0)
            for b in bases:
                im.scaledPlus(random.random(), b)

            inputs.append(im)
            self.ImageSet.addImage(im, 1.0)

        if display:
            mos = displayUtils.Mosaic(background=-10)
            ds9.mtv(mos.makeMosaic(inputs), title="Inputs", frame=2)

        self.ImageSet.analyze()

        eImages = []
        for img in self.ImageSet.getEigenImages():
            eImages.append(img)

        if display:
            mos = displayUtils.Mosaic(background=-10)
            ds9.mtv(mos.makeMosaic(eImages), title="Eigenimages", frame=3)

        self.assertEqual(len(eImages), numInputs)

        # Test for orthogonality
        for i1, i2 in itertools.combinations(range(len(eImages)), 2):
            inner = afwImage.innerProduct(eImages[i1], eImages[i2])
            norm1 = eImages[i1].getArray().sum()
            norm2 = eImages[i2].getArray().sum()
            inner /= norm1 * norm2
            self.assertAlmostEqual(inner, 0)
    def testCandidateList(self):
        self.assertFalse(self.cellSet.getCellList()[0].empty())
        self.assertTrue(self.cellSet.getCellList()[1].empty())
        self.assertFalse(self.cellSet.getCellList()[2].empty())
        self.assertTrue(self.cellSet.getCellList()[3].empty())

        stamps = []
        stampInfo = []
        for cell in self.cellSet.getCellList():
            for cand in cell:
                #
                # Swig doesn't know that we inherited from SpatialCellMaskedImageCandidate;  all
                # it knows is that we have a SpatialCellCandidate, and SpatialCellCandidates
                # don't know about getMaskedImage;  so cast the pointer to SpatialCellMaskedImageCandidate<float>
                # and all will be well
                #
                cand = afwMath.cast_SpatialCellMaskedImageCandidateF(cell[0])
                width, height = 29, 25
                cand.setWidth(width); cand.setHeight(height);

                im = cand.getMaskedImage()
                stamps.append(im)

                self.assertEqual(im.getWidth(), width)
                self.assertEqual(im.getHeight(), height)
        
        if False and display:
            mos = displayUtils.Mosaic()
            mos.makeMosaic(stamps, frame=2)
Beispiel #4
0
def plotPsfCandidates(cellSet, showBadCandidates=False, frame=1):
    import lsst.afw.display.utils as displayUtils

    stamps = []
    for cell in cellSet.getCellList():
        for cand in cell.begin(not showBadCandidates):  # maybe include bad candidates
            try:
                im = cand.getMaskedImage()

                chi2 = cand.getChi2()
                if chi2 < 1e100:
                    chi2 = "%.1f" % chi2
                else:
                    chi2 = float("nan")

                stamps.append((im, "%d%s" %
                               (maUtils.splitId(cand.getSource().getId(), True)["objId"], chi2),
                               cand.getStatus()))
            except Exception:
                continue

    mos = displayUtils.Mosaic()
    for im, label, status in stamps:
        im = type(im)(im, True)
        try:
            im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()
        except NotImplementedError:
            pass

        mos.append(im, label,
                   ds9.GREEN if status == afwMath.SpatialCellCandidate.GOOD else
                   ds9.YELLOW if status == afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)

    if mos.images:
        mos.makeMosaic(frame=frame, title="Psf Candidates")
Beispiel #5
0
def showPsf(psf, eigenValues=None, XY=None, normalize=True, display=None):
    """Display a PSF's eigen images

    If normalize is True, set the largest absolute value of each eigenimage to 1.0 (n.b. sum == 0.0 for i > 0)
    """

    if eigenValues:
        coeffs = eigenValues
    elif XY is not None:
        coeffs = psf.getLocalKernel(lsst.geom.PointD(XY[0], XY[1])).getKernelParameters()
    else:
        coeffs = None

    mos = displayUtils.Mosaic(gutter=2, background=-0.1)
    for i, k in enumerate(psf.getKernel().getKernelList()):
        im = afwImage.ImageD(k.getDimensions())
        k.computeImage(im, False)
        if normalize:
            im /= numpy.max(numpy.abs(im.getArray()))

        if coeffs:
            mos.append(im, "%g" % (coeffs[i]/coeffs[0]))
        else:
            mos.append(im)

    if not display:
        display = afwDisplay.Display()
    mos.makeMosaic(display=display, title="Kernel Basis Functions")

    return mos
Beispiel #6
0
    def testGetImage(self):
        """Test returning a realisation of the dgPsf"""

        xcen = self.psf.getKernel().getWidth()//2
        ycen = self.psf.getKernel().getHeight()//2

        stamps = []
        trueCenters = []
        for x, y in ([10, 10], [9.4999, 10.4999], [10.5001, 10.5001]):
            fx, fy = x - int(x), y - int(y)
            if fx >= 0.5:
                fx -= 1.0
            if fy >= 0.5:
                fy -= 1.0

            im = self.psf.computeImage(afwGeom.Point2D(x, y)).convertF()

            stamps.append(im.Factory(im, True))
            trueCenters.append([xcen + fx, ycen + fy])

        if display:
            mos = displayUtils.Mosaic()     # control mosaics
            ds9.mtv(mos.makeMosaic(stamps))

            for i in range(len(trueCenters)):
                bbox = mos.getBBox(i)

                ds9.dot("+",
                        bbox.getMinX() + xcen, bbox.getMinY() + ycen, ctype = ds9.RED, size = 1)
                ds9.dot("+",
                        bbox.getMinX() + trueCenters[i][0], bbox.getMinY() + trueCenters[i][1])

                ds9.dot("%.2f, %.2f" % (trueCenters[i][0], trueCenters[i][1]),
                        bbox.getMinX() + xcen, bbox.getMinY() + 2)
Beispiel #7
0
    def testKernelPsf(self):
        """Test creating a Psf from a Kernel"""

        x,y = 10.4999, 10.4999
        ksize = 15
        sigma1 = 1
        #
        # Make a PSF from that kernel
        #
        kPsf = measAlg.KernelPsf(afwMath.AnalyticKernel(ksize, ksize,
                                                        afwMath.GaussianFunction2D(sigma1, sigma1)))

        kIm = kPsf.computeImage(afwGeom.Point2D(x, y))
        #
        # And now via the dgPsf model
        #
        dgPsf = measAlg.DoubleGaussianPsf(ksize, ksize, sigma1)
        dgIm = dgPsf.computeImage(afwGeom.Point2D(x, y))
        #
        # Check that they're the same
        #
        diff = type(kIm)(kIm, True); diff -= dgIm
        stats = afwMath.makeStatistics(diff, afwMath.MAX | afwMath.MIN)
        self.assertAlmostEqual(stats.getValue(afwMath.MAX), 0.0, places=16)
        self.assertAlmostEqual(stats.getValue(afwMath.MIN), 0.0, places=16)

        if display:
            mos = displayUtils.Mosaic()
            mos.setBackground(-0.1)
            ds9.mtv(mos.makeMosaic([kIm, dgIm, diff], mode="x"), frame=1)
Beispiel #8
0
def showPsf(psf, eigenValues=None, XY=None, normalize=True, frame=None):
    """Display a PSF's eigen images

    If normalize is True, set the largest absolute value of each eigenimage to 1.0 (n.b. sum == 0.0 for i > 0)
    """

    if eigenValues:
        coeffs = eigenValues
    elif XY is not None:
        coeffs = psf.getLocalKernel(afwGeom.PointD(XY[0], XY[1])).getKernelParameters()
    else:
        coeffs = None

    mos = displayUtils.Mosaic()
    i = 0
    for k in afwMath.cast_LinearCombinationKernel(psf.getKernel()).getKernelList():
        im = afwImage.ImageD(k.getDimensions())
        k.computeImage(im, False)
        if normalize:
            im /= numpy.max(numpy.abs(im.getArray()))
            
        if coeffs:
            mos.append(im, "%g" % (coeffs[i]/coeffs[0]))
            i += 1
        else:
            mos.append(im)

    mos.makeMosaic(frame=frame, title="Eigen Images")

    return mos
Beispiel #9
0
def showKernelBasis(kernel, frame=None):
    """Display a Kernel's basis images
    """
    mos = displayUtils.Mosaic()

    for k in kernel.getKernelList():
        im = afwImage.ImageD(k.getDimensions())
        k.computeImage(im, False)
        mos.append(im)
    mos.makeMosaic(frame=frame, title="Kernel Basis Images")

    return mos
Beispiel #10
0
    def runBasicTest(self, kernel, convControl, refKernel=None, kernelDescr="", rtol=1.0e-05, atol=1e-08):
        """Assert that afwMath::convolve gives the same result as reference convolution for a given kernel.

        Inputs:
        - kernel: convolution kernel
        - convControl: convolution control parameters (afwMath.ConvolutionControl)
        - refKernel: kernel to use for refConvolve (if None then kernel is used)
        - kernelDescr: description of kernel
        - rtol: relative tolerance (see below)
        - atol: absolute tolerance (see below)

        rtol and atol are positive, typically very small numbers.
        The relative difference (rtol * abs(b)) and the absolute difference "atol" are added together
        to compare against the absolute difference between "a" and "b".
        """
        if refKernel is None:
            refKernel = kernel
        # strip garbage characters (whitespace and punctuation) to make a short description for saving files
        shortKernelDescr = self._removeGarbageChars(kernelDescr)

        doNormalize = convControl.getDoNormalize()
        doCopyEdge = convControl.getDoCopyEdge()
        maxInterpDist = convControl.getMaxInterpolationDistance()

        imMaskVar = self.maskedImage.getArrays()
        xy0 = self.maskedImage.getXY0()

        refCnvImMaskVarArr = refConvolve(imMaskVar, xy0, refKernel, doNormalize, doCopyEdge)
        refMaskedImage = afwImage.makeMaskedImageFromArrays(*refCnvImMaskVarArr)

        afwMath.convolve(self.cnvImage, self.maskedImage.getImage(), kernel, convControl)
        self.assertEqual(self.cnvImage.getXY0(), self.xy0)

        afwMath.convolve(self.cnvMaskedImage, self.maskedImage, kernel, convControl)

        if display and False:
            ds9.mtv(displayUtils.Mosaic().makeMosaic([
                self.maskedImage, refMaskedImage, self.cnvMaskedImage]), frame=0)
            if False:
                for (x, y) in ((0, 0), (1, 0), (0, 1), (50, 50)):
                    print("Mask(%d,%d) 0x%x 0x%x" % (x, y, refMaskedImage.getMask().get(x, y),
                                                     self.cnvMaskedImage.getMask().get(x, y)))

        self.assertImagesNearlyEqual(self.cnvImage, refMaskedImage.getImage(), atol=atol, rtol=rtol)
        self.assertMaskedImagesNearlyEqual(self.cnvMaskedImage, refMaskedImage, atol=atol, rtol=rtol)

        if not sameMaskPlaneDicts(self.cnvMaskedImage, self.maskedImage):
            self.cnvMaskedImage.writeFits("act%s" % (shortKernelDescr,))
            refMaskedImage.writeFits("des%s" % (shortKernelDescr,))
            self.fail("convolve(MaskedImage, kernel=%s, doNormalize=%s, "
                      "doCopyEdge=%s, maxInterpDist=%s) failed:\n%s" %
                      (kernelDescr, doNormalize, doCopyEdge, maxInterpDist,
                       "convolved mask dictionary does not match input"))
Beispiel #11
0
def main(rootDir, visit, ccd, n=4):

    # make a butler and specify your dataId
    butler = dafPersist.Butler(rootDir)
    dataId = {'visit': visit, 'ccd':ccd}

    # get the souces and the exposure from the butler
    sources = butler.get('src', dataId)
    exposure = butler.get("calexp", dataId)

    # make a list of the ones with the calib.psf.used flag set
    psfSources = [s for s in sources if s.get("calib.psf.used")]

    wx, wy = 25, 25         # the width to use for the bounding box

    subImages = []
    labels    = []
    for psfSrc in psfSources[0:n]:
        
        # make a bounding box for this source
        x, y = int(psfSrc.getX()), int(psfSrc.getY())
        bbox = afwGeom.Box2I(afwGeom.Point2I(x-wx/2, y-wy/2), afwGeom.Extent2I(wx, wy))

        # create a new image, and add it to our list
        subimg = afwImage.ImageF(exposure.getMaskedImage().getImage(), bbox)
        subImages.append(subimg)

        # use the ID for a label
        label = "ID="+str(psfSrc.getId())
        labels.append(label)


    # create a Mosaic object and set the specifications for your mosaic
    m = dispUtils.Mosaic()
    m.setGutter(2)          # width of the space between each subimage
    m.setBackground(0)
    m.setMode("square")

    # create the mosaic
    mosaic = m.makeMosaic(subImages)

    # display it with labels in ds9
    ds9.mtv(mosaic)                
    m.drawLabels(labels)

    # make a pyplot png (note: y-axis flipped for pyplot)
    img = mosaic.getArray()[::-1,:]
    vmin, vmax = zscale(img)
    pyplot.imshow(img, interpolation="none", cmap="gray", vmin=vmin, vmax=vmax)
    pyplot.gcf().savefig("mosaic.png")
Beispiel #12
0
def main(rootDir, visit, ccd, n=4):

    # butler を開き読み込みたいデータの dataId を指定する
    butler = dafPersist.Butler(rootDir)
    dataId = {'visit': visit, 'ccd': ccd}

    # butler から一次処理済データのカタログファイルをとデータを読み込む
    sources = butler.get('src', dataId)
    exposure = butler.get("calexp", dataId)

    # calib.psf.used で flag がついている天体リストを作る
    psfSources = [s for s in sources if s.get("calib.psf.used")]

    wx, wy = 25, 25  # bounding box の大きさを指定

    subImages = []
    labels = []
    for psfSrc in psfSources[0:n]:

        # この天体の bounding box を作る
        x, y = int(psfSrc.getX()), int(psfSrc.getY())
        bbox = afwGeom.Box2I(afwGeom.Point2I(x - wx / 2, y - wy / 2),
                             afwGeom.Extent2I(wx, wy))

        # 新しい画像を作り、リストに加える
        subimg = afwImage.ImageF(exposure.getMaskedImage().getImage(), bbox)
        subImages.append(subimg)

        # ラベルつけのために ID を使う
        label = "ID=" + str(psfSrc.getId())
        labels.append(label)

    # mosaic の天体を作り、仕様をセットする
    m = dispUtils.Mosaic()
    m.setGutter(2)  # 各 subimage の幅を指定する
    m.setBackground(0)
    m.setMode("square")

    # mosaic を作る
    mosaic = m.makeMosaic(subImages)

    # ds9 で表示し、その画像にラベルをつける
    ds9.mtv(mosaic)
    m.drawLabels(labels)

    # pyplot で png 画像を作る(pyplot 用に y-軸 は判定居させている)
    img = mosaic.getArray()[::-1, :]
    vmin, vmax = zscale(img)
    pyplot.imshow(img, interpolation="none", cmap="gray", vmin=vmin, vmax=vmax)
    pyplot.gcf().savefig("mosaic.png")
def BuildMosaic(filename, gutter=0, background=0):
    import lsst.afw.display.utils as Util
    import lsst.afw.image as afwImg

    m = Util.Mosaic()
    m.setGutter(gutter)
    m.setBackground(background)

    images = []
    for i in range(2, 18):
        m.append(afwImg.ImageF(filename, i), str(i))


#    mosaic = m.makeMosaic()

    return m
Beispiel #14
0
def showPsf(da, distort=False, stampSize=19, nx=7, ny=None, gutterLevel=0.05):
    mos = displayUtils.Mosaic(background=gutterLevel, gutter=1)

    if ny is None:
        ny = 2*nx

    dataId = da.dataId.copy()
    for ccd in (8, 9, 5, 4, 3,  6, 7, 2, 1, 0):
        dataId.update(ccd=ccd)
        calexp = da.getDataset("calexp", dataId)[0]
        if False:
            print calexp.getDetector().getId()
            
        mos.append(maUtils.showPsfMosaic(calexp, stampSize=stampSize,
                                         nx=nx, ny=ny, distort=distort).makeMosaic(mode=nx))

    return mos.makeMosaic(mode=5)       # Camera is 5x2
Beispiel #15
0
    def testCandidateList(self):
        if False and display:
            ds9.mtv(self.mi)

            for cell in self.cellSet.getCellList():
                x0, y0, x1, y1 = (cell.getBBox().getX0(),
                                  cell.getBBox().getY0(),
                                  cell.getBBox().getX1(),
                                  cell.getBBox().getY1())
                print((x0, y0, " ", x1, y1))
                x0 -= 0.5
                y0 -= 0.5
                x1 += 0.5
                y1 += 0.5

                ds9.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)],
                         ctype=ds9.RED)

        self.assertFalse(self.cellSet.getCellList()[0].empty())
        self.assertTrue(self.cellSet.getCellList()[1].empty())
        self.assertFalse(self.cellSet.getCellList()[2].empty())

        stamps = []
        for cell in self.cellSet.getCellList():
            for cand in cell:
                #
                # Swig doesn't know that we PsfCandidate;  all it knows is
                # that we have a SpatialCellCandidate, and
                # SpatialCellCandidates don't know about getMaskedImage;  so
                # cast the pointer to PsfCandidate<float> and all will be well
                #
                cand = algorithms.PsfCandidateF.cast(cell[0])
                width, height = 15, 17
                cand.setWidth(width)
                cand.setHeight(height)

                im = cand.getMaskedImage()
                stamps.append(im)

                self.assertEqual(im.getWidth(), width)
                self.assertEqual(im.getHeight(), height)

        if display:
            mos = displayUtils.Mosaic()
            ds9.mtv(mos.makeMosaic(stamps), frame=1)
Beispiel #16
0
    def testCandidateList(self):
        if False and display:
            ds9.mtv(self.mi)

            for cell in self.cellSet.getCellList():
                x0, y0, x1, y1 = (cell.getBBox().getX0(),
                                  cell.getBBox().getY0(),
                                  cell.getBBox().getX1(),
                                  cell.getBBox().getY1())
                print((x0, y0, " ", x1, y1))
                x0 -= 0.5
                y0 -= 0.5
                x1 += 0.5
                y1 += 0.5

                ds9.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)],
                         ctype=ds9.RED)

        self.assertFalse(self.cellSet.getCellList()[0].empty())
        self.assertTrue(self.cellSet.getCellList()[1].empty())
        self.assertFalse(self.cellSet.getCellList()[2].empty())

        stamps = []
        for cell in self.cellSet.getCellList():
            for cand in cell:
                cand = cell[0]
                width, height = 15, 17
                cand.setWidth(width)
                cand.setHeight(height)

                im = cand.getMaskedImage()
                stamps.append(im)

                self.assertEqual(im.getWidth(), width)
                self.assertEqual(im.getHeight(), height)

        if display:
            mos = displayUtils.Mosaic()
            ds9.mtv(mos.makeMosaic(stamps), frame=1)
Beispiel #17
0
    def testKernelPsf(self):
        """Test creating a Psf from a Kernel."""

        x, y = 10.4999, 10.4999
        ksize = 15
        sigma1 = 1
        #
        # Make a PSF from that kernel
        #
        kPsf = measAlg.KernelPsf(
            afwMath.AnalyticKernel(ksize, ksize,
                                   afwMath.GaussianFunction2D(sigma1, sigma1)))

        kIm = kPsf.computeImage(afwGeom.Point2D(x, y))
        #
        # And now via the dgPsf model
        #
        dgPsf = measAlg.DoubleGaussianPsf(ksize, ksize, sigma1)
        dgIm = dgPsf.computeImage(afwGeom.Point2D(x, y))
        #
        # Check that they're the same
        #
        diff = type(kIm)(kIm, True)
        diff -= dgIm
        stats = afwMath.makeStatistics(diff, afwMath.MAX | afwMath.MIN)
        self.assertAlmostEqual(stats.getValue(afwMath.MAX), 0.0, places=16)
        self.assertAlmostEqual(stats.getValue(afwMath.MIN), 0.0, places=16)

        for pad in [-2, 4, 0]:
            resizedKPsf = kPsf.resized(ksize + pad, ksize + pad)
            self.assertEqual(resizedKPsf.computeBBox().getDimensions(),
                             afwGeom.Extent2I(ksize + pad, ksize + pad))
            self.assertEqual(resizedKPsf.getKernel().getKernelParameters(),
                             kPsf.getKernel().getKernelParameters())
            self._compareKernelImages(kPsf, resizedKPsf)
        if display:
            mos = displayUtils.Mosaic()
            mos.setBackground(-0.1)
            ds9.mtv(mos.makeMosaic([kIm, dgIm, diff], mode="x"), frame=1)
    def testCandidateList(self):
        self.assertFalse(self.cellSet.getCellList()[0].empty())
        self.assertTrue(self.cellSet.getCellList()[1].empty())
        self.assertFalse(self.cellSet.getCellList()[2].empty())
        self.assertTrue(self.cellSet.getCellList()[3].empty())

        stamps = []
        for cell in self.cellSet.getCellList():
            for cand in cell:
                cand = cell[0]
                width, height = 29, 25
                cand.setWidth(width)
                cand.setHeight(height)

                im = cand.getMaskedImage()
                stamps.append(im)

                self.assertEqual(im.getWidth(), width)
                self.assertEqual(im.getHeight(), height)

        if False and display:
            mos = displayUtils.Mosaic()
            mos.makeMosaic(stamps, frame=2)
Beispiel #19
0
    def testPcaNaN(self):
        """Test calculating PCA when the images can contain NaNs"""

        width, height = 20, 10

        values = (100, 200, 300)
        for i, val in enumerate(values):
            im = afwImage.ImageF(afwGeom.Extent2I(width, height))
            im.set(val)

            if i == 1:
                im.set(width // 2, height // 2, np.nan)

            self.ImageSet.addImage(im, 1.0)

        self.ImageSet.analyze()

        eImages = []
        for img in self.ImageSet.getEigenImages():
            eImages.append(img)

        if display:
            mos = displayUtils.Mosaic(background=-10)
            ds9.mtv(mos.makeMosaic(eImages), frame=1)
Beispiel #20
0
    def testGetPcaKernel(self):
        """Convert our cellSet to a LinearCombinationKernel"""

        nEigenComponents = 2
        spatialOrder = 1
        kernelSize = 21
        nStarPerCell = 2
        nStarPerCellSpatialFit = 2
        tolerance = 1e-5

        if display:
            ds9.mtv(self.mi, frame=0)
            #
            # Show the candidates we're using
            #
            for cell in self.cellSet.getCellList():
                i = 0
                for cand in cell:
                    i += 1
                    source = cand.getSource()

                    xc, yc = source.getXAstrom() - self.mi.getX0(
                    ), source.getYAstrom() - self.mi.getY0()
                    if i <= nStarPerCell:
                        ds9.dot("o", xc, yc, ctype=ds9.GREEN)
                    else:
                        ds9.dot("o", xc, yc, ctype=ds9.YELLOW)

        pair = algorithms.createKernelFromPsfCandidates(
            self.cellSet, self.exposure.getDimensions(),
            self.exposure.getXY0(), nEigenComponents, spatialOrder, kernelSize,
            nStarPerCell)

        kernel, eigenValues = pair[0], pair[1]
        del pair

        print("lambda", " ".join(["%g" % l for l in eigenValues]))

        pair = algorithms.fitSpatialKernelFromPsfCandidates(
            kernel, self.cellSet, nStarPerCellSpatialFit, tolerance)
        status, chi2 = pair[0], pair[1]
        del pair
        print("Spatial fit: %s chi^2 = %.2g" % (status, chi2))

        psf = roundTripPsf(5, algorithms.PcaPsf(kernel))  # Hurrah!

        self.assertIsNotNone(psf.getKernel())

        self.checkTablePersistence(psf)

        if display:
            # print psf.getKernel().toString()

            eImages = []
            for k in psf.getKernel().getKernelList():
                im = afwImage.ImageD(k.getDimensions())
                k.computeImage(im, False)
                eImages.append(im)

            mos = displayUtils.Mosaic()
            frame = 3
            ds9.mtv(mos.makeMosaic(eImages), frame=frame)
            ds9.dot("Eigen Images", 0, 0, frame=frame)
            #
            # Make a mosaic of PSF candidates
            #
            stamps = []
            stampInfo = []

            for cell in self.cellSet.getCellList():
                for cand in cell:
                    s = cand.getSource()

                    im = cand.getMaskedImage()

                    stamps.append(im)
                    stampInfo.append("[%d 0x%x]" %
                                     (s.getId(), s.getFlagForDetection()))

                    mos = displayUtils.Mosaic()
            frame = 1
            ds9.mtv(mos.makeMosaic(stamps), frame=frame, lowOrderBits=True)
            for i in range(len(stampInfo)):
                ds9.dot(stampInfo[i],
                        mos.getBBox(i).getX0(),
                        mos.getBBox(i).getY0(),
                        frame=frame,
                        ctype=ds9.RED)

            psfImages = []
            labels = []
            if False:
                nx, ny = 3, 4
                for iy in range(ny):
                    for ix in range(nx):
                        x = int((ix + 0.5) * self.mi.getWidth() / nx)
                        y = int((iy + 0.5) * self.mi.getHeight() / ny)

                        im = psf.getImage(x, y)
                        psfImages.append(im.Factory(im, True))
                        labels.append("PSF(%d,%d)" % (int(x), int(y)))

                        if True:
                            print((x, y, "PSF parameters:",
                                   psf.getKernel().getKernelParameters()))
            else:
                nx, ny = 2, 2
                for x, y in [(20, 20), (60, 20), (60, 210), (20, 210)]:

                    im = psf.computeImage(afwGeom.PointD(x, y))
                    psfImages.append(im.Factory(im, True))
                    labels.append("PSF(%d,%d)" % (int(x), int(y)))

                    if True:
                        print(x, y, "PSF parameters:",
                              psf.getKernel().getKernelParameters())

            frame = 2
            mos.makeMosaic(psfImages, frame=frame, mode=nx)
            mos.drawLabels(labels, frame=frame)

        if display:

            ds9.mtv(self.mi, frame=0)

            psfImages = []
            labels = []
            if False:
                nx, ny = 3, 4
                for iy in range(ny):
                    for ix in range(nx):
                        x = int((ix + 0.5) * self.mi.getWidth() / nx)
                        y = int((iy + 0.5) * self.mi.getHeight() / ny)

                        algorithms.subtractPsf(psf, self.mi, x, y)
            else:
                nx, ny = 2, 2
                for x, y in [(20, 20), (60, 20), (60, 210), (20, 210)]:

                    if False:  # Test subtraction with non-centered psfs
                        x += 0.5
                        y -= 0.5

                    #algorithms.subtractPsf(psf, self.mi, x, y)

            ds9.mtv(self.mi, frame=1)
Beispiel #21
0
def showPsfMosaic(exposure, psf=None, nx=7, ny=None, showCenter=True, showEllipticity=False,
                  showFwhm=False, stampSize=0, display=None, title=None):
    """Show a mosaic of Psf images.  exposure may be an Exposure (optionally with PSF),
    or a tuple (width, height)

    If stampSize is > 0, the psf images will be trimmed to stampSize*stampSize
    """

    scale = 1.0
    if showFwhm:
        showEllipticity = True
        scale = 2*math.log(2)         # convert sigma^2 to HWHM^2 for a Gaussian

    mos = displayUtils.Mosaic()

    try:                                # maybe it's a real Exposure
        width, height = exposure.getWidth(), exposure.getHeight()
        x0, y0 = exposure.getXY0()
        if not psf:
            psf = exposure.getPsf()
    except AttributeError:
        try:                            # OK, maybe a list [width, height]
            width, height = exposure[0], exposure[1]
            x0, y0 = 0, 0
        except TypeError:               # I guess not
            raise RuntimeError("Unable to extract width/height from object of type %s" % type(exposure))

    if not ny:
        ny = int(nx*float(height)/width + 0.5)
        if not ny:
            ny = 1

    centroidName = "SdssCentroid"
    shapeName = "base_SdssShape"

    schema = afwTable.SourceTable.makeMinimalSchema()
    schema.getAliasMap().set("slot_Centroid", centroidName)
    schema.getAliasMap().set("slot_Centroid_flag", centroidName+"_flag")

    control = measBase.SdssCentroidControl()
    centroider = measBase.SdssCentroidAlgorithm(control, centroidName, schema)

    sdssShape = measBase.SdssShapeControl()
    shaper = measBase.SdssShapeAlgorithm(sdssShape, shapeName, schema)
    table = afwTable.SourceTable.make(schema)

    table.defineCentroid(centroidName)
    table.defineShape(shapeName)

    bbox = None
    if stampSize > 0:
        w, h = psf.computeImage(lsst.geom.PointD(0, 0)).getDimensions()
        if stampSize <= w and stampSize <= h:
            bbox = lsst.geom.BoxI(lsst.geom.PointI((w - stampSize)//2, (h - stampSize)//2),
                                  lsst.geom.ExtentI(stampSize, stampSize))

    centers = []
    shapes = []
    for iy in range(ny):
        for ix in range(nx):
            x = int(ix*(width-1)/(nx-1)) + x0
            y = int(iy*(height-1)/(ny-1)) + y0

            im = psf.computeImage(lsst.geom.PointD(x, y)).convertF()
            imPeak = psf.computePeak(lsst.geom.PointD(x, y))
            im /= imPeak
            if bbox:
                im = im.Factory(im, bbox)
            lab = "PSF(%d,%d)" % (x, y) if False else ""
            mos.append(im, lab)

            exp = afwImage.makeExposure(afwImage.makeMaskedImage(im))
            exp.setPsf(psf)
            w, h = im.getWidth(), im.getHeight()
            centerX = im.getX0() + w//2
            centerY = im.getY0() + h//2
            src = table.makeRecord()
            spans = afwGeom.SpanSet(exp.getBBox())
            foot = afwDet.Footprint(spans)
            foot.addPeak(centerX, centerY, 1)
            src.setFootprint(foot)

            try:
                centroider.measure(src, exp)
                centers.append((src.getX() - im.getX0(), src.getY() - im.getY0()))

                shaper.measure(src, exp)
                shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))
            except Exception:
                pass

    if not display:
        display = afwDisplay.Display()
    mos.makeMosaic(display=display, title=title if title else "Model Psf", mode=nx)

    if centers and display:
        with display.Buffering():
            for i, (cen, shape) in enumerate(zip(centers, shapes)):
                bbox = mos.getBBox(i)
                xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY()
                if showCenter:
                    display.dot("+", xc, yc, ctype=afwDisplay.BLUE)

                if showEllipticity:
                    ixx, ixy, iyy = shape
                    ixx *= scale
                    ixy *= scale
                    iyy *= scale
                    display.dot("@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, ctype=afwDisplay.RED)

    return mos
def showPsf(psf, set, ext=None, wcsData=None, trim=0, nspot=5,
            diagnostics=False, outDir="", frame=None, title=None):
    """Show a PSF on ds9"""

    if ext is not None:
        psf = psf[ext]

    if wcsData:
        if ext is not None:
            wcsData = wcsData[ext]
        wcs, naxis1, naxis2 = wcsData
    else:
        wcs, naxis1, naxis2 = None, None, None

    naxis = [naxis1, naxis2]
    for i in range(2):
        if naxis[i] is None:
            # cmin, cmax are the range of input star positions
            cmin, cmax = [set.getContextOffset(i) + d*set.getContextScale(i) for d in (-0.5, 0.5)]
            naxis[i] = cmax + cmin          # a decent guess

    import lsst.afw.display.utils as ds9Utils
    if naxis[0] > naxis[1]:
        nx, ny = int(nspot*naxis[0]/float(naxis[1]) + 0.5), nspot
    else:
        nx, ny = nspot, int(nspot*naxis[1]/float(naxis[0]) + 0.5)

    mos = ds9Utils.Mosaic(gutter=2, background=0.02)

    xpos, ypos = np.linspace(0, naxis[0], nx), np.linspace(0, naxis[1], ny)
    for y in ypos:
        for x in xpos:
            psf.build(x, y)

            im = afwImage.ImageF(*psf.getLoc().shape)
            im.getArray()[:] = psf.getLoc()
            im /= float(im.getArray().max())
            if trim:
                if trim > im.getHeight()//2:
                    trim = im.getHeight()//2

                im = im[trim:-trim, trim:-trim]

            mos.append(im)

    mosaic = mos.makeMosaic(mode=nx)
    if frame is not None:
        ds9.mtv(mosaic, frame=frame, title=title)
    #
    # Figure out the WCS for the mosaic
    #
    pos = []
    if False:
        for x, y, i in zip((xpos[0], xpos[-1]), (ypos[0], ypos[-1]), (0, mos.nImage - 1)):
            bbox = mos.getBBox(i)
            mosx = bbox.getMinX() + 0.5*(bbox.getWidth() - 1)
            mosy = bbox.getMinY() + 0.5*(bbox.getHeight() - 1)
            pos.append([afwGeom.PointD(mosx, mosy), wcs.pixelToSky(afwGeom.PointD(x, y))])
    else:
        pos.append([afwGeom.PointD(0, 0), wcs.pixelToSky(afwGeom.PointD(0, 0))])
        pos.append([afwGeom.PointD(*mosaic.getDimensions()), wcs.pixelToSky(afwGeom.PointD(naxis1, naxis2))])

    CD = []
    for i in range(2):
        delta = pos[1][1][i].asDegrees() - pos[0][1][i].asDegrees()
        CD.append(delta/(pos[1][0][i] - pos[0][0][i]))
    CD = np.array(CD)
    CD.shape = (2, 2)
    mosWcs = afwGeom.makeSkyWcs(crval=pos[0][0], crpix=pos[0][1], cdMatrix=CD)

    if ext is not None:
        title = "%s-%d" % (title, ext)

    if frame is not None:
        ds9.mtv(mosaic, frame=frame, title=title, wcs=mosWcs)

    if diagnostics:
        outFile = "%s-mod.fits" % title
        if outDir:
            outFile = os.path.join(outDir, outFile)
        mosaic.writeFits(outFile, mosWcs.getFitsMetadata())

    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

    mos = ds9Utils.Mosaic(gutter=4, background=0.002)
    for i in range(set.getNsample()):
        s = set.getSample(i)
        if ext is not None and s.getExtindex() != ext:
            continue

        smos = ds9Utils.Mosaic(gutter=2, background=-0.003)
        for func in [s.getVig, s.getVigResi]:
            arr = func()
            if func == s.getVig:
                norm = float(arr.max()) if True else s.getNorm()

            arr /= norm
            im = afwImage.ImageF(*arr.shape)
            im.getArray()[:] = arr
            smos.append(im)

        mos.append(smos.makeMosaic(mode="x"))

    mosaic = mos.makeMosaic(title=title)

    if frame is not None:
        ds9.mtv(mosaic, title=title, frame=frame+1)

    if diagnostics:
        outFile = "%s-psfstars.fits" % title
        if outDir:
            outFile = os.path.join(outDir, outFile)

        mosaic.writeFits(outFile)
Beispiel #23
0
def showPsfCandidates(exposure, psfCellSet, psf=None, display=None, normalize=True, showBadCandidates=True,
                      fitBasisComponents=False, variance=None, chi=None):
    """Display the PSF candidates.

    If psf is provided include PSF model and residuals;  if normalize is true normalize the PSFs
    (and residuals)

    If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi

    If fitBasisComponents is true, also find the best linear combination of the PSF's components
    (if they exist)
    """
    if not display:
        display = afwDisplay.Display()

    if chi is None:
        if variance is not None:        # old name for chi
            chi = variance
    #
    # Show us the ccandidates
    #
    mos = displayUtils.Mosaic()
    #
    candidateCenters = []
    candidateCentersBad = []
    candidateIndex = 0

    for cell in psfCellSet.getCellList():
        for cand in cell.begin(False):  # include bad candidates
            rchi2 = cand.getChi2()
            if rchi2 > 1e100:
                rchi2 = numpy.nan

            if not showBadCandidates and cand.isBad():
                continue

            if psf:
                im_resid = displayUtils.Mosaic(gutter=0, background=-5, mode="x")

                try:
                    im = cand.getMaskedImage()  # copy of this object's image
                    xc, yc = cand.getXCenter(), cand.getYCenter()

                    margin = 0 if True else 5
                    w, h = im.getDimensions()
                    bbox = lsst.geom.BoxI(lsst.geom.PointI(margin, margin), im.getDimensions())

                    if margin > 0:
                        bim = im.Factory(w + 2*margin, h + 2*margin)

                        stdev = numpy.sqrt(afwMath.makeStatistics(im.getVariance(), afwMath.MEAN).getValue())
                        afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                        bim.getVariance().set(stdev**2)

                        bim.assign(im, bbox)
                        im = bim
                        xc += margin
                        yc += margin

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())
                except Exception:
                    continue

                if not variance:
                    im_resid.append(im.Factory(im, True))

                if True:                # tweak up centroids
                    mi = im
                    psfIm = mi.getImage()
                    config = measBase.SingleFrameMeasurementTask.ConfigClass()
                    config.slots.centroid = "base_SdssCentroid"

                    schema = afwTable.SourceTable.makeMinimalSchema()
                    measureSources = measBase.SingleFrameMeasurementTask(schema, config=config)
                    catalog = afwTable.SourceCatalog(schema)

                    extra = 10          # enough margin to run the sdss centroider
                    miBig = mi.Factory(im.getWidth() + 2*extra, im.getHeight() + 2*extra)
                    miBig[extra:-extra, extra:-extra, afwImage.LOCAL] = mi
                    miBig.setXY0(mi.getX0() - extra, mi.getY0() - extra)
                    mi = miBig
                    del miBig

                    exp = afwImage.makeExposure(mi)
                    exp.setPsf(psf)

                    footprintSet = afwDet.FootprintSet(mi,
                                                       afwDet.Threshold(0.5*numpy.max(psfIm.getArray())),
                                                       "DETECTED")
                    footprintSet.makeSources(catalog)

                    if len(catalog) == 0:
                        raise RuntimeError("Failed to detect any objects")

                    measureSources.run(catalog, exp)
                    if len(catalog) == 1:
                        source = catalog[0]
                    else:               # more than one source; find the once closest to (xc, yc)
                        dmin = None  # an invalid value to catch logic errors
                        for i, s in enumerate(catalog):
                            d = numpy.hypot(xc - s.getX(), yc - s.getY())
                            if i == 0 or d < dmin:
                                source, dmin = s, d
                    xc, yc = source.getCentroid()

                # residuals using spatial model
                try:
                    subtractPsf(psf, im, xc, yc)
                except Exception:
                    continue

                resid = im
                if variance:
                    resid = resid.getImage()
                    var = im.getVariance()
                    var = var.Factory(var, True)
                    numpy.sqrt(var.getArray(), var.getArray())  # inplace sqrt
                    resid /= var

                im_resid.append(resid)

                # Fit the PSF components directly to the data (i.e. ignoring the spatial model)
                if fitBasisComponents:
                    im = cand.getMaskedImage()

                    im = im.Factory(im, True)
                    im.setXY0(cand.getMaskedImage().getXY0())

                    try:
                        noSpatialKernel = psf.getKernel()
                    except Exception:
                        noSpatialKernel = None

                    if noSpatialKernel:
                        candCenter = lsst.geom.PointD(cand.getXCenter(), cand.getYCenter())
                        fit = fitKernelParamsToImage(noSpatialKernel, im, candCenter)
                        params = fit[0]
                        kernels = afwMath.KernelList(fit[1])
                        outputKernel = afwMath.LinearCombinationKernel(kernels, params)

                        outImage = afwImage.ImageD(outputKernel.getDimensions())
                        outputKernel.computeImage(outImage, False)

                        im -= outImage.convertF()
                        resid = im

                        if margin > 0:
                            bim = im.Factory(w + 2*margin, h + 2*margin)
                            afwMath.randomGaussianImage(bim.getImage(), afwMath.Random())
                            bim *= stdev

                            bim.assign(resid, bbox)
                            resid = bim

                        if variance:
                            resid = resid.getImage()
                            resid /= var

                        im_resid.append(resid)

                im = im_resid.makeMosaic()
            else:
                im = cand.getMaskedImage()

            if normalize:
                im /= afwMath.makeStatistics(im, afwMath.MAX).getValue()

            objId = splitId(cand.getSource().getId(), True)["objId"]
            if psf:
                lab = "%d chi^2 %.1f" % (objId, rchi2)
                ctype = afwDisplay.RED if cand.isBad() else afwDisplay.GREEN
            else:
                lab = "%d flux %8.3g" % (objId, cand.getSource().getPsfInstFlux())
                ctype = afwDisplay.GREEN

            mos.append(im, lab, ctype)

            if False and numpy.isnan(rchi2):
                display.mtv(cand.getMaskedImage().getImage(), title="showPsfCandidates: candidate")
                print("amp", cand.getAmplitude())

            im = cand.getMaskedImage()
            center = (candidateIndex, xc - im.getX0(), yc - im.getY0())
            candidateIndex += 1
            if cand.isBad():
                candidateCentersBad.append(center)
            else:
                candidateCenters.append(center)

    if variance:
        title = "chi(Psf fit)"
    else:
        title = "Stars & residuals"
    mosaicImage = mos.makeMosaic(display=display, title=title)

    with display.Buffering():
        for centers, color in ((candidateCenters, afwDisplay.GREEN), (candidateCentersBad, afwDisplay.RED)):
            for cen in centers:
                bbox = mos.getBBox(cen[0])
                display.dot("+", cen[1] + bbox.getMinX(), cen[2] + bbox.getMinY(), ctype=color)

    return mosaicImage
Beispiel #24
0
    spatialBg = results.backgroundModel
    kernelCellSet = results.kernelCellSet
except Exception as e:
    print('FAIL')
    sys.exit(1)

if False:
    print(spatialKernel.getSpatialFunctionList()[0].toString())
    print(spatialKernel.getKernelParameters())
    print(spatialKernel.getSpatialParameters())
    import pdb
    pdb.set_trace()

# Lets see what we got
if display:
    mos = displayUtils.Mosaic()

    # Inputs
    for cell in kernelCellSet.getCellList():
        for cand in cell.begin(False):  # False = include bad candidates
            rchi2 = cand.getChi2()

            # No kernels made
            if cand.getStatus() == afwMath.SpatialCellCandidate.UNKNOWN:
                continue

            try:
                im = cand.getKernelImage(ipDiffim.KernelCandidateF.RECENT)
            except Exception:
                continue
Beispiel #25
0
def makeDeblendFamilyMosaic(mi,
                            parent,
                            kids,
                            mapperInfo=None,
                            background=-10,
                            maskbit=False,
                            imBbox=None):
    """Create a mosaic of an object's children
    """

    aa = {}
    if maskbit:
        aa.update(mask=True)
    parent_im = footprintToImage(parent.getFootprint(), mi, **aa)
    bbox = afwGeom.BoxD(parent.getFootprint().getBBox())
    pext = (bbox.getMinX(), bbox.getMaxX(), bbox.getMinY(), bbox.getMaxY())

    pks = parent.getFootprint().getPeaks()
    pix = [pk.getIx() for pk in pks]
    piy = [pk.getIy() for pk in pks]
    pfx = [pk.getFx() for pk in pks]
    pfy = [pk.getFy() for pk in pks]

    N = 1 + len(kids)
    S = np.ceil(np.sqrt(N))
    C = S
    R = np.ceil(float(N) / C)

    Rx, Ry = [], []
    tts = []
    stys = []
    xys = []
    #
    # Find how large an image we need to display the parent and all the children
    #
    kidImages, kim = {}, None
    for kid in kids:
        kim = footprintToImage(kid.getFootprint(), mi, **aa)
        kidImages[kid] = kim

    if not kim:
        kim = parent_im.clone()

    if not imBbox:
        imBbox = parent_im.getBBox(afwImage.PARENT)
        for kid in kids:
            imBbox.include(kidImages[kid].getBBox(afwImage.PARENT))

    mos = displayUtils.Mosaic(background=background)

    bbox = afwGeom.Box2I(
        afwGeom.Point2I(kim.getX0() - imBbox.getMinX(),
                        kim.getY0() - imBbox.getMinY()), kim.getDimensions())

    kidImages[parent] = parent_im  # not strictly a kid

    for kid in [parent] + kids:
        kim = kidImages[kid]
        #
        # Put the child into the correct place in the parent image.  We have to do this for
        # the parent too if some of the children extended outside its BBox
        #
        bbox = afwGeom.Box2I(
            afwGeom.Point2I(kim.getX0() - imBbox.getMinX(),
                            kim.getY0() - imBbox.getMinY()),
            kim.getDimensions())

        _kim = parent_im.Factory(imBbox)
        if kid.getFootprint().getBBox().isEmpty():
            _kim[:] = 0
            pass
        else:
            _kim[bbox] = kim

        mos.append(
            _kim,
            '%d%s' % (mapperInfo.getId(kid) if mapperInfo else
                      (kid.getId() & 0xfff), "P" if kid == parent else "C"))
        del _kim

    return mos
Beispiel #26
0
def showKernelMosaic(bbox,
                     kernel,
                     nx=7,
                     ny=None,
                     frame=None,
                     title=None,
                     showCenter=True,
                     showEllipticity=True):
    """Show a mosaic of Kernel images.
    """
    mos = displayUtils.Mosaic()

    x0 = bbox.getBeginX()
    y0 = bbox.getBeginY()
    width = bbox.getWidth()
    height = bbox.getHeight()

    if not ny:
        ny = int(nx * float(height) / width + 0.5)
        if not ny:
            ny = 1

    schema = afwTable.SourceTable.makeMinimalSchema()
    centroidName = "base_SdssCentroid"
    shapeName = "base_SdssShape"
    control = measBase.SdssCentroidControl()
    schema.getAliasMap().set("slot_Centroid", centroidName)
    schema.getAliasMap().set("slot_Centroid_flag", centroidName + "_flag")
    centroider = measBase.SdssCentroidAlgorithm(control, centroidName, schema)
    sdssShape = measBase.SdssShapeControl()
    shaper = measBase.SdssShapeAlgorithm(sdssShape, shapeName, schema)
    table = afwTable.SourceTable.make(schema)
    table.defineCentroid(centroidName)
    table.defineShape(shapeName)

    centers = []
    shapes = []
    for iy in range(ny):
        for ix in range(nx):
            x = int(ix * (width - 1) / (nx - 1)) + x0
            y = int(iy * (height - 1) / (ny - 1)) + y0

            im = afwImage.ImageD(kernel.getDimensions())
            ksum = kernel.computeImage(im, False, x, y)
            lab = "Kernel(%d,%d)=%.2f" % (x, y, ksum) if False else ""
            mos.append(im, lab)

            # SdssCentroidAlgorithm.measure requires an exposure of floats
            exp = afwImage.makeExposure(afwImage.makeMaskedImage(
                im.convertF()))
            w, h = im.getWidth(), im.getHeight()
            centerX = im.getX0() + w // 2
            centerY = im.getY0() + h // 2
            src = table.makeRecord()
            foot = afwDet.Footprint(exp.getBBox())
            foot.addPeak(centerX, centerY, 1)
            src.setFootprint(foot)

            centroider.measure(src, exp)
            centers.append((src.getX(), src.getY()))

            shaper.measure(src, exp)
            shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))

    mos.makeMosaic(frame=frame,
                   title=title if title else "Model Kernel",
                   mode=nx)

    if centers and frame is not None:
        i = 0
        with ds9.Buffering():
            for cen, shape in zip(centers, shapes):
                bbox = mos.getBBox(i)
                i += 1
                xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY()
                if showCenter:
                    ds9.dot("+", xc, yc, ctype=ds9.BLUE, frame=frame)

                if showEllipticity:
                    ixx, ixy, iyy = shape
                    ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy),
                            xc,
                            yc,
                            frame=frame,
                            ctype=ds9.RED)

    return mos
Beispiel #27
0
def showPsfMosaic(exposure, psf=None, nx=7, ny=None,
                  showCenter=True, showEllipticity=False, showFwhm=False,
                  stampSize=0, frame=None, title=None):
    """Show a mosaic of Psf images.  exposure may be an Exposure (optionally with PSF), or a tuple (width, height)

    If stampSize is > 0, the psf images will be trimmed to stampSize*stampSize
    """

    scale = 1.0
    if showFwhm:
        showEllipticity = True
        scale = 2*math.log(2)         # convert sigma^2 to HWHM^2 for a Gaussian

    mos = displayUtils.Mosaic()

    try:                                # maybe it's a real Exposure
        width, height = exposure.getWidth(), exposure.getHeight()
        x0, y0 = exposure.getXY0()
        if not psf:
            psf = exposure.getPsf()
    except AttributeError:
        try:                            # OK, maybe a list [width, height]
            width, height = exposure[0], exposure[1]
            x0, y0 = 0, 0
        except TypeError:               # I guess not
            raise RuntimeError, ("Unable to extract width/height from object of type %s" % type(exposure))

    if not ny:
        ny = int(nx*float(height)/width + 0.5)
        if not ny:
            ny = 1

    schema = afwTable.SourceTable.makeMinimalSchema()

    control = algorithmsLib.GaussianCentroidControl()
    centroider = algorithmsLib.MeasureSourcesBuilder().addAlgorithm(control).build(schema)

    sdssShape = algorithmsLib.SdssShapeControl()
    shaper = algorithmsLib.MeasureSourcesBuilder().addAlgorithm(sdssShape).build(schema)
    
    table = afwTable.SourceTable.make(schema)

    table.defineCentroid(control.name)
    table.defineShape(sdssShape.name)

    bbox = None
    if stampSize > 0:
        w, h = psf.computeImage(afwGeom.PointD(0, 0)).getDimensions()
        if stampSize <= w and stampSize <= h:
            bbox = afwGeom.BoxI(afwGeom.PointI((w - stampSize)//2, (h - stampSize)//2),
                                afwGeom.ExtentI(stampSize, stampSize))

    centers = []
    shapes = []
    for iy in range(ny):
        for ix in range(nx):
            x = int(ix*(width-1)/(nx-1)) + x0
            y = int(iy*(height-1)/(ny-1)) + y0

            im = psf.computeImage(afwGeom.PointD(x, y)).convertF()
            imPeak = psf.computePeak(afwGeom.PointD(x, y))
            im /= imPeak
            if bbox:
                im = im.Factory(im, bbox)
            lab = "PSF(%d,%d)" % (x, y) if False else ""
            mos.append(im, lab)
    
            exp = afwImage.makeExposure(afwImage.makeMaskedImage(im))
            w, h = im.getWidth(), im.getHeight()
            cen = afwGeom.PointD(im.getX0() + w//2, im.getY0() + h//2)
            src = table.makeRecord()
            foot = afwDet.Footprint(exp.getBBox())
            src.setFootprint(foot)

            centroider.apply(src, exp, cen)
            centers.append((src.getX() - im.getX0(), src.getY() - im.getY0()))

            shaper.apply(src, exp, cen)
            shapes.append((src.getIxx(), src.getIxy(), src.getIyy()))
            
    mos.makeMosaic(frame=frame, title=title if title else "Model Psf", mode=nx)

    if centers and frame is not None:
        i = 0
        with ds9.Buffering():
            for cen, shape in zip(centers, shapes):
                bbox = mos.getBBox(i); i += 1
                xc, yc = cen[0] + bbox.getMinX(),  cen[1] + bbox.getMinY()
                if showCenter:
                    ds9.dot("+", xc, yc,  ctype=ds9.BLUE, frame=frame)

                if showEllipticity:
                    ixx, ixy, iyy = shape
                    ixx *= scale; ixy *= scale; iyy *= scale
                    ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, frame=frame, ctype=ds9.RED)

    return mos
class PcaPsfDeterminer(object):
    """!
    A measurePsfTask psf estimator
    """
    ConfigClass = PcaPsfDeterminerConfig

    def __init__(self, config):
        """!Construct a PCA PSF Fitter

        \param[in] config instance of PcaPsfDeterminerConfig
        """
        self.config = config
        # N.b. name of component is meas.algorithms.psfDeterminer so you can turn on psf debugging
        # independent of which determiner is active
        self.debugLog = pexLog.Debug("meas.algorithms.psfDeterminer")
        self.warnLog = pexLog.Log(pexLog.getDefaultLog(),
                                  "meas.algorithms.psfDeterminer")

    def _fitPsf(self, exposure, psfCellSet, kernelSize, nEigenComponents):
        algorithmsLib.PsfCandidateF.setPixelThreshold(
            self.config.pixelThreshold)
        algorithmsLib.PsfCandidateF.setMaskBlends(self.config.doMaskBlends)
        #
        # Loop trying to use nEigenComponents, but allowing smaller numbers if necessary
        #
        for nEigen in range(nEigenComponents, 0, -1):
            # Determine KL components
            try:
                kernel, eigenValues = algorithmsLib.createKernelFromPsfCandidates(
                    psfCellSet, exposure.getDimensions(), exposure.getXY0(),
                    nEigen, self.config.spatialOrder, kernelSize,
                    self.config.nStarPerCell, bool(self.config.constantWeight))

                break  # OK, we can get nEigen components
            except pexExceptions.LengthError as e:
                if nEigen == 1:  # can't go any lower
                    raise IndexError("No viable PSF candidates survive")

                self.warnLog.log(
                    pexLog.Log.WARN,
                    "%s: reducing number of eigen components" % e.what())
        #
        # We got our eigen decomposition so let's use it
        #
        # Express eigenValues in units of reduced chi^2 per star
        size = kernelSize + 2 * self.config.borderWidth
        nu = size * size - 1  # number of degrees of freedom/star for chi^2
        eigenValues = [
            l / float(
                algorithmsLib.countPsfCandidates(
                    psfCellSet, self.config.nStarPerCell) * nu)
            for l in eigenValues
        ]

        # Fit spatial model
        status, chi2 = algorithmsLib.fitSpatialKernelFromPsfCandidates(
            kernel, psfCellSet, bool(self.config.nonLinearSpatialFit),
            self.config.nStarPerCellSpatialFit, self.config.tolerance,
            self.config.lam)

        psf = algorithmsLib.PcaPsf(kernel)

        return psf, eigenValues, nEigen, chi2

    def determinePsf(self,
                     exposure,
                     psfCandidateList,
                     metadata=None,
                     flagKey=None):
        """!Determine a PCA PSF model for an exposure given a list of PSF candidates

        \param[in] exposure exposure containing the psf candidates (lsst.afw.image.Exposure)
        \param[in] psfCandidateList a sequence of PSF candidates (each an lsst.meas.algorithms.PsfCandidate);
            typically obtained by detecting sources and then running them through a star selector
        \param[in,out] metadata  a home for interesting tidbits of information
        \param[in] flagKey schema key used to mark sources actually used in PSF determination

        \return a list of
         - psf: the measured PSF, an lsst.meas.algorithms.PcaPsf
         - cellSet: an lsst.afw.math.SpatialCellSet containing the PSF candidates
        """
        import lsstDebug
        display = lsstDebug.Info(__name__).display
        displayExposure = lsstDebug.Info(
            __name__).displayExposure  # display the Exposure + spatialCells
        displayPsfCandidates = lsstDebug.Info(
            __name__).displayPsfCandidates  # show the viable candidates
        displayIterations = lsstDebug.Info(
            __name__).displayIterations  # display on each PSF iteration
        displayPsfComponents = lsstDebug.Info(
            __name__).displayPsfComponents  # show the PCA components
        displayResiduals = lsstDebug.Info(
            __name__).displayResiduals  # show residuals
        displayPsfMosaic = lsstDebug.Info(
            __name__).displayPsfMosaic  # show mosaic of reconstructed PSF(x,y)
        matchKernelAmplitudes = lsstDebug.Info(
            __name__).matchKernelAmplitudes  # match Kernel amplitudes
        # for spatial plots
        keepMatplotlibPlots = lsstDebug.Info(
            __name__).keepMatplotlibPlots  # Keep matplotlib alive
        # post mortem
        displayPsfSpatialModel = lsstDebug.Info(
            __name__).displayPsfSpatialModel  # Plot spatial model?
        showBadCandidates = lsstDebug.Info(
            __name__).showBadCandidates  # Include bad candidates
        normalizeResiduals = lsstDebug.Info(
            __name__).normalizeResiduals  # Normalise residuals by
        # object amplitude
        pause = lsstDebug.Info(
            __name__).pause  # Prompt user after each iteration?

        if display > 1:
            pause = True

        mi = exposure.getMaskedImage()

        if len(psfCandidateList) == 0:
            raise RuntimeError("No PSF candidates supplied.")

        # construct and populate a spatial cell set
        bbox = mi.getBBox()
        psfCellSet = afwMath.SpatialCellSet(bbox, self.config.sizeCellX,
                                            self.config.sizeCellY)
        sizes = []
        for i, psfCandidate in enumerate(psfCandidateList):
            if psfCandidate.getSource().getPsfFluxFlag():  # bad measurement
                continue

            try:
                psfCellSet.insertCandidate(psfCandidate)
            except Exception, e:
                self.debugLog.debug(
                    2, "Skipping PSF candidate %d of %d: %s" %
                    (i, len(psfCandidateList), e))
                continue
            source = psfCandidate.getSource()

            quad = afwEll.Quadrupole(source.getIxx(), source.getIyy(),
                                     source.getIxy())
            axes = afwEll.Axes(quad)
            sizes.append(axes.getA())
        if len(sizes) == 0:
            raise RuntimeError("No usable PSF candidates supplied")
        nEigenComponents = self.config.nEigenComponents  # initial version

        if self.config.kernelSize >= 15:
            self.debugLog.debug(1, \
                "WARNING: NOT scaling kernelSize by stellar quadrupole moment " +
                "because config.kernelSize=%s >= 15; using config.kernelSize as as the width, instead" \
                % (self.config.kernelSize,)
            )
            actualKernelSize = int(self.config.kernelSize)
        else:
            medSize = numpy.median(sizes)
            actualKernelSize = 2 * int(self.config.kernelSize *
                                       math.sqrt(medSize) + 0.5) + 1
            if actualKernelSize < self.config.kernelSizeMin:
                actualKernelSize = self.config.kernelSizeMin
            if actualKernelSize > self.config.kernelSizeMax:
                actualKernelSize = self.config.kernelSizeMax

            if display:
                print "Median size=%s" % (medSize, )
        self.debugLog.debug(3, "Kernel size=%s" % (actualKernelSize, ))

        # Set size of image returned around candidate
        psfCandidateList[0].setHeight(actualKernelSize)
        psfCandidateList[0].setWidth(actualKernelSize)

        if self.config.doRejectBlends:
            # Remove blended candidates completely
            blendedCandidates = [
            ]  # Candidates to remove; can't do it while iterating
            for cell, cand in candidatesIter(psfCellSet, False):
                if len(cand.getSource().getFootprint().getPeaks()) > 1:
                    blendedCandidates.append((cell, cand))
                    continue
            if display:
                print "Removing %d blended Psf candidates" % len(
                    blendedCandidates)
            for cell, cand in blendedCandidates:
                cell.removeCandidate(cand)
            if sum(1 for cand in candidatesIter(psfCellSet, False)) == 0:
                raise RuntimeError("All PSF candidates removed as blends")

        if display:
            frame = 0
            if displayExposure:
                ds9.mtv(exposure, frame=frame, title="psf determination")
                maUtils.showPsfSpatialCells(exposure,
                                            psfCellSet,
                                            self.config.nStarPerCell,
                                            symb="o",
                                            ctype=ds9.CYAN,
                                            ctypeUnused=ds9.YELLOW,
                                            size=4,
                                            frame=frame)

        #
        # Do a PCA decomposition of those PSF candidates
        #
        reply = "y"  # used in interactive mode
        for iter in range(self.config.nIterForPsf):
            if display and displayPsfCandidates:  # Show a mosaic of usable PSF candidates
                #
                import lsst.afw.display.utils as displayUtils

                stamps = []
                for cell in psfCellSet.getCellList():
                    for cand in cell.begin(not showBadCandidates
                                           ):  # maybe include bad candidates
                        cand = algorithmsLib.cast_PsfCandidateF(cand)

                        try:
                            im = cand.getMaskedImage()

                            chi2 = cand.getChi2()
                            if chi2 > 1e100:
                                chi2 = numpy.nan

                            stamps.append(
                                (im, "%d%s" %
                                 (maUtils.splitId(cand.getSource().getId(),
                                                  True)["objId"], chi2),
                                 cand.getStatus()))
                        except Exception, e:
                            continue

                if len(stamps) == 0:
                    print "WARNING: No PSF candidates to show; try setting showBadCandidates=True"
                else:
                    mos = displayUtils.Mosaic()
                    for im, label, status in stamps:
                        im = type(im)(im, True)
                        try:
                            im /= afwMath.makeStatistics(
                                im, afwMath.MAX).getValue()
                        except NotImplementedError:
                            pass

                        mos.append(
                            im, label, ds9.GREEN
                            if status == afwMath.SpatialCellCandidate.GOOD else
                            ds9.YELLOW if status ==
                            afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)

                    mos.makeMosaic(frame=8, title="Psf Candidates")

            # Re-fit until we don't have any candidates with naughty chi^2 values influencing the fit
            cleanChi2 = False  # Any naughty (negative/NAN) chi^2 values?
            while not cleanChi2:
                cleanChi2 = True
                #
                # First, estimate the PSF
                #
                psf, eigenValues, nEigenComponents, fitChi2 = \
                    self._fitPsf(exposure, psfCellSet, actualKernelSize, nEigenComponents)
                #
                # In clipping, allow all candidates to be innocent until proven guilty on this iteration.
                # Throw out any prima facie guilty candidates (naughty chi^2 values)
                #
                for cell in psfCellSet.getCellList():
                    awfulCandidates = []
                    for cand in cell.begin(False):  # include bad candidates
                        cand = algorithmsLib.cast_PsfCandidateF(cand)
                        cand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN
                                       )  # until proven guilty
                        rchi2 = cand.getChi2()
                        if not numpy.isfinite(rchi2) or rchi2 <= 0:
                            # Guilty prima facie
                            awfulCandidates.append(cand)
                            cleanChi2 = False
                            self.debugLog.debug(
                                2, "chi^2=%s; id=%s" %
                                (cand.getChi2(), cand.getSource().getId()))
                    for cand in awfulCandidates:
                        if display:
                            print "Removing bad candidate: id=%d, chi^2=%f" % \
                                  (cand.getSource().getId(), cand.getChi2())
                        cell.removeCandidate(cand)

            #
            # Clip out bad fits based on reduced chi^2
            #
            badCandidates = list()
            for cell in psfCellSet.getCellList():
                for cand in cell.begin(False):  # include bad candidates
                    cand = algorithmsLib.cast_PsfCandidateF(cand)
                    rchi2 = cand.getChi2(
                    )  # reduced chi^2 when fitting PSF to candidate
                    assert rchi2 > 0
                    if rchi2 > self.config.reducedChi2ForPsfCandidates:
                        badCandidates.append(cand)

            badCandidates.sort(key=lambda x: x.getChi2(), reverse=True)
            numBad = int(
                len(badCandidates) * (iter + 1) / self.config.nIterForPsf +
                0.5)
            for i, c in zip(range(numBad), badCandidates):
                if display:
                    chi2 = c.getChi2()
                    if chi2 > 1e100:
                        chi2 = numpy.nan

                    print "Chi^2 clipping %-4d  %.2g" % (c.getSource().getId(),
                                                         chi2)
                c.setStatus(afwMath.SpatialCellCandidate.BAD)

            #
            # Clip out bad fits based on spatial fitting.
            #
            # This appears to be better at getting rid of sources that have a single dominant kernel component
            # (other than the zeroth; e.g., a nearby contaminant) because the surrounding sources (which help
            # set the spatial model) don't contain that kernel component, and so the spatial modeling
            # downweights the component.
            #

            residuals = list()
            candidates = list()
            kernel = psf.getKernel()
            noSpatialKernel = afwMath.cast_LinearCombinationKernel(
                psf.getKernel())
            for cell in psfCellSet.getCellList():
                for cand in cell.begin(False):
                    cand = algorithmsLib.cast_PsfCandidateF(cand)
                    candCenter = afwGeom.PointD(cand.getXCenter(),
                                                cand.getYCenter())
                    try:
                        im = cand.getMaskedImage(kernel.getWidth(),
                                                 kernel.getHeight())
                    except Exception, e:
                        continue

                    fit = algorithmsLib.fitKernelParamsToImage(
                        noSpatialKernel, im, candCenter)
                    params = fit[0]
                    kernels = fit[1]
                    amp = 0.0
                    for p, k in zip(params, kernels):
                        amp += p * afwMath.cast_FixedKernel(k).getSum()

                    predict = [
                        kernel.getSpatialFunction(k)(candCenter.getX(),
                                                     candCenter.getY())
                        for k in range(kernel.getNKernelParameters())
                    ]

                    #print cand.getSource().getId(), [a / amp for a in params], predict

                    residuals.append(
                        [a / amp - p for a, p in zip(params, predict)])
                    candidates.append(cand)
Beispiel #29
0
    def determinePsf(self,
                     exposure,
                     psfCandidateList,
                     metadata=None,
                     flagKey=None):
        """!Determine a PCA PSF model for an exposure given a list of PSF candidates

        \param[in] exposure exposure containing the psf candidates (lsst.afw.image.Exposure)
        \param[in] psfCandidateList a sequence of PSF candidates (each an lsst.meas.algorithms.PsfCandidate);
            typically obtained by detecting sources and then running them through a star selector
        \param[in,out] metadata  a home for interesting tidbits of information
        \param[in] flagKey schema key used to mark sources actually used in PSF determination

        \return a list of
         - psf: the measured PSF, an lsst.meas.algorithms.PcaPsf
         - cellSet: an lsst.afw.math.SpatialCellSet containing the PSF candidates
        """
        import lsstDebug
        display = lsstDebug.Info(__name__).display
        displayExposure = lsstDebug.Info(
            __name__).displayExposure  # display the Exposure + spatialCells
        displayPsfCandidates = lsstDebug.Info(
            __name__).displayPsfCandidates  # show the viable candidates
        displayIterations = lsstDebug.Info(
            __name__).displayIterations  # display on each PSF iteration
        displayPsfComponents = lsstDebug.Info(
            __name__).displayPsfComponents  # show the PCA components
        displayResiduals = lsstDebug.Info(
            __name__).displayResiduals  # show residuals
        displayPsfMosaic = lsstDebug.Info(
            __name__).displayPsfMosaic  # show mosaic of reconstructed PSF(x,y)
        # match Kernel amplitudes for spatial plots
        matchKernelAmplitudes = lsstDebug.Info(__name__).matchKernelAmplitudes
        # Keep matplotlib alive post mortem
        keepMatplotlibPlots = lsstDebug.Info(__name__).keepMatplotlibPlots
        displayPsfSpatialModel = lsstDebug.Info(
            __name__).displayPsfSpatialModel  # Plot spatial model?
        showBadCandidates = lsstDebug.Info(
            __name__).showBadCandidates  # Include bad candidates
        # Normalize residuals by object amplitude
        normalizeResiduals = lsstDebug.Info(__name__).normalizeResiduals
        pause = lsstDebug.Info(
            __name__).pause  # Prompt user after each iteration?

        if display > 1:
            pause = True

        mi = exposure.getMaskedImage()

        if len(psfCandidateList) == 0:
            raise RuntimeError("No PSF candidates supplied.")

        # construct and populate a spatial cell set
        bbox = mi.getBBox()
        psfCellSet = afwMath.SpatialCellSet(bbox, self.config.sizeCellX,
                                            self.config.sizeCellY)
        sizes = []
        for i, psfCandidate in enumerate(psfCandidateList):
            if psfCandidate.getSource().getPsfFluxFlag():  # bad measurement
                continue

            try:
                psfCellSet.insertCandidate(psfCandidate)
            except Exception as e:
                self.log.debug("Skipping PSF candidate %d of %d: %s", i,
                               len(psfCandidateList), e)
                continue
            source = psfCandidate.getSource()

            quad = afwEll.Quadrupole(source.getIxx(), source.getIyy(),
                                     source.getIxy())
            axes = afwEll.Axes(quad)
            sizes.append(axes.getA())
        if len(sizes) == 0:
            raise RuntimeError("No usable PSF candidates supplied")
        nEigenComponents = self.config.nEigenComponents  # initial version

        if self.config.kernelSize >= 15:
            self.log.warn(
                "WARNING: NOT scaling kernelSize by stellar quadrupole moment "
                +
                "because config.kernelSize=%s >= 15; using config.kernelSize as as the width, instead",
                self.config.kernelSize)
            actualKernelSize = int(self.config.kernelSize)
        else:
            medSize = numpy.median(sizes)
            actualKernelSize = 2 * int(self.config.kernelSize *
                                       math.sqrt(medSize) + 0.5) + 1
            if actualKernelSize < self.config.kernelSizeMin:
                actualKernelSize = self.config.kernelSizeMin
            if actualKernelSize > self.config.kernelSizeMax:
                actualKernelSize = self.config.kernelSizeMax

            if display:
                print("Median size=%s" % (medSize, ))
        self.log.trace("Kernel size=%s", actualKernelSize)

        # Set size of image returned around candidate
        psfCandidateList[0].setHeight(actualKernelSize)
        psfCandidateList[0].setWidth(actualKernelSize)

        if self.config.doRejectBlends:
            # Remove blended candidates completely
            blendedCandidates = [
            ]  # Candidates to remove; can't do it while iterating
            for cell, cand in candidatesIter(psfCellSet, False):
                if len(cand.getSource().getFootprint().getPeaks()) > 1:
                    blendedCandidates.append((cell, cand))
                    continue
            if display:
                print("Removing %d blended Psf candidates" %
                      len(blendedCandidates))
            for cell, cand in blendedCandidates:
                cell.removeCandidate(cand)
            if sum(1 for cand in candidatesIter(psfCellSet, False)) == 0:
                raise RuntimeError("All PSF candidates removed as blends")

        if display:
            frame = 0
            if displayExposure:
                ds9.mtv(exposure, frame=frame, title="psf determination")
                maUtils.showPsfSpatialCells(exposure,
                                            psfCellSet,
                                            self.config.nStarPerCell,
                                            symb="o",
                                            ctype=ds9.CYAN,
                                            ctypeUnused=ds9.YELLOW,
                                            size=4,
                                            frame=frame)

        #
        # Do a PCA decomposition of those PSF candidates
        #
        reply = "y"  # used in interactive mode
        for iterNum in range(self.config.nIterForPsf):
            if display and displayPsfCandidates:  # Show a mosaic of usable PSF candidates
                #
                import lsst.afw.display.utils as displayUtils

                stamps = []
                for cell in psfCellSet.getCellList():
                    for cand in cell.begin(not showBadCandidates
                                           ):  # maybe include bad candidates
                        try:
                            im = cand.getMaskedImage()

                            chi2 = cand.getChi2()
                            if chi2 > 1e100:
                                chi2 = numpy.nan

                            stamps.append(
                                (im, "%d%s" %
                                 (maUtils.splitId(cand.getSource().getId(),
                                                  True)["objId"], chi2),
                                 cand.getStatus()))
                        except Exception as e:
                            continue

                if len(stamps) == 0:
                    print(
                        "WARNING: No PSF candidates to show; try setting showBadCandidates=True"
                    )
                else:
                    mos = displayUtils.Mosaic()
                    for im, label, status in stamps:
                        im = type(im)(im, True)
                        try:
                            im /= afwMath.makeStatistics(
                                im, afwMath.MAX).getValue()
                        except NotImplementedError:
                            pass

                        mos.append(
                            im, label, ds9.GREEN
                            if status == afwMath.SpatialCellCandidate.GOOD else
                            ds9.YELLOW if status ==
                            afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)

                    mos.makeMosaic(frame=8, title="Psf Candidates")

            # Re-fit until we don't have any candidates with naughty chi^2 values influencing the fit
            cleanChi2 = False  # Any naughty (negative/NAN) chi^2 values?
            while not cleanChi2:
                cleanChi2 = True
                #
                # First, estimate the PSF
                #
                psf, eigenValues, nEigenComponents, fitChi2 = \
                    self._fitPsf(exposure, psfCellSet, actualKernelSize, nEigenComponents)
                #
                # In clipping, allow all candidates to be innocent until proven guilty on this iteration.
                # Throw out any prima facie guilty candidates (naughty chi^2 values)
                #
                for cell in psfCellSet.getCellList():
                    awfulCandidates = []
                    for cand in cell.begin(False):  # include bad candidates
                        cand.setStatus(afwMath.SpatialCellCandidate.UNKNOWN
                                       )  # until proven guilty
                        rchi2 = cand.getChi2()
                        if not numpy.isfinite(rchi2) or rchi2 <= 0:
                            # Guilty prima facie
                            awfulCandidates.append(cand)
                            cleanChi2 = False
                            self.log.debug("chi^2=%s; id=%s", cand.getChi2(),
                                           cand.getSource().getId())
                    for cand in awfulCandidates:
                        if display:
                            print("Removing bad candidate: id=%d, chi^2=%f" % \
                                  (cand.getSource().getId(), cand.getChi2()))
                        cell.removeCandidate(cand)

            #
            # Clip out bad fits based on reduced chi^2
            #
            badCandidates = list()
            for cell in psfCellSet.getCellList():
                for cand in cell.begin(False):  # include bad candidates
                    rchi2 = cand.getChi2(
                    )  # reduced chi^2 when fitting PSF to candidate
                    assert rchi2 > 0
                    if rchi2 > self.config.reducedChi2ForPsfCandidates:
                        badCandidates.append(cand)

            badCandidates.sort(key=lambda x: x.getChi2(), reverse=True)
            numBad = numCandidatesToReject(len(badCandidates), iterNum,
                                           self.config.nIterForPsf)
            for i, c in zip(range(numBad), badCandidates):
                if display:
                    chi2 = c.getChi2()
                    if chi2 > 1e100:
                        chi2 = numpy.nan

                    print("Chi^2 clipping %-4d  %.2g" %
                          (c.getSource().getId(), chi2))
                c.setStatus(afwMath.SpatialCellCandidate.BAD)

            #
            # Clip out bad fits based on spatial fitting.
            #
            # This appears to be better at getting rid of sources that have a single dominant kernel component
            # (other than the zeroth; e.g., a nearby contaminant) because the surrounding sources (which help
            # set the spatial model) don't contain that kernel component, and so the spatial modeling
            # downweights the component.
            #

            residuals = list()
            candidates = list()
            kernel = psf.getKernel()
            noSpatialKernel = psf.getKernel()
            for cell in psfCellSet.getCellList():
                for cand in cell.begin(False):
                    candCenter = afwGeom.PointD(cand.getXCenter(),
                                                cand.getYCenter())
                    try:
                        im = cand.getMaskedImage(kernel.getWidth(),
                                                 kernel.getHeight())
                    except Exception as e:
                        continue

                    fit = fitKernelParamsToImage(noSpatialKernel, im,
                                                 candCenter)
                    params = fit[0]
                    kernels = fit[1]
                    amp = 0.0
                    for p, k in zip(params, kernels):
                        amp += p * k.getSum()

                    predict = [
                        kernel.getSpatialFunction(k)(candCenter.getX(),
                                                     candCenter.getY())
                        for k in range(kernel.getNKernelParameters())
                    ]

                    #print cand.getSource().getId(), [a / amp for a in params], predict

                    residuals.append(
                        [a / amp - p for a, p in zip(params, predict)])
                    candidates.append(cand)

            residuals = numpy.array(residuals)

            for k in range(kernel.getNKernelParameters()):
                if False:
                    # Straight standard deviation
                    mean = residuals[:, k].mean()
                    rms = residuals[:, k].std()
                elif False:
                    # Using interquartile range
                    sr = numpy.sort(residuals[:, k])
                    mean = sr[int(0.5*len(sr))] if len(sr) % 2 else \
                        0.5 * (sr[int(0.5*len(sr))] + sr[int(0.5*len(sr))+1])
                    rms = 0.74 * (sr[int(0.75 * len(sr))] -
                                  sr[int(0.25 * len(sr))])
                else:
                    stats = afwMath.makeStatistics(
                        residuals[:, k], afwMath.MEANCLIP | afwMath.STDEVCLIP)
                    mean = stats.getValue(afwMath.MEANCLIP)
                    rms = stats.getValue(afwMath.STDEVCLIP)

                rms = max(
                    1.0e-4,
                    rms)  # Don't trust RMS below this due to numerical issues

                if display:
                    print("Mean for component %d is %f" % (k, mean))
                    print("RMS for component %d is %f" % (k, rms))
                badCandidates = list()
                for i, cand in enumerate(candidates):
                    if numpy.fabs(residuals[i, k] -
                                  mean) > self.config.spatialReject * rms:
                        badCandidates.append(i)

                badCandidates.sort(
                    key=lambda x: numpy.fabs(residuals[x, k] - mean),
                    reverse=True)

                numBad = numCandidatesToReject(len(badCandidates), iterNum,
                                               self.config.nIterForPsf)

                for i, c in zip(range(min(len(badCandidates), numBad)),
                                badCandidates):
                    cand = candidates[c]
                    if display:
                        print("Spatial clipping %d (%f,%f) based on %d: %f vs %f" % \
                              (cand.getSource().getId(), cand.getXCenter(), cand.getYCenter(), k,
                               residuals[badCandidates[i], k], self.config.spatialReject * rms))
                    cand.setStatus(afwMath.SpatialCellCandidate.BAD)

            #
            # Display results
            #
            if display and displayIterations:
                if displayExposure:
                    if iterNum > 0:
                        ds9.erase(frame=frame)
                    maUtils.showPsfSpatialCells(exposure,
                                                psfCellSet,
                                                self.config.nStarPerCell,
                                                showChi2=True,
                                                symb="o",
                                                size=8,
                                                frame=frame,
                                                ctype=ds9.YELLOW,
                                                ctypeBad=ds9.RED,
                                                ctypeUnused=ds9.MAGENTA)
                    if self.config.nStarPerCellSpatialFit != self.config.nStarPerCell:
                        maUtils.showPsfSpatialCells(
                            exposure,
                            psfCellSet,
                            self.config.nStarPerCellSpatialFit,
                            symb="o",
                            size=10,
                            frame=frame,
                            ctype=ds9.YELLOW,
                            ctypeBad=ds9.RED)
                if displayResiduals:
                    while True:
                        try:
                            maUtils.showPsfCandidates(
                                exposure,
                                psfCellSet,
                                psf=psf,
                                frame=4,
                                normalize=normalizeResiduals,
                                showBadCandidates=showBadCandidates)
                            maUtils.showPsfCandidates(
                                exposure,
                                psfCellSet,
                                psf=psf,
                                frame=5,
                                normalize=normalizeResiduals,
                                showBadCandidates=showBadCandidates,
                                variance=True)
                        except:
                            if not showBadCandidates:
                                showBadCandidates = True
                                continue
                        break

                if displayPsfComponents:
                    maUtils.showPsf(psf, eigenValues, frame=6)
                if displayPsfMosaic:
                    maUtils.showPsfMosaic(exposure,
                                          psf,
                                          frame=7,
                                          showFwhm=True)
                    ds9.scale('linear', 0, 1, frame=7)
                if displayPsfSpatialModel:
                    maUtils.plotPsfSpatialModel(
                        exposure,
                        psf,
                        psfCellSet,
                        showBadCandidates=True,
                        matchKernelAmplitudes=matchKernelAmplitudes,
                        keepPlots=keepMatplotlibPlots)

                if pause:
                    while True:
                        try:
                            reply = input(
                                "Next iteration? [ynchpqQs] ").strip()
                        except EOFError:
                            reply = "n"

                        reply = reply.split()
                        if reply:
                            reply, args = reply[0], reply[1:]
                        else:
                            reply = ""

                        if reply in ("", "c", "h", "n", "p", "q", "Q", "s",
                                     "y"):
                            if reply == "c":
                                pause = False
                            elif reply == "h":
                                print("c[ontinue without prompting] h[elp] n[o] p[db] q[uit displaying] " \
                                      "s[ave fileName] y[es]")
                                continue
                            elif reply == "p":
                                import pdb
                                pdb.set_trace()
                            elif reply == "q":
                                display = False
                            elif reply == "Q":
                                sys.exit(1)
                            elif reply == "s":
                                fileName = args.pop(0)
                                if not fileName:
                                    print("Please provide a filename")
                                    continue

                                print("Saving to %s" % fileName)
                                maUtils.saveSpatialCellSet(psfCellSet,
                                                           fileName=fileName)
                                continue
                            break
                        else:
                            print("Unrecognised response: %s" % reply,
                                  file=sys.stderr)

                    if reply == "n":
                        break

        # One last time, to take advantage of the last iteration
        psf, eigenValues, nEigenComponents, fitChi2 = \
            self._fitPsf(exposure, psfCellSet, actualKernelSize, nEigenComponents)

        #
        # Display code for debugging
        #
        if display and reply != "n":
            if displayExposure:
                maUtils.showPsfSpatialCells(exposure,
                                            psfCellSet,
                                            self.config.nStarPerCell,
                                            showChi2=True,
                                            symb="o",
                                            ctype=ds9.YELLOW,
                                            ctypeBad=ds9.RED,
                                            size=8,
                                            frame=frame)
                if self.config.nStarPerCellSpatialFit != self.config.nStarPerCell:
                    maUtils.showPsfSpatialCells(
                        exposure,
                        psfCellSet,
                        self.config.nStarPerCellSpatialFit,
                        symb="o",
                        ctype=ds9.YELLOW,
                        ctypeBad=ds9.RED,
                        size=10,
                        frame=frame)
                if displayResiduals:
                    maUtils.showPsfCandidates(
                        exposure,
                        psfCellSet,
                        psf=psf,
                        frame=4,
                        normalize=normalizeResiduals,
                        showBadCandidates=showBadCandidates)

            if displayPsfComponents:
                maUtils.showPsf(psf, eigenValues, frame=6)

            if displayPsfMosaic:
                maUtils.showPsfMosaic(exposure, psf, frame=7, showFwhm=True)
                ds9.scale("linear", 0, 1, frame=7)
            if displayPsfSpatialModel:
                maUtils.plotPsfSpatialModel(
                    exposure,
                    psf,
                    psfCellSet,
                    showBadCandidates=True,
                    matchKernelAmplitudes=matchKernelAmplitudes,
                    keepPlots=keepMatplotlibPlots)
        #
        # Generate some QA information
        #
        # Count PSF stars
        #
        numGoodStars = 0
        numAvailStars = 0

        avgX = 0.0
        avgY = 0.0

        for cell in psfCellSet.getCellList():
            for cand in cell.begin(False):  # don't ignore BAD stars
                numAvailStars += 1

            for cand in cell.begin(True):  # do ignore BAD stars
                src = cand.getSource()
                if flagKey is not None:
                    src.set(flagKey, True)
                avgX += src.getX()
                avgY += src.getY()
                numGoodStars += 1

        avgX /= numGoodStars
        avgY /= numGoodStars

        if metadata is not None:
            metadata.set("spatialFitChi2", fitChi2)
            metadata.set("numGoodStars", numGoodStars)
            metadata.set("numAvailStars", numAvailStars)
            metadata.set("avgX", avgX)
            metadata.set("avgY", avgY)

        psf = PcaPsf(psf.getKernel(), afwGeom.Point2D(avgX, avgY))

        return psf, psfCellSet
Beispiel #30
0
def showKernelCandidates(kernelCellSet,
                         kernel,
                         background,
                         frame=None,
                         showBadCandidates=True,
                         resids=False,
                         kernels=False):
    """Display the Kernel candidates.
    If kernel is provided include spatial model and residuals;
    If chi is True, generate a plot of residuals/sqrt(variance), i.e. chi
    """

    #
    # Show us the ccandidates
    #
    if kernels:
        mos = displayUtils.Mosaic(gutter=5, background=0)
    else:
        mos = displayUtils.Mosaic(gutter=5, background=-1)
    #
    candidateCenters = []
    candidateCentersBad = []
    candidateIndex = 0
    for cell in kernelCellSet.getCellList():
        for cand in cell.begin(False):  # include bad candidates
            # Original difference image; if does not exist, skip candidate
            try:
                resid = cand.getDifferenceImage(
                    diffimLib.KernelCandidateF.ORIG)
            except Exception:
                continue

            rchi2 = cand.getChi2()
            if rchi2 > 1e100:
                rchi2 = np.nan

            if not showBadCandidates and cand.isBad():
                continue

            im_resid = displayUtils.Mosaic(gutter=1, background=-0.5, mode="x")

            try:
                im = cand.getScienceMaskedImage()
                im = im.Factory(im, True)
                im.setXY0(cand.getScienceMaskedImage().getXY0())
            except Exception:
                continue
            if (not resids and not kernels):
                im_resid.append(im.Factory(im, True))
            try:
                im = cand.getTemplateMaskedImage()
                im = im.Factory(im, True)
                im.setXY0(cand.getTemplateMaskedImage().getXY0())
            except Exception:
                continue
            if (not resids and not kernels):
                im_resid.append(im.Factory(im, True))

            # Difference image with original basis
            if resids:
                var = resid.getVariance()
                var = var.Factory(var, True)
                np.sqrt(var.getArray(), var.getArray())  # inplace sqrt
                resid = resid.getImage()
                resid /= var
                bbox = kernel.shrinkBBox(resid.getBBox())
                resid = resid.Factory(resid, bbox, True)
            elif kernels:
                kim = cand.getKernelImage(
                    diffimLib.KernelCandidateF.ORIG).convertF()
                resid = kim.Factory(kim, True)
            im_resid.append(resid)

            # residuals using spatial model
            ski = afwImage.ImageD(kernel.getDimensions())
            kernel.computeImage(ski, False, int(cand.getXCenter()),
                                int(cand.getYCenter()))
            sk = afwMath.FixedKernel(ski)
            sbg = 0.0
            if background:
                sbg = background(int(cand.getXCenter()),
                                 int(cand.getYCenter()))
            sresid = cand.getDifferenceImage(sk, sbg)
            resid = sresid
            if resids:
                resid = sresid.getImage()
                resid /= var
                bbox = kernel.shrinkBBox(resid.getBBox())
                resid = resid.Factory(resid, bbox, True)
            elif kernels:
                kim = ski.convertF()
                resid = kim.Factory(kim, True)
            im_resid.append(resid)

            im = im_resid.makeMosaic()

            lab = "%d chi^2 %.1f" % (cand.getId(), rchi2)
            ctype = ds9.RED if cand.isBad() else ds9.GREEN

            mos.append(im, lab, ctype)

            if False and np.isnan(rchi2):
                ds9.mtv(cand.getScienceMaskedImage.getImage(),
                        title="candidate",
                        frame=1)
                print("rating", cand.getCandidateRating())

            im = cand.getScienceMaskedImage()
            center = (candidateIndex, cand.getXCenter() - im.getX0(),
                      cand.getYCenter() - im.getY0())
            candidateIndex += 1
            if cand.isBad():
                candidateCentersBad.append(center)
            else:
                candidateCenters.append(center)

    if resids:
        title = "chi Diffim"
    elif kernels:
        title = "Kernels"
    else:
        title = "Candidates & residuals"
    mosaicImage = mos.makeMosaic(frame=frame, title=title)

    return mosaicImage