def _computeVaryingPsf(self):
        """Compute a varying PSF as a linear combination of PCA (== Karhunen-Loeve) basis functions

        We simply desire a PSF that is not constant across the image, so the precise choice of
        parameters (e.g., sigmas, setSpatialParameters) are not crucial.
        """
        kernelSize = 31
        sigma1 = 1.75
        sigma2 = 2.0 * sigma1
        basisKernelList = []
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(
                kernelSize, kernelSize,
                afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= np.sum(basisImage.getArray())
            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0
            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1
        spFunc = afwMath.PolynomialFunction2D(order)
        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5E-2, 0.2E-2]])
        exactPsf = measAlg.PcaPsf(exactKernel)

        return exactPsf
    def setUp(self):

        self.schema = afwTable.SourceTable.makeMinimalSchema()
        config = measBase.SingleFrameMeasurementConfig()
        config.algorithms.names = [
            "base_PixelFlags",
            "base_SdssCentroid",
            "base_GaussianFlux",
            "base_SdssShape",
            "base_CircularApertureFlux",
            "base_PsfFlux",
        ]
        config.algorithms["base_CircularApertureFlux"].radii = [3.0]
        config.slots.centroid = "base_SdssCentroid"
        config.slots.psfFlux = "base_PsfFlux"
        config.slots.apFlux = "base_CircularApertureFlux_3_0"
        config.slots.modelFlux = None
        config.slots.instFlux = None
        config.slots.calibFlux = None
        config.slots.shape = "base_SdssShape"

        self.measureTask = measBase.SingleFrameMeasurementTask(self.schema,
                                                               config=config)

        width, height = 110, 301

        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        sd = 3  # standard deviation of image
        self.mi.getVariance().set(sd * sd)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 31  # size of desired kernel

        sigma1 = 1.75
        sigma2 = 2 * sigma1

        self.exposure = afwImage.makeExposure(self.mi)
        self.exposure.setPsf(
            measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1,
                                      0.1))
        self.exposure.setDetector(DetectorWrapper().detector)

        #
        # Make a kernel with the exactly correct basis functions.  Useful for debugging
        #
        basisKernelList = []
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(
                self.ksize, self.ksize,
                afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= np.sum(basisImage.getArray())

            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0

            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1  # 1 => up to linear
        spFunc = afwMath.PolynomialFunction2D(order)

        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0, 0],
                                          [0.0, 0.5 * 1e-2, 0.2e-2]])
        self.exactPsf = measAlg.PcaPsf(exactKernel)

        rand = afwMath.Random()  # make these tests repeatable by setting seed

        addNoise = True

        if addNoise:
            im = self.mi.getImage()
            afwMath.randomGaussianImage(im, rand)  # N(0, 1)
            im *= sd  # N(0, sd^2)
            del im

        xarr, yarr = [], []

        for x, y in [
            (20, 20),
            (60, 20),
            (30, 35),
            (50, 50),
            (20, 90),
            (70, 160),
            (25, 265),
            (75, 275),
            (85, 30),
            (50, 120),
            (70, 80),
            (60, 210),
            (20, 210),
        ]:
            xarr.append(x)
            yarr.append(y)

        for x, y in zip(xarr, yarr):
            dx = rand.uniform() - 0.5  # random (centered) offsets
            dy = rand.uniform() - 0.5

            k = exactKernel.getSpatialFunction(1)(
                x, y)  # functional variation of Kernel ...
            b = (k * sigma1**2 / ((1 - k) * sigma2**2)
                 )  # ... converted double Gaussian's "b"

            # flux = 80000 - 20*x - 10*(y/float(height))**2
            flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5))
            I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2))
            for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1):
                if iy < 0 or iy >= self.mi.getHeight():
                    continue

                for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1):
                    if ix < 0 or ix >= self.mi.getWidth():
                        continue

                    intensity = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1,
                                            sigma2, b)
                    Isample = rand.poisson(
                        intensity) if addNoise else intensity
                    self.mi.getImage().set(
                        ix, iy,
                        self.mi.getImage().get(ix, iy) + Isample)
                    self.mi.getVariance().set(
                        ix, iy,
                        self.mi.getVariance().get(ix, iy) + intensity)
        #
        bbox = afwGeom.BoxI(afwGeom.PointI(0, 0),
                            afwGeom.ExtentI(width, height))
        self.cellSet = afwMath.SpatialCellSet(bbox, 100)

        self.footprintSet = afwDetection.FootprintSet(
            self.mi, afwDetection.Threshold(100), "DETECTED")
        self.catalog = self.measure(self.footprintSet, self.exposure)

        for source in self.catalog:
            try:
                cand = measAlg.makePsfCandidate(source, self.exposure)
                self.cellSet.insertCandidate(cand)

            except Exception as e:
                print(e)
                continue
