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
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
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)
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