Пример #3
0
def convertpsField(infile, filt, trim=True, rcscale=0.001, MAX_ORDER_B=5, LSST_ORDER=4):
    if filt not in filtToHdu:
        print("INVALID FILTER", filt)
        sys.exit(1)

    buff = open(infile, "rb")
    pstruct = fits.getdata(buff, ext=filtToHdu[filt])

    spaParList = [[]]*len(pstruct)
    kernelList = []
    for i in range(len(pstruct)):
        nrow_b = pstruct[i][0]  # ny
        ncol_b = pstruct[i][1]  # nx
        cmat = pstruct[i][2].reshape((MAX_ORDER_B, MAX_ORDER_B))
        krow = pstruct[i][4]  # RNROW
        kcol = pstruct[i][5]  # RNCOL
        # This is *not* transposed
        karr = pstruct[i][7].reshape((krow, kcol)).astype(num.float64)

        if trim:
            karr = karr[10:41, 10:41]

        kim = afwImage.ImageD(karr)
        kern = afwMath.FixedKernel(kim)
        kernelList.append(kern)

        # NOTES:

        # Afw has the polynomial terms like:
        #
        # * f(x,y) =   c0                                                      (0th order)
        # *          + c1 x    + c2 y                                          (1st order)
        # *          + c3 x^2  + c4 x y    + c5 y^2                            (2nd order)
        # *          + c6 x^3  + c7 x^2 y  + c8 x y^2    + c9 y^3              (3rd order)
        # *          + c10 x^4 + c11 x^3 y + c12 x^2 y^2 + c13 x y^3 + c14 y^4 (4th order)
        #
        # So, ordered: x^0,y^0 x^1,y^0 x^0,y^1 x^2,y^0 x^1,y^1 x^0,y^2

        # SDSS has the terms ordered like, after reshape():
        #
        # x^0,y^0 x^0,y^1 x^0,y^2
        # x^1,y^0 x^1,y^1 x^1,y^2
        # x^2,y^0 x^2,y^1 x^2,y^2
        #
        # So, it technically goes up to fourth order in LSST-speak.  OK, that is the trick.
        #
        # Mapping:
        # cmat[0][0] = c0  x^0y^0
        # cmat[1][0] = c2  x^0y^1
        # cmat[2][0] = c5  x^0y^2
        # cmat[0][1] = c1  x^1y^0
        # cmat[1][1] = c4  x^1y^1
        # cmat[2][1] = c8  x^1y^2
        # cmat[0][2] = c3  x^2y^0
        # cmat[1][2] = c7  x^2y^1
        # cmat[2][2] = c12 x^2y^2
        #
        # This is quantified in skMatrixPos2TriSeqPosT

        spaParamsTri = num.zeros(MAX_ORDER_B * MAX_ORDER_B)
        for k in range(nrow_b * ncol_b):
            row = k % nrow_b
            col = k // nrow_b
            coeff = cmat[row, col]
            scale = pow(rcscale, row) * pow(rcscale, col)
            scaledCoeff = coeff * scale

            # Was originally written like this, but the SDSS code
            # takes inputs as y,x instead of x,y meaning it was
            # originally transposed
            #
            # idx         = row * MAX_ORDER_B + col

            idx = col * MAX_ORDER_B + row
            spaParamsTri[skMatrixPos2TriSeqPosT[idx]] = scaledCoeff

            # print "%d y=%d x=%d %10.3e %2d %2d %10.3e" % \
            # (i, row, col, cmat[row,col], idx, skMatrixPos2TriSeqPosT[idx], scaledCoeff)

        # print spaParamsTri
        nTerms = (LSST_ORDER + 1) * (LSST_ORDER + 2) // 2
        spaParamsTri = spaParamsTri[:nTerms]
        spaParList[i] = spaParamsTri

    buff.close()
    spaFun = afwMath.PolynomialFunction2D(LSST_ORDER)
    spatialKernel = afwMath.LinearCombinationKernel(kernelList, spaFun)
    spatialKernel.setSpatialParameters(spaParList)
    spatialPsf = measAlg.PcaPsf(spatialKernel)
    return spatialPsf
Пример #4
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)
Пример #5
0
    def setUp(self):
        width, height = 110, 301

        self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height))
        self.mi.set(0)
        sd = 3                          # standard deviation of image
        self.mi.getVariance().set(sd*sd)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.FWHM = 5
        self.ksize = 31                      # size of desired kernel

        sigma1 = 1.75
        sigma2 = 2*sigma1

        self.exposure = afwImage.makeExposure(self.mi)
        self.exposure.setPsf(measAlg.DoubleGaussianPsf(self.ksize, self.ksize,
                                                    1.5*sigma1, 1, 0.1))
        self.exposure.setDetector(cameraGeom.Detector(cameraGeom.Id(1), False, 1.0))
        self.exposure.getDetector().setDistortion(None) #cameraGeom.NullDistortion())
        
        #
        # Make a kernel with the exactly correct basis functions.  Useful for debugging
        #
        basisKernelList = afwMath.KernelList()
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(self.ksize, self.ksize,
                                                 afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= numpy.sum(basisImage.getArray())

            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0

            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1                                # 1 => up to linear
        spFunc = afwMath.PolynomialFunction2D(order)

        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0,          0],
                                          [0.0, 0.5*1e-2, 0.2e-2]])
        self.exactPsf = measAlg.PcaPsf(exactKernel)        

        rand = afwMath.Random()               # make these tests repeatable by setting seed

        addNoise = True

        if addNoise:
            im = self.mi.getImage()
            afwMath.randomGaussianImage(im, rand) # N(0, 1)
            im *= sd                              # N(0, sd^2)
            del im

        xarr, yarr = [], []

        for x, y in [(20, 20), (60, 20), 
                     (30, 35),
                     (50, 50),
                     (20, 90), (70, 160), (25, 265), (75, 275), (85, 30),
                     (50, 120), (70, 80),
                     (60, 210), (20, 210),
                     ]:
            xarr.append(x)
            yarr.append(y)

        for x, y in zip(xarr, yarr):
            dx = rand.uniform() - 0.5   # random (centered) offsets
            dy = rand.uniform() - 0.5

            k = exactKernel.getSpatialFunction(1)(x, y) # functional variation of Kernel ...
            b = (k*sigma1**2/((1 - k)*sigma2**2))       # ... converted double Gaussian's "b"

            #flux = 80000 - 20*x - 10*(y/float(height))**2
            flux = 80000*(1 + 0.1*(rand.uniform() - 0.5))
            I0 = flux*(1 + b)/(2*numpy.pi*(sigma1**2 + b*sigma2**2))
            for iy in range(y - self.ksize//2, y + self.ksize//2 + 1):
                if iy < 0 or iy >= self.mi.getHeight():
                    continue

                for ix in range(x - self.ksize//2, x + self.ksize//2 + 1):
                    if ix < 0 or ix >= self.mi.getWidth():
                        continue

                    I = I0*psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b)
                    Isample = rand.poisson(I) if addNoise else I
                    self.mi.getImage().set(ix, iy, self.mi.getImage().get(ix, iy) + Isample)
                    self.mi.getVariance().set(ix, iy, self.mi.getVariance().get(ix, iy) + I)
        # 
        bbox = afwGeom.BoxI(afwGeom.PointI(0,0), afwGeom.ExtentI(width, height))
        self.cellSet = afwMath.SpatialCellSet(bbox, 100)

        self.footprintSet = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(100), "DETECTED")

        self.catalog = SpatialModelPsfTestCase.measure(self.footprintSet, self.exposure)

        for source in self.catalog:
            try:
                cand = measAlg.makePsfCandidate(source, self.exposure)
                self.cellSet.insertCandidate(cand)

            except Exception, e:
                print e
                continue