def makeCcdMosaic(dir,
                  basename,
                  e,
                  c,
                  aList,
                  imageFactory=afwImage.MaskedImageF,
                  verbose=0):
    """Return an image of all the specified amplifiers, aList, for the given CCD

    E.g. sl = makeCcdMosaic("/lsst/DC3root/rlp1173", "v704897", 0, 3, range(8))
    """

    try:
        aList[0]
    except TypeError:
        aList = [aList]

    for what in ("header", "data"):
        if what == "header":
            bbox = afwGeom.Box2I()
            ampBBox = {}
            wcs = {}
        else:
            ccdImage = imageFactory(bbox.getWidth(), bbox.getHeight())
            ccdImage.set(0)
            ccdImage.setXY0(bbox.getLLC())

        for a in aList:
            filename = os.path.join(
                dir, "IPSD", "output", "sci", "%s-e%d" % (basename, e),
                "%s-e%d-c%03d-a%02d.sci" % (basename, e, c, a))
            if verbose and what == "header":
                print(filename)

            if what == "header":
                md = afwImage.readMetadata(filename + "_img.fits")
                xy0 = afwGeom.Point2I(md.get("CRVAL1A"), md.get("CRVAL2A"))
                xy1 = xy0 + afwGeom.Extent2I(
                    md.get("NAXIS1") - 1,
                    md.get("NAXIS2") - 1)
                bbox.grow(xy0)
                bbox.grow(xy1)

                ampBBox[a] = afwGeom.Box2I(xy0, xy1)
                wcs[a] = afwImage.Wcs(md)
            else:
                try:
                    data = imageFactory(filename + "_img.fits")
                except:
                    data = imageFactory(filename)

                ampImage = ccdImage.Factory(ccdImage, ampBBox[a])
                ampImage[:] = data
                del ampImage

    try:
        ccdImage.getMask()
        if 0 in wcs:
            ccdImage = afwImage.ExposureF(ccdImage, wcs[0])
    except AttributeError:
        pass

    return ccdImage
    def testPeakLikelihoodFlux(self):
        """Test measurement with PeakLikelihoodFlux
        """
        # make mp: a flux measurer
        measControl = measAlg.PeakLikelihoodFluxControl()
        schema = afwTable.SourceTable.makeMinimalSchema()
        mp = measAlg.MeasureSourcesBuilder().addAlgorithm(measControl).build(
            schema)

        # make and measure a series of exposures containing just one star, approximately centered
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 101))
        kernelWidth = 35
        var = 100
        fwhm = 3.0
        sigma = fwhm / FwhmPerSigma
        convolutionControl = afwMath.ConvolutionControl()
        psf = measAlg.SingleGaussianPsf(kernelWidth, kernelWidth, sigma)
        psfKernel = psf.getLocalKernel()
        psfImage = psf.computeKernelImage()
        sumPsfSq = numpy.sum(psfImage.getArray()**2)
        psfSqArr = psfImage.getArray()**2
        for flux in (1000, 10000):
            ctrInd = afwGeom.Point2I(50, 51)
            ctrPos = afwGeom.Point2D(ctrInd)

            kernelBBox = psfImage.getBBox(afwImage.PARENT)
            kernelBBox.shift(afwGeom.Extent2I(ctrInd))

            # compute predicted flux error
            unshMImage = makeFakeImage(bbox, [ctrPos], [flux], fwhm, var)

            # filter image by PSF
            unshFiltMImage = afwImage.MaskedImageF(
                unshMImage.getBBox(afwImage.PARENT))
            afwMath.convolve(unshFiltMImage, unshMImage, psfKernel,
                             convolutionControl)

            # compute predicted flux = value of image at peak / sum(PSF^2)
            # this is a sanity check of the algorithm, as much as anything
            predFlux = unshFiltMImage.getImage().get(ctrInd[0],
                                                     ctrInd[1]) / sumPsfSq
            self.assertLess(abs(flux - predFlux), flux * 0.01)

            # compute predicted flux error based on filtered pixels
            # = sqrt(value of filtered variance at peak / sum(PSF^2)^2)
            predFluxErr = math.sqrt(unshFiltMImage.getVariance().get(
                ctrInd[0], ctrInd[1])) / sumPsfSq

            # compute predicted flux error based on unfiltered pixels
            # = sqrt(sum(unfiltered variance * PSF^2)) / sum(PSF^2)
            # and compare to that derived from filtered pixels;
            # again, this is a test of the algorithm
            varView = afwImage.ImageF(unshMImage.getVariance(), kernelBBox)
            varArr = varView.getArray()
            unfiltPredFluxErr = math.sqrt(numpy.sum(
                varArr * psfSqArr)) / sumPsfSq
            self.assertLess(abs(unfiltPredFluxErr - predFluxErr),
                            predFluxErr * 0.01)

            for fracOffset in (afwGeom.Extent2D(0, 0),
                               afwGeom.Extent2D(0.2, -0.3)):
                adjCenter = ctrPos + fracOffset
                if fracOffset == (0, 0):
                    maskedImage = unshMImage
                    filteredImage = unshFiltMImage
                else:
                    maskedImage = makeFakeImage(bbox, [adjCenter], [flux],
                                                fwhm, var)
                    # filter image by PSF
                    filteredImage = afwImage.MaskedImageF(
                        maskedImage.getBBox(afwImage.PARENT))
                    afwMath.convolve(filteredImage, maskedImage, psfKernel,
                                     convolutionControl)

                exposure = afwImage.makeExposure(filteredImage)
                exposure.setPsf(psf)

                table = afwTable.SourceTable.make(schema)
                source = table.makeRecord()
                mp.apply(source, exposure, afwGeom.Point2D(*adjCenter))
                measFlux = source.get(measControl.name)
                measFluxErr = source.get(measControl.name + ".err")
                self.assertFalse(source.get(measControl.name + ".flags"))
                self.assertLess(abs(measFlux - flux), flux * 0.003)

                self.assertLess(abs(measFluxErr - predFluxErr),
                                predFluxErr * 0.2)

                # try nearby points and verify that the flux is smaller;
                # this checks that the sub-pixel shift is performed in the correct direction
                for dx in (-0.2, 0, 0.2):
                    for dy in (-0.2, 0, 0.2):
                        if dx == dy == 0:
                            continue
                        offsetCtr = afwGeom.Point2D(adjCenter[0] + dx,
                                                    adjCenter[1] + dy)
                        table = afwTable.SourceTable.make(schema)
                        source = table.makeRecord()
                        mp.apply(source, exposure, offsetCtr)
                        offsetFlux = source.get(measControl.name)
                        self.assertLess(offsetFlux, measFlux)

        # source so near edge of image that PSF does not overlap exposure should result in failure

        for edgePos in (
            (1, 50),
            (50, 1),
            (50, bbox.getHeight() - 1),
            (bbox.getWidth() - 1, 50),
        ):
            table = afwTable.SourceTable.make(schema)
            source = table.makeRecord()
            mp.apply(source, exposure, afwGeom.Point2D(*edgePos))
            self.assertTrue(source.get(measControl.name + ".flags"))

        # no PSF should result in failure: flags set
        noPsfExposure = afwImage.ExposureF(filteredImage)
        table = afwTable.SourceTable.make(schema)
        source = table.makeRecord()
        mp.apply(source, noPsfExposure, afwGeom.Point2D(*adjCenter))
        self.assertTrue(source.get(measControl.name + ".flags"))
Beispiel #3
0
    def _makeAmpInfoCatalog(self):
        """Construct an amplifier info catalog
        """

        extended = 1024  # extended register
        x_overscan = 40  # number of overscan pixel in x
        saturation = 65535
        # Linearity correction is still under discussion, so this is a placeholder.
        linearityType = "PROPORTIONAL"
        linearityThreshold = 0
        linearityMax = saturation
        linearityCoeffs = [linearityThreshold, linearityMax]
        schema = AmpInfoTable.makeMinimalSchema()
        linThreshKey = schema.addField('linearityThreshold', type=float)
        linMaxKey = schema.addField('linearityMaximum', type=float)
        linUnitsKey = schema.addField('linearityUnits', type=str, size=9)
        # end placeholder
        self.ampInfoDict = {}
        ampCatalog = AmpInfoCatalog(schema)

        for ampY in range(1, 3):
            for ampX in range(1, 3):
                record = ampCatalog.addNew()
                record.setName("%d%d" % (ampX, ampY))
                print('Amp Name : %s, %s' % (ampX, ampY))

                if ((ampX == 1) & (ampY == 1)):
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(0, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawHorizontalOverscanBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1044, 0),
                            afwGeom.Extent2I(x_overscan, extended),
                        ))
                    record.setRawXYOffset(\
                        afwGeom.Extent2I(1084, 1024))
                    # bias region
                    record.setRawBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(10, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawDataBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(10, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))

                if ((ampX == 1) & (ampY == 2)):
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1024, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawHorizontalOverscanBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1084, 0),
                            afwGeom.Extent2I(x_overscan, extended),
                        ))
                    record.setRawXYOffset(\
                        afwGeom.Extent2I(1084, 1024))
                    # bias region
                    record.setRawBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1134, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawDataBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1134, 0),
                            afwGeom.Extent2I(extended, extended),
                        ))

                if ((ampX == 2) & (ampY == 1)):
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(0, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawHorizontalOverscanBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1044, 1024),
                            afwGeom.Extent2I(x_overscan, extended),
                        ))
                    record.setRawXYOffset(\
                        afwGeom.Extent2I(1084, 1024))
                    # bias region
                    record.setRawBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(10, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawDataBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(10, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))

                if ((ampX == 2) & (ampY == 2)):
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1024, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawHorizontalOverscanBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1084, 1024),
                            afwGeom.Extent2I(x_overscan, extended),
                        ))
                    record.setRawXYOffset(\
                        afwGeom.Extent2I(1084, 1024))
                    # bias region
                    record.setRawBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1134, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))
                    record.setRawDataBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(1134, 1024),
                            afwGeom.Extent2I(extended, extended),
                        ))

                readCorner = LL  # in raw frames; always LL because raws are in amp coords

                record.setReadoutCorner(readCorner)
                record.setGain(self.gain[(ampX, ampY)])
                record.setReadNoise(self.readNoise[(ampX, ampY)])
                record.setSaturation(saturation)
                record.setHasRawInfo(True)
                record.setRawPrescanBBox(afwGeom.Box2I())
                # linearity placeholder stuff
                record.setLinearityCoeffs(
                    [float(val) for val in linearityCoeffs])
                record.setLinearityType(linearityType)
                record.set(linThreshKey, float(linearityThreshold))
                record.set(linMaxKey, float(linearityMax))
                record.set(linUnitsKey, "DN")
        return ampCatalog
def makeAmpTables(segmentsFile):
    """
    Read the segments file from a PhoSim release and produce the appropriate AmpInfo
    @param segmentsFile -- String indicating where the file is located
    """
    returnDict = {}
    readoutMap = {
        'LL': afwTable.LL,
        'LR': afwTable.LR,
        'UR': afwTable.UR,
        'UL': afwTable.UL
    }
    detectorName = [
    ]  # set to a value that is an invalid dict key, to catch bugs
    with open(segmentsFile) as fh:
        fh.readline()
        for l in fh:
            els = l.rstrip().split()
            detectorName = els[1]
            #skip focus and guiding for now:
            if detectorName[0] in ('F', 'G'):
                continue
            if detectorName not in returnDict:
                schema = afwTable.AmpInfoTable.makeMinimalSchema()
                returnDict[detectorName] = afwTable.AmpInfoCatalog(schema)
            record = returnDict[detectorName].addNew()
            name = els[2]
            gain = float(els[7])
            saturation = int(els[8])
            readnoise = float(els[9])
            xoff = int(els[5])
            yoff = int(els[6])
            ndatax = int(els[3])
            ndatay = int(els[4])

            flipx = False
            flipy = False

            if detectorName.startswith("S") and name == "A":
                readCorner = readoutMap['UR']
            elif detectorName.startswith("S") and name == "B":
                readCorner = readoutMap['UL']
            elif detectorName.startswith("N") and name == "A":
                readCorner = readoutMap['LL']
            elif detectorName.startswith("N") and name == "B":
                readCorner = readoutMap['LR']
            else:
                raise RuntimeError(
                    "Did not recognize detector name or amp name")

            prescan = 6
            hoverscan = 50
            voverscan = 50
            rawBBox = afwGeom.Box2I(
                afwGeom.Point2I(xoff, yoff),
                afwGeom.Extent2I(ndatax + prescan + hoverscan,
                                 ndatay + voverscan))
            # Note: I'm not particularry happy with how the data origin is derived (it neglects [xy]off),
            # but I don't see a better way.
            if readCorner is afwTable.LL:
                originRawData = afwGeom.Point2I(xoff + prescan + hoverscan,
                                                yoff)
                originData = afwGeom.Point2I(0, 0)
                originHOverscan = afwGeom.Point2I(xoff + prescan, yoff)
                originVOverscan = afwGeom.Point2I(xoff + prescan + hoverscan,
                                                  yoff + ndatay)
                originPrescan = afwGeom.Point2I(xoff, yoff)
            elif readCorner is afwTable.LR:
                originRawData = afwGeom.Point2I(xoff, yoff)
                originData = afwGeom.Point2I(ndatax, 0)
                originHOverscan = afwGeom.Point2I(xoff + ndatax, yoff)
                originVOverscan = afwGeom.Point2I(xoff, yoff + ndatay)
                originPrescan = afwGeom.Point2I(xoff + ndatax + hoverscan,
                                                yoff)
            elif readCorner is afwTable.UL:
                originRawData = afwGeom.Point2I(xoff + prescan + hoverscan,
                                                yoff + voverscan)
                originData = afwGeom.Point2I(0, 0)
                originHOverscan = afwGeom.Point2I(xoff + prescan,
                                                  yoff + voverscan)
                originVOverscan = afwGeom.Point2I(xoff + prescan + hoverscan,
                                                  yoff)
                originPrescan = afwGeom.Point2I(xoff, yoff + voverscan)
            elif readCorner is afwTable.UR:
                originRawData = afwGeom.Point2I(xoff, yoff + voverscan)
                originData = afwGeom.Point2I(ndatax, 0)
                originHOverscan = afwGeom.Point2I(xoff + ndatax,
                                                  yoff + voverscan)
                originVOverscan = afwGeom.Point2I(xoff, yoff)
                originPrescan = afwGeom.Point2I(xoff + ndatax + hoverscan,
                                                yoff + voverscan)
            else:
                raise RuntimeError(
                    "Expected readout corner to be LL, LR, UL, or UR")

            rawDataBBox = afwGeom.Box2I(originRawData,
                                        afwGeom.Extent2I(ndatax, ndatay))
            dataBBox = afwGeom.Box2I(originData,
                                     afwGeom.Extent2I(ndatax, ndatay))
            rawHorizontalOverscanBBox = afwGeom.Box2I(
                originHOverscan, afwGeom.Extent2I(hoverscan, ndatay))
            rawVerticalOverscanBBox = afwGeom.Box2I(
                originVOverscan, afwGeom.Extent2I(ndatax, voverscan))
            rawPrescanBBox = afwGeom.Box2I(originPrescan,
                                           afwGeom.Extent2I(prescan, ndatay))

            print "\nDetector=%s; Amp=%s" % (detectorName, name)
            print rawHorizontalOverscanBBox
            print rawVerticalOverscanBBox
            print dataBBox
            print rawBBox
            #Set the elements of the record for this amp
            record.setBBox(
                dataBBox)  # This is the box for the amp in the assembled frame
            record.setName(name)
            record.setReadoutCorner(readCorner)
            record.setGain(gain)
            record.setSaturation(saturation)
            record.setSuspectLevel(float("nan"))
            record.setReadNoise(readnoise)
            ampIndex = dict(A=0, B=1)[name]
            record.setLinearityCoeffs([ampIndex, 0, 0, 0])
            record.setLinearityType(LinearizeLookupTable.LinearityType)
            print "Linearity type=%r; coeffs=%s" % (
                record.getLinearityType(), record.getLinearityCoeffs())
            record.setHasRawInfo(True)
            record.setRawFlipX(flipx)
            record.setRawFlipY(flipy)
            record.setRawBBox(rawBBox)
            # I believe that xy offset is not needed if the raw data are pre-assembled
            record.setRawXYOffset(afwGeom.Extent2I(0, 0))
            """
            if readCorner is afwTable.LL:
                record.setRawXYOffset(afwGeom.Extent2I(xoff + prescan + hoverscan, yoff))
            elif readCorner is afwTable.LR:
                record.setRawXYOffset(afwGeom.Extent2I(xoff, yoff))
            elif readCorner is afwTable.UL:
                record.setRawXYOffset(afwGeom.Extent2I(xoff + prescan + hoverscan, yoff + voverscan))
            elif readCorner is afwTable.UR:
                record.setRawXYOffset(afwGeom.Extent2I(xoff, yoff + voverscan))
            """
            record.setRawDataBBox(rawDataBBox)
            record.setRawHorizontalOverscanBBox(rawHorizontalOverscanBBox)
            record.setRawVerticalOverscanBBox(rawVerticalOverscanBBox)
            # I think of prescan as being along the bottom of the raw data.  I actually
            # don't know how you would do a prescan in the serial direction.
            record.setRawPrescanBBox(afwGeom.Box2I())
    return returnDict
Beispiel #5
0
    def _makeModel(self, exposure, psf, fp, negCenter, posCenter):

        negPsf = psf.computeImage(negCenter).convertF()
        posPsf = psf.computeImage(posCenter).convertF()
        negPeak = psf.computePeak(negCenter)
        posPeak = psf.computePeak(posCenter)
        negPsf /= negPeak
        posPsf /= posPeak

        model = afwImage.ImageF(fp.getBBox())
        negModel = afwImage.ImageF(fp.getBBox())
        posModel = afwImage.ImageF(fp.getBBox())

        # The center of the Psf should be at negCenter, posCenter
        negPsfBBox = negPsf.getBBox()
        posPsfBBox = posPsf.getBBox()
        modelBBox = model.getBBox()

        # Portion of the negative Psf that overlaps the montage
        negOverlapBBox = afwGeom.Box2I(negPsfBBox)
        negOverlapBBox.clip(modelBBox)
        self.assertFalse(negOverlapBBox.isEmpty())

        # Portion of the positivePsf that overlaps the montage
        posOverlapBBox = afwGeom.Box2I(posPsfBBox)
        posOverlapBBox.clip(modelBBox)
        self.assertFalse(posOverlapBBox.isEmpty())

        negPsfSubim = type(negPsf)(negPsf, negOverlapBBox)
        modelSubim = type(model)(model, negOverlapBBox)
        negModelSubim = type(negModel)(negModel, negOverlapBBox)
        modelSubim += negPsfSubim  # just for debugging
        negModelSubim += negPsfSubim  # for fitting

        posPsfSubim = type(posPsf)(posPsf, posOverlapBBox)
        modelSubim = type(model)(model, posOverlapBBox)
        posModelSubim = type(posModel)(posModel, posOverlapBBox)
        modelSubim += posPsfSubim
        posModelSubim += posPsfSubim

        data = afwImage.ImageF(exposure.getMaskedImage().getImage(), fp.getBBox())
        var = afwImage.ImageF(exposure.getMaskedImage().getVariance(), fp.getBBox())
        matrixNorm = 1. / np.sqrt(np.median(var.getArray()))

        if display:
            ds9.mtv(model, frame=5, title="Unfitted model")
            ds9.mtv(data, frame=6, title="Data")

        posPsfSum = np.sum(posPsf.getArray())
        negPsfSum = np.sum(negPsf.getArray())

        M = np.array((np.ravel(negModel.getArray()), np.ravel(posModel.getArray()))).T.astype(np.float64)
        B = np.array((np.ravel(data.getArray()))).astype(np.float64)
        M *= matrixNorm
        B *= matrixNorm

        # Numpy solution
        fneg0, fpos0 = np.linalg.lstsq(M, B)[0]

        # Afw solution
        lsq = afwMath.LeastSquares.fromDesignMatrix(M, B, afwMath.LeastSquares.DIRECT_SVD)
        fneg, fpos = lsq.getSolution()

        # Should be exaxtly the same as each other
        self.assertAlmostEqual(1e-2*fneg0, 1e-2*fneg)
        self.assertAlmostEqual(1e-2*fpos0, 1e-2*fpos)

        # Recreate model
        fitted = afwImage.ImageF(fp.getBBox())
        negFit = type(negPsf)(negPsf, negOverlapBBox, afwImage.PARENT, True)
        negFit *= float(fneg)
        posFit = type(posPsf)(posPsf, posOverlapBBox, afwImage.PARENT, True)
        posFit *= float(fpos)

        fitSubim = type(fitted)(fitted, negOverlapBBox)
        fitSubim += negFit
        fitSubim = type(fitted)(fitted, posOverlapBBox)
        fitSubim += posFit
        if display:
            ds9.mtv(fitted, frame=7, title="Fitted model")

        fitted -= data

        if display:
            ds9.mtv(fitted, frame=8, title="Residuals")

        fitted *= fitted
        fitted /= var

        if display:
            ds9.mtv(fitted, frame=9, title="Chi2")

        return fneg, negPsfSum, fpos, posPsfSum, fitted
Beispiel #6
0
    def testAssertWcssNearlyEqualOverBBox(self):
        """Test assertWcsNearlyEqualOverBBox and wcsNearlyEqualOverBBox"""
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Extent2I(3001, 3001))
        ctrPix = afwGeom.Point2I(1500, 1500)
        metadata = dafBase.PropertySet()
        metadata.set("RADECSYS", "FK5")
        metadata.set("EQUINOX", 2000.0)
        metadata.set("CTYPE1", "RA---TAN")
        metadata.set("CTYPE2", "DEC--TAN")
        metadata.set("CUNIT1", "deg")
        metadata.set("CUNIT2", "deg")
        metadata.set("CRVAL1", 215.5)
        metadata.set("CRVAL2", 53.0)
        metadata.set("CRPIX1", ctrPix[0] + 1)
        metadata.set("CRPIX2", ctrPix[1] + 1)
        metadata.set("CD1_1", 5.1e-05)
        metadata.set("CD1_2", 0.0)
        metadata.set("CD2_2", -5.1e-05)
        metadata.set("CD2_1", 0.0)
        wcs0 = afwImage.cast_TanWcs(afwImage.makeWcs(metadata))
        metadata.set("CRVAL2", 53.000001)  # tweak CRVAL2 for wcs1
        wcs1 = afwImage.cast_TanWcs(afwImage.makeWcs(metadata))

        self.assertWcsNearlyEqualOverBBox(wcs0,
                                          wcs0,
                                          bbox,
                                          maxDiffSky=1e-7 * afwGeom.arcseconds,
                                          maxDiffPix=1e-7)
        self.assertTrue(
            afwImage.wcsNearlyEqualOverBBox(wcs0,
                                            wcs0,
                                            bbox,
                                            maxDiffSky=1e-7 *
                                            afwGeom.arcseconds,
                                            maxDiffPix=1e-7))

        self.assertWcsNearlyEqualOverBBox(wcs0,
                                          wcs1,
                                          bbox,
                                          maxDiffSky=0.04 * afwGeom.arcseconds,
                                          maxDiffPix=0.02)
        self.assertTrue(
            afwImage.wcsNearlyEqualOverBBox(wcs0,
                                            wcs1,
                                            bbox,
                                            maxDiffSky=0.04 *
                                            afwGeom.arcseconds,
                                            maxDiffPix=0.02))

        with self.assertRaises(AssertionError):
            self.assertWcsNearlyEqualOverBBox(wcs0,
                                              wcs1,
                                              bbox,
                                              maxDiffSky=0.001 *
                                              afwGeom.arcseconds,
                                              maxDiffPix=0.02)
        self.assertFalse(
            afwImage.wcsNearlyEqualOverBBox(wcs0,
                                            wcs1,
                                            bbox,
                                            maxDiffSky=0.001 *
                                            afwGeom.arcseconds,
                                            maxDiffPix=0.02))

        with self.assertRaises(AssertionError):
            self.assertWcsNearlyEqualOverBBox(wcs0,
                                              wcs1,
                                              bbox,
                                              maxDiffSky=0.04 *
                                              afwGeom.arcseconds,
                                              maxDiffPix=0.001)
        self.assertFalse(
            afwImage.wcsNearlyEqualOverBBox(wcs0,
                                            wcs1,
                                            bbox,
                                            maxDiffSky=0.04 *
                                            afwGeom.arcseconds,
                                            maxDiffPix=0.001))

        # check that doShortCircuit works in the private implementation
        errStr1 = _compareWcsOverBBox(wcs0,
                                      wcs1,
                                      bbox,
                                      maxDiffSky=0.001 * afwGeom.arcseconds,
                                      maxDiffPix=0.001,
                                      doShortCircuit=False)
        errStr2 = _compareWcsOverBBox(wcs0,
                                      wcs1,
                                      bbox,
                                      maxDiffSky=0.001 * afwGeom.arcseconds,
                                      maxDiffPix=0.001,
                                      doShortCircuit=True)
        self.assertNotEqual(errStr1, errStr2)
Beispiel #7
0
    def testAssignWithBBox(self):
        """Test assign(rhs, bbox) with non-empty bbox
        """
        for xy0 in (
                afwGeom.Point2I(*val) for val in (
                    (0, 0),
                    (-100, 120),  # an arbitrary value that is off the image
                )):
            destMIDim = afwGeom.Extent2I(5, 4)
            srcMIDim = afwGeom.Extent2I(3, 2)
            destMI = afwImage.MaskedImageF(destMIDim)
            destImage = destMI.getImage()
            destVariance = destMI.getVariance()
            destMask = destMI.getMask()
            destMI.setXY0(xy0)
            srcMI = makeRampImage(*srcMIDim)
            srcMI.setXY0(55, -33)  # an arbitrary value that should be ignored
            self.assertRaises(Exception, destMI.set, srcMI)  # size mismatch

            for validMin in (afwGeom.Point2I(*val) for val in (
                (0, 0),
                (2, 0),
                (0, 1),
                (1, 2),
            )):
                # None to omit the argument
                for origin in (None, afwImage.PARENT, afwImage.LOCAL):
                    destImage[:] = -1.0
                    destVariance[:] = -1.0
                    destMask[:] = 0xFFFF
                    bbox = afwGeom.Box2I(validMin, srcMI.getDimensions())
                    if origin != afwImage.LOCAL:
                        bbox.shift(afwGeom.Extent2I(xy0))
                    if origin is None:
                        destMI.assign(srcMI, bbox)
                        destMIView = afwImage.MaskedImageF(destMI, bbox)
                    else:
                        destMI.assign(srcMI, bbox, origin)
                        destMIView = afwImage.MaskedImageF(
                            destMI, bbox, origin)
                    for i in range(3):
                        self.assertListEqual(
                            destMIView.getArrays()[i].flatten().tolist(),
                            srcMI.getArrays()[i].flatten().tolist())
                    numPixNotAssigned = (destMIDim[0] * destMIDim[1]) - (
                        srcMIDim[0] * srcMIDim[1])
                    self.assertEqual(np.sum(destImage.getArray() < -0.5),
                                     numPixNotAssigned)
                    self.assertEqual(np.sum(destVariance.getArray() < -0.5),
                                     numPixNotAssigned)
                    self.assertEqual(np.sum(destMask.getArray() == 0xFFFF),
                                     numPixNotAssigned)

            for badMin in (afwGeom.Point2I(*val) + afwGeom.Extent2I(xy0)
                           for val in (
                               (-1, 0),
                               (3, 0),
                               (0, -1),
                               (1, 3),
                           )):
                # None to omit the argument
                for origin in (None, afwImage.PARENT, afwImage.LOCAL):
                    bbox = afwGeom.Box2I(validMin, srcMI.getDimensions())
                    if origin != afwImage.LOCAL:
                        bbox.shift(afwGeom.Extent2I(xy0))
                    if origin is None:
                        self.assertRaises(Exception, destMI.set, srcMI, bbox)
                    else:
                        self.assertRaises(Exception, destMI.set, srcMI, bbox,
                                          origin)
Beispiel #8
0
    def testReadWriteFits(self):
        """Test readFits and writeFits.
        """
        # This should pass without an exception
        mainExposure = afwImage.ExposureF(inFilePathSmall)
        mainExposure.setDetector(cameraGeom.Detector(cameraGeom.Id(666)))

        subBBox = afwGeom.Box2I(afwGeom.Point2I(10, 10),
                                afwGeom.Extent2I(40, 50))
        subExposure = mainExposure.Factory(mainExposure, subBBox,
                                           afwImage.LOCAL)
        self.checkWcs(mainExposure, subExposure)
        det = subExposure.getDetector()
        self.assertTrue(det)

        subExposure = afwImage.ExposureF(inFilePathSmall, subBBox)

        self.checkWcs(mainExposure, subExposure)

        # This should throw an exception
        def getExposure():
            afwImage.ExposureF(inFilePathSmallImage)

        utilsTests.assertRaisesLsstCpp(self, lsst.afw.fits.FitsError,
                                       getExposure)

        mainExposure.setPsf(self.psf)

        # Make sure we can write without an exception
        mainExposure.getCalib().setExptime(10)
        mainExposure.getCalib().setMidTime(dafBase.DateTime())
        midMjd = mainExposure.getCalib().getMidTime().get()
        fluxMag0, fluxMag0Err = 1e12, 1e10
        mainExposure.getCalib().setFluxMag0(fluxMag0, fluxMag0Err)

        mainExposure.writeFits(outFile)

        # Check scaling of Calib
        scale = 2.0
        calib = mainExposure.getCalib()
        calib *= scale
        self.assertEqual((fluxMag0 * scale, fluxMag0Err * scale),
                         calib.getFluxMag0())
        calib /= scale
        self.assertEqual((fluxMag0, fluxMag0Err), calib.getFluxMag0())

        readExposure = type(mainExposure)(outFile)

        os.remove(outFile)
        #
        # Check the round-tripping
        #
        self.assertEqual(mainExposure.getFilter().getName(),
                         readExposure.getFilter().getName())

        self.assertEqual(mainExposure.getCalib().getExptime(),
                         readExposure.getCalib().getExptime())
        self.assertEqual(midMjd, readExposure.getCalib().getMidTime().get())
        self.assertEqual((fluxMag0, fluxMag0Err),
                         readExposure.getCalib().getFluxMag0())

        psf = readExposure.getPsf()
        self.assert_(psf is not None)
        dummyPsf = DummyPsf.swigConvert(psf)
        self.assert_(dummyPsf is not None)
        self.assertEqual(dummyPsf.getValue(), self.psf.getValue())
Beispiel #9
0
    def _makeAmpInfoCatalog(self):
        """Construct an amplifier info catalog
        """
        # Much of this will need to be filled in when we know it.
        xDataExtent = 512  # trimmed
        yDataExtent = 2002

        extended = 10  # extended register
        h_overscan = 22  # number of overscan in x
        v_overscan = 46  # number of overscan in y

        xRawExtent = extended + h_overscan + xDataExtent
        yRawExtent = v_overscan + yDataExtent  # no prescan in vertical

        saturation = 65535
        # Linearity correction is still under discussion, so this is a placeholder.
        linearityType = "PROPORTIONAL"
        linearityThreshold = 0
        linearityMax = saturation
        linearityCoeffs = [linearityThreshold, linearityMax]

        schema = AmpInfoTable.makeMinimalSchema()

        linThreshKey = schema.addField('linearityThreshold', type=float)
        linMaxKey = schema.addField('linearityMaximum', type=float)
        linUnitsKey = schema.addField('linearityUnits', type=str, size=9)
        # end placeholder
        self.ampInfoDict = {}
        ampCatalog = AmpInfoCatalog(schema)
        for ampY in (0, 1):
            for ampX in range(8):
                record = ampCatalog.addNew()
                record.setName("%d%d" % (ampX, ampY))

                if bool(ampY):
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I(ampX * xDataExtent,
                                            ampY * yDataExtent),
                            afwGeom.Extent2I(xDataExtent, yDataExtent),
                        ))
                else:
                    record.setBBox(
                        afwGeom.Box2I(
                            afwGeom.Point2I((7 - ampX) * xDataExtent,
                                            ampY * yDataExtent),
                            afwGeom.Extent2I(xDataExtent, yDataExtent),
                        ))

                readCorner = LL  # in raw frames; always LL because raws are in amp coords
                # bias region
                x0Bias = extended + xDataExtent
                y0Data = 0
                x0Data = extended

                record.setRawBBox(
                    afwGeom.Box2I(
                        afwGeom.Point2I(0, 0),
                        afwGeom.Extent2I(xRawExtent, yRawExtent),
                    ))
                record.setRawDataBBox(
                    afwGeom.Box2I(
                        afwGeom.Point2I(x0Data, y0Data),
                        afwGeom.Extent2I(xDataExtent, yDataExtent),
                    ))
                record.setRawHorizontalOverscanBBox(
                    afwGeom.Box2I(
                        afwGeom.Point2I(x0Bias, y0Data),
                        afwGeom.Extent2I(h_overscan, yDataExtent),
                    ))
                record.setRawVerticalOverscanBBox(
                    afwGeom.Box2I(
                        afwGeom.Point2I(x0Data, y0Data + yDataExtent),
                        afwGeom.Extent2I(xDataExtent, v_overscan),
                    ))
                record.setRawXYOffset(
                    afwGeom.Extent2I(ampX * xRawExtent, ampY * yRawExtent))
                record.setReadoutCorner(readCorner)
                record.setGain(self.gain[(ampX, ampY)])
                record.setReadNoise(self.readNoise[(ampX, ampY)])
                record.setSaturation(saturation)
                record.setHasRawInfo(True)
                record.setRawFlipX(bool(ampY))
                # flip data when assembling if in top of chip
                record.setRawFlipY(bool(ampY))
                record.setRawPrescanBBox(afwGeom.Box2I())
                # linearity placeholder stuff
                record.setLinearityCoeffs(
                    [float(val) for val in linearityCoeffs])
                record.setLinearityType(linearityType)
                record.set(linThreshKey, float(linearityThreshold))
                record.set(linMaxKey, float(linearityMax))
                record.set(linUnitsKey, "DN")
        return ampCatalog
def sourceToFootprintList(candidateInList, templateExposure, scienceExposure,
                          kernelSize, config, log):
    """Convert a list of sources for the PSF-matching Kernel to Footprints.

    Parameters
    ----------
    candidateInList : TODO: DM-17458
        Input list of Sources
    templateExposure : TODO: DM-17458
        Template image, to be checked for Mask bits in Source Footprint
    scienceExposure : TODO: DM-17458
        Science image, to be checked for Mask bits in Source Footprint
    kernelSize : TODO: DM-17458
        TODO: DM-17458
    config : TODO: DM-17458
        Config that defines the Mask planes that indicate an invalid Source and Bbox grow radius
    log : TODO: DM-17458
        Log for output

    Returns
    -------
    candidateOutList : `list`
        a list of dicts having a "source" and "footprint" field, to be used for Psf-matching

    Raises
    ------
    RuntimeError
        TODO: DM-17458

    Notes
    -----
    Takes an input list of Sources that were selected to constrain
    the Psf-matching Kernel and turns them into a List of Footprints,
    which are used to seed a set of KernelCandidates.  The function
    checks both the template and science image for masked pixels,
    rejecting the Source if certain Mask bits (defined in config) are
    set within the Footprint.
    """

    candidateOutList = []
    fsb = diffimLib.FindSetBitsU()
    badBitMask = 0
    for mp in config.badMaskPlanes:
        badBitMask |= afwImage.Mask.getPlaneBitMask(mp)
    bbox = scienceExposure.getBBox()

    # Size to grow Sources
    if config.scaleByFwhm:
        fpGrowPix = int(config.fpGrowKernelScaling * kernelSize + 0.5)
    else:
        fpGrowPix = config.fpGrowPix
    log.info("Growing %d kernel candidate stars by %d pixels",
             len(candidateInList), fpGrowPix)

    for kernelCandidate in candidateInList:
        if not type(kernelCandidate) == afwTable.SourceRecord:
            raise RuntimeError("Candiate not of type afwTable.SourceRecord")
        bm1 = 0
        bm2 = 0
        center = afwGeom.Point2I(scienceExposure.getWcs().skyToPixel(
            kernelCandidate.getCoord()))
        if center[0] < bbox.getMinX() or center[0] > bbox.getMaxX():
            continue
        if center[1] < bbox.getMinY() or center[1] > bbox.getMaxY():
            continue

        xmin = center[0] - fpGrowPix
        xmax = center[0] + fpGrowPix
        ymin = center[1] - fpGrowPix
        ymax = center[1] + fpGrowPix

        # Keep object centered
        if (xmin - bbox.getMinX()) < 0:
            xmax += (xmin - bbox.getMinX())
            xmin -= (xmin - bbox.getMinX())
        if (ymin - bbox.getMinY()) < 0:
            ymax += (ymin - bbox.getMinY())
            ymin -= (ymin - bbox.getMinY())
        if (bbox.getMaxX() - xmax) < 0:
            xmin -= (bbox.getMaxX() - xmax)
            xmax += (bbox.getMaxX() - xmax)
        if (bbox.getMaxY() - ymax) < 0:
            ymin -= (bbox.getMaxY() - ymax)
            ymax += (bbox.getMaxY() - ymax)
        if xmin > xmax or ymin > ymax:
            continue

        kbbox = afwGeom.Box2I(afwGeom.Point2I(xmin, ymin),
                              afwGeom.Point2I(xmax, ymax))
        try:
            fsb.apply(
                afwImage.MaskedImageF(templateExposure.getMaskedImage(),
                                      kbbox,
                                      deep=False).getMask())
            bm1 = fsb.getBits()
            fsb.apply(
                afwImage.MaskedImageF(scienceExposure.getMaskedImage(),
                                      kbbox,
                                      deep=False).getMask())
            bm2 = fsb.getBits()
        except Exception:
            pass
        else:
            if not ((bm1 & badBitMask) or (bm2 & badBitMask)):
                candidateOutList.append({
                    'source':
                    kernelCandidate,
                    'footprint':
                    afwDetect.Footprint(afwGeom.SpanSet(kbbox))
                })
    log.info("Selected %d / %d sources for KernelCandidacy",
             len(candidateOutList), len(candidateInList))
    return candidateOutList
Beispiel #11
0
    def testGetSubExposure(self):
        """
        Test that a subExposure of the original Exposure can be obtained.

        The MaskedImage class should throw a
        lsst::pex::exceptions::InvalidParameter if the requested
        subRegion is not fully contained within the original
        MaskedImage.
        
        """
        #
        # This subExposure is valid
        #
        subBBox = afwGeom.Box2I(afwGeom.Point2I(40, 50),
                                afwGeom.Extent2I(10, 10))
        subExposure = self.exposureCrWcs.Factory(self.exposureCrWcs, subBBox,
                                                 afwImage.LOCAL)

        self.checkWcs(self.exposureCrWcs, subExposure)

        # this subRegion is not valid and should trigger an exception
        # from the MaskedImage class and should trigger an exception
        # from the WCS class for the MaskedImage 871034p_1_MI.

        subRegion3 = afwGeom.Box2I(afwGeom.Point2I(100, 100),
                                   afwGeom.Extent2I(10, 10))

        def getSubRegion():
            self.exposureCrWcs.Factory(self.exposureCrWcs, subRegion3,
                                       afwImage.LOCAL)

        utilsTests.assertRaisesLsstCpp(self, pexExcept.LengthErrorException,
                                       getSubRegion)

        # this subRegion is not valid and should trigger an exception
        # from the MaskedImage class only for the MaskedImage small_MI.
        # small_MI (cols, rows) = (256, 256)

        subRegion4 = afwGeom.Box2I(afwGeom.Point2I(250, 250),
                                   afwGeom.Extent2I(10, 10))

        def getSubRegion():
            self.exposureCrWcs.Factory(self.exposureCrWcs, subRegion4,
                                       afwImage.LOCAL)

        utilsTests.assertRaisesLsstCpp(self, pexExcept.LengthErrorException,
                                       getSubRegion)

        #check the sub- and parent- exposures are using the same Wcs transformation
        subBBox = afwGeom.Box2I(afwGeom.Point2I(40, 50),
                                afwGeom.Extent2I(10, 10))
        subExposure = self.exposureCrWcs.Factory(self.exposureCrWcs, subBBox,
                                                 afwImage.LOCAL)
        parentPos = self.exposureCrWcs.getWcs().pixelToSky(0, 0)

        parentPos = parentPos.getPosition()

        subExpPos = subExposure.getWcs().pixelToSky(0, 0).getPosition()

        for i in range(2):
            self.assertAlmostEqual(parentPos[i], subExpPos[i], 9,
                                   "Wcs in sub image has changed")
def makeFakeKernelSet(sizeCell=128,
                      nCell=3,
                      deltaFunctionCounts=1.e4,
                      tGaussianWidth=1.0,
                      addNoise=True,
                      bgValue=100.,
                      display=False):
    """Generate test template and science images with sources.

    Parameters
    ----------
    sizeCell : `int`, optional
        Size of the square spatial cells in pixels.
    nCell : `int`, optional
        Number of adjacent spatial cells in both direction in both images.
    deltaFunctionCounts : `float`, optional
        Flux value for the template image sources.
    tGaussianWidth : `float`, optional
        Sigma of the generated Gaussian PSF sources in the template image.
    addNoise : `bool`, optional
        If `True`, Poisson noise is added to both the generated template
        and science images.
    bgValue : `float`, optional
        Background level to be added to the generated science image.
    display : `bool`, optional
        If `True` displays the generated template and science images by
        `lsst.afw.display.Display`.

    Notes
    -----
    - The generated images consist of adjacent ``nCell x nCell`` cells, each
      of pixel size ``sizeCell x sizeCell``.
    - The sources in the science image are generated by convolving the
      template by ``sKernel``. ``sKernel`` is a spatial `LinearCombinationKernel`
      of hard wired kernel bases functions. The linear combination has first
      order polynomial spatial dependence with polynomial parameters from ``fakeCoeffs()``.
    - The template image sources are generated in the center of each spatial
      cell from one pixel, set to `deltaFunctionCounts` counts, then convolved
      by a 2D Gaussian with sigma of `tGaussianWidth` along each axis.
    - The sources are also returned in ``kernelCellSet`` each source is "detected"
      exactly at the center of a cell.

    Returns
    -------
    tMi : `lsst.afw.image.MaskedImage`
        Generated template image.
    sMi : `lsst.afw.image.MaskedImage`
        Generated science image.
    sKernel : `lsst.afw.math.LinearCombinationKernel`
        The spatial kernel used to generate the sources in the science image.
    kernelCellSet : `lsst.afw.math.SpatialCellSet`
        Cell grid of `lsst.afw.math.SpatialCell` instances, containing
        `lsst.ip.diffim.KernelCandidate` instances around all the generated sources
        in the science image.
    configFake : `lsst.ip.diffim.ImagePsfMatchConfig`
        Config instance used in the image generation.
    """
    from . import imagePsfMatch
    configFake = imagePsfMatch.ImagePsfMatchConfig()
    configFake.kernel.name = "AL"
    subconfigFake = configFake.kernel.active
    subconfigFake.alardNGauss = 1
    subconfigFake.alardSigGauss = [
        2.5,
    ]
    subconfigFake.alardDegGauss = [
        2,
    ]
    subconfigFake.sizeCellX = sizeCell
    subconfigFake.sizeCellY = sizeCell
    subconfigFake.spatialKernelOrder = 1
    subconfigFake.spatialModelType = "polynomial"
    subconfigFake.singleKernelClipping = False  # variance is a hack
    subconfigFake.spatialKernelClipping = False  # variance is a hack
    if bgValue > 0.0:
        subconfigFake.fitForBackground = True

    policyFake = pexConfig.makePolicy(subconfigFake)

    basisList = makeKernelBasisList(subconfigFake)
    kSize = subconfigFake.kernelSize

    # This sets the final extent of each convolved delta function
    gaussKernelWidth = sizeCell // 2

    # This sets the scale over which pixels are correlated in the
    # spatial convolution; should be at least as big as the kernel you
    # are trying to fit for
    spatialKernelWidth = kSize

    # Number of bad pixels due to convolutions
    border = (gaussKernelWidth + spatialKernelWidth) // 2

    # Make a fake image with a matrix of delta functions
    totalSize = nCell * sizeCell + 2 * border
    tim = afwImage.ImageF(afwGeom.Extent2I(totalSize, totalSize))
    for x in range(nCell):
        for y in range(nCell):
            tim[x * sizeCell + sizeCell // 2 + border - 1,
                y * sizeCell + sizeCell // 2 + border - 1,
                afwImage.LOCAL] = deltaFunctionCounts

    # Turn this into stars with a narrow width; conserve counts
    gaussFunction = afwMath.GaussianFunction2D(tGaussianWidth, tGaussianWidth)
    gaussKernel = afwMath.AnalyticKernel(gaussKernelWidth, gaussKernelWidth,
                                         gaussFunction)
    cim = afwImage.ImageF(tim.getDimensions())
    afwMath.convolve(cim, tim, gaussKernel, True)
    tim = cim

    # Trim off border pixels
    bbox = gaussKernel.shrinkBBox(tim.getBBox(afwImage.LOCAL))
    tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)

    # Now make a science image which is this convolved with some
    # spatial function.  Use input basis list.
    polyFunc = afwMath.PolynomialFunction2D(1)
    kCoeffs = fakeCoeffs()
    nToUse = min(len(kCoeffs), len(basisList))

    # Make the full convolved science image
    sKernel = afwMath.LinearCombinationKernel(basisList[:nToUse], polyFunc)
    sKernel.setSpatialParameters(kCoeffs[:nToUse])
    sim = afwImage.ImageF(tim.getDimensions())
    afwMath.convolve(sim, tim, sKernel, True)

    # Get the good subregion
    bbox = sKernel.shrinkBBox(sim.getBBox(afwImage.LOCAL))

    # Add background
    sim += bgValue

    # Watch out for negative values
    tim += 2 * np.abs(np.min(tim.getArray()))

    # Add noise?
    if addNoise:
        sim = makePoissonNoiseImage(sim)
        tim = makePoissonNoiseImage(tim)

    # And turn into MaskedImages
    sim = afwImage.ImageF(sim, bbox, afwImage.LOCAL)
    svar = afwImage.ImageF(sim, True)
    smask = afwImage.Mask(sim.getDimensions())
    smask.set(0x0)
    sMi = afwImage.MaskedImageF(sim, smask, svar)

    tim = afwImage.ImageF(tim, bbox, afwImage.LOCAL)
    tvar = afwImage.ImageF(tim, True)
    tmask = afwImage.Mask(tim.getDimensions())
    tmask.set(0x0)
    tMi = afwImage.MaskedImageF(tim, tmask, tvar)

    if display:
        import lsst.afw.display as afwDisplay
        afwDisplay.Display(frame=1).mtv(tMi)
        afwDisplay.Display(frame=2).mtv(sMi)

    # Finally, make a kernelSet from these 2 images
    kernelCellSet = afwMath.SpatialCellSet(
        afwGeom.Box2I(afwGeom.Point2I(0, 0),
                      afwGeom.Extent2I(sizeCell * nCell, sizeCell * nCell)),
        sizeCell, sizeCell)
    stampHalfWidth = 2 * kSize
    for x in range(nCell):
        for y in range(nCell):
            xCoord = x * sizeCell + sizeCell // 2
            yCoord = y * sizeCell + sizeCell // 2
            p0 = afwGeom.Point2I(xCoord - stampHalfWidth,
                                 yCoord - stampHalfWidth)
            p1 = afwGeom.Point2I(xCoord + stampHalfWidth,
                                 yCoord + stampHalfWidth)
            bbox = afwGeom.Box2I(p0, p1)
            tsi = afwImage.MaskedImageF(tMi, bbox, origin=afwImage.LOCAL)
            ssi = afwImage.MaskedImageF(sMi, bbox, origin=afwImage.LOCAL)

            kc = diffimLib.makeKernelCandidate(xCoord, yCoord, tsi, ssi,
                                               policyFake)
            kernelCellSet.insertCandidate(kc)

    tMi.setXY0(0, 0)
    sMi.setXY0(0, 0)
    return tMi, sMi, sKernel, kernelCellSet, configFake
Beispiel #13
0
def plantSources(x0, y0, nx, ny, sky, nObj, wid, detector, useRandom=False):

    pixToTanPix = detector.getTransform(cameraGeom.PIXELS,
                                        cameraGeom.TAN_PIXELS)

    img0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    img = afwImage.ImageF(afwGeom.ExtentI(nx, ny))

    ixx0, iyy0, ixy0 = wid * wid, wid * wid, 0.0

    edgeBuffer = 40.0 * wid

    flux = 1.0e4
    nkx, nky = int(10 * wid) + 1, int(10 * wid) + 1
    xhwid, yhwid = nkx // 2, nky // 2

    nRow = int(math.sqrt(nObj))
    xstep = (nx - 1 - 0.0 * edgeBuffer) // (nRow + 1)
    ystep = (ny - 1 - 0.0 * edgeBuffer) // (nRow + 1)

    if useRandom:
        nObj = nRow * nRow

    goodAdded0 = []
    goodAdded = []

    for i in range(nObj):

        # get our position
        if useRandom:
            xcen0, ycen0 = np.random.uniform(nx), np.random.uniform(ny)
        else:
            xcen0, ycen0 = xstep * (
                (i % nRow) + 1), ystep * (int(i / nRow) + 1)
        ixcen0, iycen0 = int(xcen0), int(ycen0)

        # distort position and shape
        pTan = afwGeom.Point2D(xcen0, ycen0)
        p = pixToTanPix.applyInverse(pTan)
        linTransform = afwGeom.linearizeTransform(pixToTanPix,
                                                  p).invert().getLinear()
        m = afwGeom.Quadrupole(ixx0, iyy0, ixy0)
        m.transform(linTransform)

        xcen, ycen = xcen0, ycen0  # p.getX(), p.getY()
        if (xcen < 1.0 * edgeBuffer or (nx - xcen) < 1.0 * edgeBuffer
                or ycen < 1.0 * edgeBuffer or (ny - ycen) < 1.0 * edgeBuffer):
            continue
        ixcen, iycen = int(xcen), int(ycen)
        ixx, iyy, ixy = m.getIxx(), m.getIyy(), m.getIxy()

        # plant the object
        tmp = 0.25 * (ixx - iyy)**2 + ixy**2
        a2 = 0.5 * (ixx + iyy) + np.sqrt(tmp)
        b2 = 0.5 * (ixx + iyy) - np.sqrt(tmp)

        theta = 0.5 * np.arctan2(2.0 * ixy, ixx - iyy)
        a = np.sqrt(a2)
        b = np.sqrt(b2)

        c, s = math.cos(theta), math.sin(theta)
        good0, good = True, True
        for y in range(nky):
            iy = iycen + y - yhwid
            iy0 = iycen0 + y - yhwid

            for x in range(nkx):
                ix = ixcen + x - xhwid
                ix0 = ixcen0 + x - xhwid

                if ix >= 0 and ix < nx and iy >= 0 and iy < ny:
                    dx, dy = ix - xcen, iy - ycen
                    u = c * dx + s * dy
                    v = -s * dx + c * dy
                    I0 = flux / (2 * math.pi * a * b)
                    val = I0 * math.exp(-0.5 * ((u / a)**2 + (v / b)**2))
                    if val < 0:
                        val = 0
                    prevVal = img.get(ix, iy)
                    img.set(ix, iy, val + prevVal)
                else:
                    good = False

                if ix0 >= 0 and ix0 < nx and iy0 >= 0 and iy0 < ny:
                    dx, dy = ix - xcen, iy - ycen
                    I0 = flux / (2 * math.pi * wid * wid)
                    val = I0 * math.exp(-0.5 * ((dx / wid)**2 + (dy / wid)**2))
                    if val < 0:
                        val = 0
                    prevVal = img0.get(ix0, iy0)
                    img0.set(ix0, iy0, val + prevVal)
                else:
                    good0 = False

        if good0:
            goodAdded0.append([xcen, ycen])
        if good:
            goodAdded.append([xcen, ycen])

    # add sky and noise
    img += sky
    img0 += sky
    noise = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    noise0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny))
    for i in range(nx):
        for j in range(ny):
            noise.set(i, j, np.random.poisson(img.get(i, j)))
            noise0.set(i, j, np.random.poisson(img0.get(i, j)))

    edgeWidth = int(0.5 * edgeBuffer)
    mask = afwImage.Mask(afwGeom.ExtentI(nx, ny))
    left = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.ExtentI(edgeWidth, ny))
    right = afwGeom.Box2I(afwGeom.Point2I(nx - edgeWidth, 0),
                          afwGeom.ExtentI(edgeWidth, ny))
    top = afwGeom.Box2I(afwGeom.Point2I(0, ny - edgeWidth),
                        afwGeom.ExtentI(nx, edgeWidth))
    bottom = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                           afwGeom.ExtentI(nx, edgeWidth))

    for pos in [left, right, top, bottom]:
        msk = afwImage.Mask(mask, pos, deep=False)
        msk.set(msk.getPlaneBitMask('EDGE'))

    expos = afwImage.makeExposure(
        afwImage.makeMaskedImage(noise, mask, afwImage.ImageF(noise, True)))
    expos0 = afwImage.makeExposure(
        afwImage.makeMaskedImage(noise0, mask, afwImage.ImageF(noise0, True)))

    im = expos.getMaskedImage().getImage()
    im0 = expos0.getMaskedImage().getImage()
    im -= sky
    im0 -= sky

    return expos, goodAdded, expos0, goodAdded0
Beispiel #14
0
    def setUp(self):
        np.random.seed(500)  # make test repeatable
        self.x0, self.y0 = 0, 0
        self.nx, self.ny = 512, 512  # 2048, 4096
        self.sky = 100.0
        self.nObj = 100

        # make a detector with distortion
        self.detector = DetectorWrapper(
            bbox=afwGeom.Box2I(afwGeom.Point2I(0, 0),
                               afwGeom.Extent2I(self.nx, self.ny)),
            orientation=cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)),
            radialDistortion=0.925,
        ).detector

        # make a detector with no distortion
        self.flatDetector = DetectorWrapper(
            bbox=afwGeom.Box2I(afwGeom.Point2I(0, 0),
                               afwGeom.Extent2I(self.nx, self.ny)),
            orientation=cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)),
            radialDistortion=0.0,
        ).detector

        # detection policies
        detConfig = measAlg.SourceDetectionConfig()
        # Cannot use default background approximation order (6) for such a small image.
        detConfig.background.approxOrderX = 4

        # measurement policies
        measConfig = measBase.SingleFrameMeasurementConfig()
        measConfig.algorithms.names = [
            "base_SdssCentroid",
            "base_SdssShape",
            "base_GaussianFlux",
            "base_PsfFlux",
        ]
        measConfig.slots.centroid = "base_SdssCentroid"
        measConfig.slots.shape = "base_SdssShape"
        measConfig.slots.psfFlux = "base_PsfFlux"
        measConfig.plugins["base_SdssCentroid"].doFootprintCheck = False
        measConfig.slots.apFlux = None
        measConfig.slots.modelFlux = None
        measConfig.slots.instFlux = None
        measConfig.slots.calibFlux = None

        self.schema = afwTable.SourceTable.makeMinimalSchema()
        detConfig.validate()
        measConfig.validate()
        self.detTask = measAlg.SourceDetectionTask(config=detConfig,
                                                   schema=self.schema)
        self.measTask = measBase.SingleFrameMeasurementTask(config=measConfig,
                                                            schema=self.schema)

        # psf star selector
        starSelectorClass = measAlg.sourceSelectorRegistry["objectSize"]
        starSelectorConfig = starSelectorClass.ConfigClass()
        starSelectorConfig.fluxMin = 5000.0
        starSelectorConfig.badFlags = []
        self.starSelector = starSelectorClass(config=starSelectorConfig)

        self.makePsfCandidates = measAlg.MakePsfCandidatesTask()

        # psf determiner
        psfDeterminerFactory = measAlg.psfDeterminerRegistry["pca"]
        psfDeterminerConfig = psfDeterminerFactory.ConfigClass()
        width, height = self.nx, self.ny
        nEigenComponents = 3
        psfDeterminerConfig.sizeCellX = width // 3
        psfDeterminerConfig.sizeCellY = height // 3
        psfDeterminerConfig.nEigenComponents = nEigenComponents
        psfDeterminerConfig.spatialOrder = 1
        psfDeterminerConfig.kernelSizeMin = 31
        psfDeterminerConfig.nStarPerCell = 0
        psfDeterminerConfig.nStarPerCellSpatialFit = 0  # unlimited
        self.psfDeterminer = psfDeterminerFactory(psfDeterminerConfig)
Beispiel #15
0
 def getBBox(self):
     """Get bounding box of tract (as an afwGeom.Box2I)
     """
     return afwGeom.Box2I(self._bbox)
Beispiel #16
0
    def testPeakRemoval(self):
        '''
        A simple example: three overlapping blobs (detected as 1
        footprint with three peaks).  Additional peaks are added near
        the blob peaks that should be identified as degenerate.
        '''
        H, W = 100, 100

        fpbb = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Point2I(W - 1, H - 1))

        afwimg = afwImage.MaskedImageF(fpbb)
        imgbb = afwimg.getBBox()
        img = afwimg.getImage().getArray()

        var = afwimg.getVariance().getArray()
        var[:, :] = 1.

        blob_fwhm = 10.
        blob_psf = doubleGaussianPsf(99, 99, blob_fwhm, 2. * blob_fwhm, 0.03)

        fakepsf_fwhm = 3.
        fakepsf = gaussianPsf(11, 11, fakepsf_fwhm)

        blobimgs = []
        x = 75.
        XY = [(x, 35.), (x, 65.), (50., 50.)]
        flux = 1e6
        for x, y in XY:
            bim = blob_psf.computeImage(afwGeom.Point2D(x, y))
            bbb = bim.getBBox()
            bbb.clip(imgbb)

            bim = bim.Factory(bim, bbb)
            bim2 = bim.getArray()

            blobimg = np.zeros_like(img)
            blobimg[bbb.getMinY():bbb.getMaxY() + 1,
                    bbb.getMinX():bbb.getMaxX() + 1] += flux * bim2
            blobimgs.append(blobimg)

            img[bbb.getMinY():bbb.getMaxY() + 1,
                bbb.getMinX():bbb.getMaxX() + 1] += flux * bim2

        # Run the detection code to get a ~ realistic footprint
        thresh = afwDet.createThreshold(5., 'value', True)
        fpSet = afwDet.FootprintSet(afwimg, thresh, 'DETECTED', 1)
        fps = fpSet.getFootprints()

        self.assertTrue(len(fps) == 1)

        # Add new peaks near to the first peaks that will be degenerate
        fp0 = fps[0]
        for x, y in XY:
            fp0.addPeak(x - 10, y + 6, 10)

        deb = deblend(fp0,
                      afwimg,
                      fakepsf,
                      fakepsf_fwhm,
                      verbose=True,
                      removeDegenerateTemplates=True)

        self.assertTrue(deb.deblendedParents[0].peaks[3].degenerate)
        self.assertTrue(deb.deblendedParents[0].peaks[4].degenerate)
        self.assertTrue(deb.deblendedParents[0].peaks[5].degenerate)
    def testCoaddApCorrMap(self):
        """Check that we can create and use a coadd ApCorrMap."""
        coaddBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 100))
        scale = 5.0e-5*afwGeom.degrees
        cdMatrix = afwGeom.makeCdMatrix(scale=scale)
        crval = afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees)
        center = afwGeom.Point2D(afwGeom.Extent2D(coaddBox.getDimensions())*0.5)
        coaddWcs = afwGeom.makeSkyWcs(crpix=afwGeom.Point2D(0, 0), crval=crval, cdMatrix=cdMatrix)
        schema = afwTable.ExposureTable.makeMinimalSchema()
        weightKey = schema.addField("customweightname", type="D", doc="Coadd weight")
        catalog = afwTable.ExposureCatalog(schema)

        # Non-overlapping
        num = 5
        inputBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(10, 10))
        validBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(7, 7))
        pointList = []
        pointListValid = []

        for i in range(num):
            value = np.array([[1]], dtype=float)  # Constant with value = i+1
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value*(i + 1))
            apCorrMap.set("only", bf)

            point = afwGeom.Point2D(0, 0) - afwGeom.Extent2D(coaddBox.getDimensions())*(i+0.5)/num
            wcs = afwGeom.makeSkyWcs(crpix=point, crval=crval, cdMatrix=cdMatrix)
            center = afwGeom.Box2D(inputBox).getCenter()
            pointList.append(coaddWcs.skyToPixel(wcs.pixelToSky(center)))

            # This point will only be valid for the second overlapping record
            pointValid = center + afwGeom.Extent2D(4, 4)
            pointListValid.append(coaddWcs.skyToPixel(wcs.pixelToSky(pointValid)))

            # A record with the valid polygon defining a limited region
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 1)
            record['id'] = i
            record.setValidPolygon(afwGeom.Polygon(afwGeom.Box2D(validBox)))
            catalog.append(record)

            # An overlapping record with the whole region as valid
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value*(i + 2))
            apCorrMap.set("only", bf)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 2)
            record['id'] = i + num
            record.setValidPolygon(afwGeom.Polygon(afwGeom.Box2D(inputBox)))
            catalog.append(record)

        apCorrMap = measAlg.makeCoaddApCorrMap(catalog, coaddBox, coaddWcs, "customweightname")
        # This will test a point where both records contribute
        self.assertApCorrMap(apCorrMap, pointList)
        # Only the second record will be valid for this point
        self.assertApCorrMapValid(apCorrMap, pointListValid)

        filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "coaddApCorrMap.fits")
        exposure = afwImage.ExposureF(1, 1)
        exposure.getInfo().setApCorrMap(apCorrMap)
        exposure.writeFits(filename)
        exposure = afwImage.ExposureF(filename)
        self.assertApCorrMap(exposure.getInfo().getApCorrMap(), pointList)
        self.assertApCorrMapValid(exposure.getInfo().getApCorrMap(), pointListValid)
        os.unlink(filename)
Beispiel #18
0
import lsst.afw.table as afwTable
import lsst.afw.geom as afwGeom
import numpy as np

# This is copying from afw/tests/testAmpInfoTable.py:
schema = afwTable.AmpInfoTable.makeMinimalSchema()
catalog = afwTable.AmpInfoCatalog(schema)
record = catalog.addNew()

name = 'Amp1'
bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(8176, 6132))
gain = 0.7
saturation = 57571
readNoise = 12.5
readoutCorner = afwTable.LL  #I think this means Lower Left.
linearityCoeffs = (1.0, np.nan, np.nan, np.nan)
linearityType = "None"
rawBBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(8176, 6132))
rawXYOffset = afwGeom.Extent2I(0, 0)
rawDataBBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                            afwGeom.Extent2I(8176, 6132))
#rawHorizontalOverscanBBox = afwGeom.Box2I(afwGeom.Point2I(8176, 0), afwGeom.Extent2I(0, 8176))
#rawVerticalOverscanBBox = afwGeom.Box2I(afwGeom.Point2I(6132, 0), afwGeom.Extent2I(0, 6132))
rawPrescanBBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(0, 0))

record.setHasRawInfo(True)  #Sets the first Flag=True
record.setRawFlipX(False)  #Sets the second Flag=False
record.setRawFlipY(False)  #Sets the third Flag=False
record.setBBox(bbox)
record.setName(name)
record.setGain(gain)
Beispiel #19
0
    def testImagesOverlap(self):
        # make pairs of image, variance and mask planes
        # using the same dimensions for each so we can mix and match
        # while making masked images
        dim = afwGeom.Extent2I(10, 8)
        # a set of bounding boxes, some of which overlap each other
        # and some of which do not, and include the full image bounding box
        bboxes = (
            afwGeom.Box2I(afwGeom.Point2I(0, 0), dim),
            afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(3, 3)),
            afwGeom.Box2I(afwGeom.Point2I(2, 2), afwGeom.Extent2I(6, 4)),
            afwGeom.Box2I(afwGeom.Point2I(4, 4), afwGeom.Extent2I(6, 4)),
        )
        masks = [afwImage.Mask(dim), afwImage.Mask(dim)]
        variances = [afwImage.ImageF(dim), afwImage.ImageF(dim)]
        imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI,
                        afwImage.ImageU)
        for ImageClass1, ImageClass2 in itertools.product(
                imageClasses, imageClasses):
            images = [ImageClass1(dim), ImageClass2(dim)]
            for image1, mask1, variance1, image2, mask2, variance2 in itertools.product(
                    images, masks, variances, images, masks, variances):
                with self.subTest(ImageClass1=ImageClass1,
                                  ImageClass2=ImageClass2,
                                  image1=image1,
                                  mask1=mask1,
                                  variance1=variance1,
                                  image2=image2,
                                  mask2=mask2,
                                  variance2=variance2):
                    shouldOverlap = (image1 is image2) or (mask1 is mask2) or (
                        variance1 is variance2)

                    mi1 = afwImage.makeMaskedImage(image=image1,
                                                   mask=mask1,
                                                   variance=variance1)
                    mi2 = afwImage.makeMaskedImage(image=image2,
                                                   mask=mask2,
                                                   variance=variance2)
                    self.assertEqual(afwImage.imagesOverlap(mi1, mi2),
                                     shouldOverlap)
                    self.assertEqual(afwImage.imagesOverlap(mi2, mi1),
                                     shouldOverlap)

                    for bbox1, bbox2 in itertools.product(bboxes, bboxes):
                        with self.subTest(bbox1=bbox1, bbox2=bbox2):
                            subMi1 = afwImage.makeMaskedImage(
                                image=type(image1)(image1, bbox1),
                                mask=afwImage.Mask(mask1, bbox1),
                                variance=afwImage.ImageF(variance1, bbox1))
                            subMi2 = afwImage.makeMaskedImage(
                                image=type(image2)(image2, bbox2),
                                mask=afwImage.Mask(mask2, bbox2),
                                variance=afwImage.ImageF(variance2, bbox2))
                            subregionsShouldOverlap = shouldOverlap and bbox1.overlaps(
                                bbox2)
                            self.assertEqual(
                                afwImage.imagesOverlap(subMi1, subMi2),
                                subregionsShouldOverlap)
                            self.assertEqual(
                                afwImage.imagesOverlap(subMi2, subMi1),
                                subregionsShouldOverlap)
    def testInputCounts(self, showPlot=False):
        # Generate a simulated coadd of four overlapping-but-offset CCDs.
        # Populate it with three sources.
        # Demonstrate that we can correctly recover the number of images which
        # contribute to each source.

        size = 20  # Size of images (pixels)
        value = 100.0  # Source flux

        ccdPositions = [
            afwGeom.Point2D(8, 0),
            afwGeom.Point2D(10, 10),
            afwGeom.Point2D(-8, -8),
            afwGeom.Point2D(-8, 8)
        ]

        # Represent sources by a tuple of position and expected number of
        # contributing CCDs (based on the size/positions given above).
        Source = namedtuple("Source", ["pos", "count"])
        sources = [
            Source(pos=afwGeom.Point2D(6, 6), count=2),
            Source(pos=afwGeom.Point2D(10, 10), count=3),
            Source(pos=afwGeom.Point2D(14, 14), count=1)
        ]

        # These lines are used in the creation of WCS information
        scale = 1.0e-5 * afwGeom.degrees
        cdMatrix = afwGeom.makeCdMatrix(scale=scale)
        crval = afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees)

        # Construct the info needed to set the exposure object
        imageBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(size, size))
        wcsRef = afwGeom.makeSkyWcs(crpix=afwGeom.Point2D(0, 0),
                                    crval=crval,
                                    cdMatrix=cdMatrix)

        # Create the exposure object, and set it up to be the output of a coadd
        exp = afwImage.ExposureF(size, size)
        exp.setWcs(wcsRef)
        exp.getInfo().setCoaddInputs(
            afwImage.CoaddInputs(afwTable.ExposureTable.makeMinimalSchema(),
                                 afwTable.ExposureTable.makeMinimalSchema()))

        # Set the fake CCDs that "went into" making this coadd, using the
        # differing wcs objects created above.
        ccds = exp.getInfo().getCoaddInputs().ccds
        for pos in ccdPositions:
            record = ccds.addNew()
            record.setWcs(
                afwGeom.makeSkyWcs(crpix=pos, crval=crval, cdMatrix=cdMatrix))
            record.setBBox(imageBox)
            record.setValidPolygon(afwGeom.Polygon(afwGeom.Box2D(imageBox)))

        # Configure a SingleFrameMeasurementTask to run InputCounts.
        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.plugins.names = [
            "base_PeakCentroid", "base_InputCount"
        ]
        measureSourcesConfig.slots.centroid = "base_PeakCentroid"
        measureSourcesConfig.slots.psfFlux = None
        measureSourcesConfig.slots.apFlux = None
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.instFlux = None
        measureSourcesConfig.slots.calibFlux = None
        measureSourcesConfig.slots.shape = None
        measureSourcesConfig.validate()
        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema,
                                                   config=measureSourcesConfig)
        catalog = afwTable.SourceCatalog(schema)

        # Add simulated sources to the measurement catalog.
        for src in sources:
            spans = afwGeom.SpanSet.fromShape(1)
            spans = spans.shiftedBy(int(src.pos.getX()), int(src.pos.getY()))
            foot = afwDetection.Footprint(spans)
            peak = foot.getPeaks().addNew()
            peak.setFx(src.pos[0])
            peak.setFy(src.pos[1])
            peak.setPeakValue(value)
            catalog.addNew().setFootprint(foot)

        task.run(catalog, exp)

        for src, rec in zip(sources, catalog):
            self.assertEqual(rec.get("base_InputCount_value"), src.count)

        if display:
            ccdVennDiagram(exp)
Beispiel #21
0
    def makeMosaic(self,
                   images=None,
                   display="deferToFrame",
                   mode=None,
                   background=None,
                   title="",
                   frame=None):
        """Return a mosaic of all the images provided; if none are specified,
        use the list accumulated with Mosaic.append().

        Note that this mosaic is a patchwork of the input images;  if you want to
        make a mosaic of a set images of the sky, you probably want to use the coadd code

        If display or frame (deprecated) is specified, display the mosaic
        """

        if images:
            if self.images:
                raise RuntimeError(
                    "You have already appended %d images to this Mosaic" %
                    len(self.images))

            try:
                len(images)  # check that it quacks like a list
            except TypeError:
                images = [images]

            self.images = images
        else:
            images = self.images

        if self.nImage == 0:
            raise RuntimeError("You must provide at least one image")

        self.xsize, self.ysize = 0, 0
        for im in images:
            w, h = im.getWidth(), im.getHeight()
            if w > self.xsize:
                self.xsize = w
            if h > self.ysize:
                self.ysize = h

        if background is None:
            background = self.background
        if mode is None:
            mode = self.mode

        if mode == "square":
            nx, ny = 1, self.nImage
            while nx * im.getWidth() < ny * im.getHeight():
                nx += 1
                ny = self.nImage // nx

                if nx * ny < self.nImage:
                    ny += 1
                if nx * ny < self.nImage:
                    nx += 1

            if nx > self.nImage:
                nx = self.nImage

            assert (nx * ny >= self.nImage)
        elif mode == "x":
            nx, ny = self.nImage, 1
        elif mode == "y":
            nx, ny = 1, self.nImage
        elif isinstance(mode, int):
            nx = mode
            ny = self.nImage // nx
            if nx * ny < self.nImage:
                ny += 1
        else:
            raise RuntimeError("Unknown mosaicing mode: %s" % mode)

        self.nx, self.ny = nx, ny

        mosaic = images[0].Factory(
            afwGeom.Extent2I(nx * self.xsize + (nx - 1) * self.gutter,
                             ny * self.ysize + (ny - 1) * self.gutter))
        try:
            mosaic.set(self.background)
        except AttributeError:
            raise RuntimeError(
                "Attempt to mosaic images of type %s which don't support set" %
                type(mosaic))

        for i in range(len(images)):
            smosaic = mosaic.Factory(mosaic, self.getBBox(i % nx, i // nx),
                                     afwImage.LOCAL)
            im = images[i]

            if smosaic.getDimensions() != im.getDimensions(
            ):  # im is smaller than smosaic
                llc = afwGeom.PointI(
                    (smosaic.getWidth() - im.getWidth()) // 2,
                    (smosaic.getHeight() - im.getHeight()) // 2)
                smosaic = smosaic.Factory(
                    smosaic, afwGeom.Box2I(llc, im.getDimensions()),
                    afwImage.LOCAL)

            smosaic[:] = im

        display = _getDisplayFromDisplayOrFrame(display, frame)
        if display:
            display.mtv(mosaic, title=title)

            if images == self.images:
                self.drawLabels(display=display)

        return mosaic
Beispiel #22
0
display = True

verbosity = 4
logUtils.traceSetAt("ip.diffim", verbosity)

defDataDir = lsst.utils.getPackageDir('afwdata')
imageProcDir = lsst.utils.getPackageDir('ip_diffim')

if len(sys.argv) == 1:
    defTemplatePath = os.path.join(defDataDir, "CFHT", "D4",
                                   "cal-53535-i-797722_2_tmpl.fits")
    defSciencePath = os.path.join(defDataDir, "CFHT", "D4",
                                  "cal-53535-i-797722_2.fits")
    templateMaskedImage = afwImage.MaskedImageF(defTemplatePath)
    scienceMaskedImage = afwImage.MaskedImageF(defSciencePath)
    bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(512, 512))
    templateMaskedImage = afwImage.MaskedImageF(templateMaskedImage,
                                                bbox,
                                                origin=afwImage.LOCAL)
    scienceMaskedImage = afwImage.MaskedImageF(scienceMaskedImage,
                                               bbox,
                                               origin=afwImage.LOCAL)

elif len(sys.argv) == 3:
    defTemplatePath = sys.argv[1]
    defSciencePath = sys.argv[2]
    templateMaskedImage = afwImage.MaskedImageF(defTemplatePath)
    scienceMaskedImage = afwImage.MaskedImageF(defSciencePath)
else:
    sys.exit(1)
Beispiel #23
0
    def measureBackground(self, exposure):
        statsControl = afwMath.StatisticsControl(
            self.config.qa.flatness.clipSigma, self.config.qa.flatness.nIter)
        maskVal = exposure.getMaskedImage().getMask().getPlaneBitMask(
            ["BAD", "SAT", "DETECTED"])
        statsControl.setAndMask(maskVal)
        maskedImage = exposure.getMaskedImage()
        stats = afwMath.makeStatistics(maskedImage,
                                       afwMath.MEDIAN | afwMath.STDEVCLIP,
                                       statsControl)
        skyLevel = stats.getValue(afwMath.MEDIAN)
        skySigma = stats.getValue(afwMath.STDEVCLIP)
        self.log.info("Flattened sky level: %f +/- %f" % (skyLevel, skySigma))
        metadata = exposure.getMetadata()
        metadata.set('SKYLEVEL', skyLevel)
        metadata.set('SKYSIGMA', skySigma)

        # calcluating flatlevel over the subgrids
        stat = afwMath.MEANCLIP if self.config.qa.flatness.doClip else afwMath.MEAN
        meshXHalf = int(self.config.qa.flatness.meshX / 2.)
        meshYHalf = int(self.config.qa.flatness.meshY / 2.)
        nX = int(
            (exposure.getWidth() + meshXHalf) / self.config.qa.flatness.meshX)
        nY = int(
            (exposure.getHeight() + meshYHalf) / self.config.qa.flatness.meshY)
        skyLevels = numpy.zeros((nX, nY))

        for j in range(nY):
            yc = meshYHalf + j * self.config.qa.flatness.meshY
            for i in range(nX):
                xc = meshXHalf + i * self.config.qa.flatness.meshX

                xLLC = xc - meshXHalf
                yLLC = yc - meshYHalf
                xURC = xc + meshXHalf - 1
                yURC = yc + meshYHalf - 1

                bbox = afwGeom.Box2I(afwGeom.Point2I(xLLC, yLLC),
                                     afwGeom.Point2I(xURC, yURC))
                miMesh = maskedImage.Factory(exposure.getMaskedImage(), bbox,
                                             afwImage.LOCAL)

                skyLevels[i,
                          j] = afwMath.makeStatistics(miMesh, stat,
                                                      statsControl).getValue()

        good = numpy.where(numpy.isfinite(skyLevels))
        skyMedian = numpy.median(skyLevels[good])
        flatness = (skyLevels[good] - skyMedian) / skyMedian
        flatness_rms = numpy.std(flatness)
        flatness_pp = flatness.max() - flatness.min() if len(
            flatness) > 0 else numpy.nan

        self.log.info("Measuring sky levels in %dx%d grids: %f" %
                      (nX, nY, skyMedian))
        self.log.info("Sky flatness in %dx%d grids - pp: %f rms: %f" %
                      (nX, nY, flatness_pp, flatness_rms))

        metadata.set('FLATNESS_PP', float(flatness_pp))
        metadata.set('FLATNESS_RMS', float(flatness_rms))
        metadata.set('FLATNESS_NGRIDS', '%dx%d' % (nX, nY))
        metadata.set('FLATNESS_MESHX', self.config.qa.flatness.meshX)
        metadata.set('FLATNESS_MESHY', self.config.qa.flatness.meshY)
Beispiel #24
0
    def testStackBadPixels(self):
        """Check that we properly ignore masked pixels, and set noGoodPixelsMask where there are
        no good pixels"""
        mimgVec = []

        DETECTED = afwImage.Mask.getPlaneBitMask("DETECTED")
        EDGE = afwImage.Mask.getPlaneBitMask("EDGE")
        INTRP = afwImage.Mask.getPlaneBitMask("INTRP")
        SAT = afwImage.Mask.getPlaneBitMask("SAT")

        sctrl = afwMath.StatisticsControl()
        sctrl.setNanSafe(False)
        sctrl.setAndMask(INTRP | SAT)
        sctrl.setNoGoodPixelsMask(EDGE)

        # set these pixels to EDGE
        edgeBBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(20, 20))
        width, height = 512, 512
        dim = afwGeom.Extent2I(width, height)
        val, maskVal = 10, DETECTED
        for i in range(4):
            mimg = afwImage.MaskedImageF(dim)
            mimg.set(val, maskVal, 1)
            #
            # Set part of the image to NaN (with the INTRP bit set)
            #
            llc = afwGeom.Point2I(width // 2 * (i // 2), height // 2 * (i % 2))
            bbox = afwGeom.Box2I(llc, dim // 2)

            smimg = mimg.Factory(mimg, bbox, afwImage.LOCAL)
            del smimg
            #
            # And the bottom corner to SAT
            #
            smask = mimg.getMask().Factory(mimg.getMask(), edgeBBox,
                                           afwImage.LOCAL)
            smask |= SAT
            del smask

            mimgVec.append(mimg)

            if display > 1:
                ds9.mtv(mimg, frame=i, title=str(i))

        mimgStack = afwMath.statisticsStack(mimgVec, afwMath.MEAN, sctrl)

        if display:
            i += 1
            ds9.mtv(mimgStack, frame=i, title="Stack")
            i += 1
            ds9.mtv(mimgStack.getVariance(), frame=i, title="var(Stack)")
        #
        # Check the output, ignoring EDGE pixels
        #
        sctrl = afwMath.StatisticsControl()
        sctrl.setAndMask(afwImage.Mask.getPlaneBitMask("EDGE"))

        stats = afwMath.makeStatistics(mimgStack, afwMath.MIN | afwMath.MAX,
                                       sctrl)
        self.assertEqual(stats.getValue(afwMath.MIN), val)
        self.assertEqual(stats.getValue(afwMath.MAX), val)
        #
        # We have to clear EDGE in the known bad corner to check the mask
        #
        smask = mimgStack.getMask().Factory(mimgStack.getMask(), edgeBBox,
                                            afwImage.LOCAL)
        self.assertEqual(smask.get(edgeBBox.getMinX(), edgeBBox.getMinY()),
                         EDGE)
        smask &= ~EDGE
        del smask

        self.assertEqual(
            afwMath.makeStatistics(mimgStack.getMask(), afwMath.SUM,
                                   sctrl).getValue(), maskVal)
 def setUp(self):
     boxCorner = afwGeom.Point2I(11, 50)
     boxExtent = afwGeom.Extent2I(100, 99)
     self.bbox = afwGeom.Box2I(boxCorner, boxExtent)
     self.xy0 = afwGeom.Point2I(100, 251)
     self.kernel = self.makeKernel()
Beispiel #26
0
    def testClipped(self):
        """Test that we set mask bits when pixels are clipped"""
        box = afwGeom.Box2I(afwGeom.Point2I(12345, 67890),
                            afwGeom.Extent2I(3, 3))
        num = 10
        maskVal = 0xAD
        value = 0.0

        images = [afwImage.MaskedImageF(box) for _ in range(num)]
        statsCtrl = afwMath.StatisticsControl()
        statsCtrl.setAndMask(maskVal)
        clipped = 1 << afwImage.Mask().addMaskPlane("CLIPPED")

        # No clipping: check that vanilla is working
        for img in images:
            img.getImage().set(value)
            img.getMask().set(0)
        stack = afwMath.statisticsStack(images,
                                        afwMath.MEANCLIP,
                                        clipped=clipped)
        self.assertFloatsAlmostEqual(stack.getImage().getArray(),
                                     0.0,
                                     atol=0.0)
        self.assertFloatsAlmostEqual(stack.getMask().getArray(), 0,
                                     atol=0.0)  # Not floats, but that's OK

        # Clip a pixel; the CLIPPED bit should be set
        images[0].getImage().set(1, 1, value + 1.0)
        stack = afwMath.statisticsStack(images,
                                        afwMath.MEANCLIP,
                                        clipped=clipped)
        self.assertFloatsAlmostEqual(stack.getImage().getArray(),
                                     0.0,
                                     atol=0.0)
        self.assertEqual(stack.getMask().get(1, 1), clipped)

        # Mask a pixel; the CLIPPED bit should be set
        images[0].getMask().set(1, 1, maskVal)
        stack = afwMath.statisticsStack(images,
                                        afwMath.MEAN,
                                        statsCtrl,
                                        clipped=clipped)
        self.assertFloatsAlmostEqual(stack.getImage().getArray(),
                                     0.0,
                                     atol=0.0)
        self.assertEqual(stack.getMask().get(1, 1), clipped)

        # Excuse that mask; the CLIPPED bit should not be set
        stack = afwMath.statisticsStack(images,
                                        afwMath.MEAN,
                                        statsCtrl,
                                        clipped=clipped,
                                        excuse=maskVal)
        self.assertFloatsAlmostEqual(stack.getImage().getArray(),
                                     0.0,
                                     atol=0.0)
        self.assertEqual(stack.getMask().get(1, 1), 0)

        # Map that mask value to a different one.
        rejected = 1 << afwImage.Mask().addMaskPlane("REJECTED")
        maskMap = [(maskVal, rejected)]
        images[0].getMask().set(1, 1,
                                0)  # only want to clip, not mask, this one
        images[1].getMask().set(
            1, 2, maskVal)  # only want to mask, not clip, this one
        stack = afwMath.statisticsStack(images,
                                        afwMath.MEANCLIP,
                                        statsCtrl,
                                        wvector=[],
                                        clipped=clipped,
                                        maskMap=maskMap)
        self.assertFloatsAlmostEqual(stack.getImage().getArray(),
                                     0.0,
                                     atol=0.0)
        self.assertEqual(stack.getMask().get(1, 1), clipped)
        self.assertEqual(stack.getMask().get(1, 2), rejected)
    def testPixelFlags(self):
        width, height = 100, 100
        mi = afwImage.MaskedImageF(width, height)
        exp = afwImage.makeExposure(mi)
        mi.getImage().set(0)
        mask = mi.getMask()
        sat = mask.getPlaneBitMask('SAT')
        interp = mask.getPlaneBitMask('INTRP')
        edge = mask.getPlaneBitMask('EDGE')
        bad = mask.getPlaneBitMask('BAD')
        mask.set(0)
        mask.set(20, 20, sat)
        mask.set(60, 60, interp)
        mask.set(40, 20, bad)
        mask.Factory(
            mask,
            afwGeom.Box2I(afwGeom.Point2I(0, 0),
                          afwGeom.Extent2I(3, height))).set(edge)

        x0, y0 = 1234, 5678
        exp.setXY0(afwGeom.Point2I(x0, y0))

        control = measAlg.PixelFlagControl()
        schema = afwTable.SourceTable.makeMinimalSchema()
        mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build(
            schema)
        table = afwTable.SourceTable.make(schema)

        allFlags = [
            "flags.pixel.edge",
            "flags.pixel.bad",
            "flags.pixel.saturated.center",
            "flags.pixel.saturated.any",
            "flags.pixel.interpolated.center",
            "flags.pixel.interpolated.any",
        ]
        for x, y, setFlags in [
            (1, 50, ["flags.pixel.edge"]),
            (40, 20, ["flags.pixel.bad"]),
            (20, 20,
             ["flags.pixel.saturated.center", "flags.pixel.saturated.any"]),
            (20, 22, ["flags.pixel.saturated.any"]),
            (60, 60, [
                "flags.pixel.interpolated.center",
                "flags.pixel.interpolated.any"
            ]),
            (60, 62, ["flags.pixel.interpolated.any"]),
            (float("NAN"), 50, ["flags.pixel.edge"]),
        ]:
            source = table.makeRecord()
            foot = afwDetection.Footprint(
                afwGeom.Point2I(afwGeom.Point2D(x + x0, y + y0)), 5)
            source.setFootprint(foot)
            mp.apply(source, exp, afwGeom.Point2D(x + x0, y + y0))
            for flag in allFlags:
                value = source.get(flag)
                if flag in setFlags:
                    self.assertTrue(
                        value,
                        "Flag %s should be set for %f,%f" % (flag, x, y))
                else:
                    self.assertFalse(
                        value,
                        "Flag %s should not be set for %f,%f" % (flag, x, y))
Beispiel #28
0
 def tst():
     afwImage.ImageF(
         self.image1, 
         afwGeom.Box2I(afwGeom.Point2I(1, -1), afwGeom.Extent2I(10, 5)),
         afwImage.LOCAL
     )
Beispiel #29
0
    def testCcd(self):
        """Test if we can build a Ccd out of Amps"""

        #print >> sys.stderr, "Skipping testCcd"; return

        ccdId = cameraGeom.Id("CCD")
        ccdInfo = {"ampSerial" : CameraGeomTestCase.ampSerial}
        ccd = cameraGeomUtils.makeCcd(self.geomPolicy, ccdId, ccdInfo=ccdInfo)
        if display:
            cameraGeomUtils.showCcd(ccd)
            ds9.incrDefaultFrame()
            trimmedImage = cameraGeomUtils.makeImageFromCcd(ccd, isTrimmed=True)
            cameraGeomUtils.showCcd(ccd, trimmedImage, isTrimmed=True)
            ds9.incrDefaultFrame()

        for i in range(2):
            self.assertEqual(ccd.getSize().getMm()[i],
                             ccdInfo["pixelSize"]*ccd.getAllPixels(True).getDimensions()[i])

        self.assertEqual(ccd.getId().getName(), ccdInfo["name"])
        self.assertEqual(ccd.getAllPixels().getWidth(), ccdInfo["width"])
        self.assertEqual(ccd.getAllPixels().getHeight(), ccdInfo["height"])
        self.assertEqual([a.getId().getSerial() for a in ccd],
                         range(ccdInfo["ampIdMin"], ccdInfo["ampIdMax"] + 1))

        id = cameraGeom.Id("ID%d" % ccdInfo["ampIdMax"])
        self.assertTrue(ccd.findAmp(id), id)

        self.assertEqual(ccd.findAmp(afwGeom.Point2I(10, 10)).getId().getSerial(), ccdInfo["ampIdMin"])

        self.assertEqual(ccd.getAllPixels().getMin(),
                         ccd.findAmp(afwGeom.Point2I(10, 10)).getAllPixels().getMin())

        self.assertEqual(ccd.getAllPixels().getMax(),
                         ccd.findAmp(afwGeom.Point2I(ccdInfo["width"] - 1,
                                                            ccdInfo["height"] - 1)).getAllPixels().getMax())
        ps = ccd.getPixelSize()
        #
        # Test mapping pixel <--> mm.  Use a pixel at the middle of the top of the CCD
        #
        pix = afwGeom.Point2D(99.5, 203.5)            # wrt bottom left
        pos = cameraGeom.FpPoint(0.00, 1.02)             # pixel center wrt CCD center
        posll = cameraGeom.FpPoint(0.00, 1.02)           # llc of pixel wrt CCD center
        #
        # Map pix into untrimmed coordinates
        #
        amp = ccd.findAmp(afwGeom.Point2I(int(pix[0]), int(pix[1])))
        corrI = amp.getDataSec(False).getMin() - amp.getDataSec(True).getMin()
        corr = afwGeom.Extent2D(corrI.getX(), corrI.getY())
        pix += corr
        
        self.assertEqual(amp.getDiskCoordSys(), cameraGeom.Amp.AMP)
        self.assertEqual(ccd.getPixelFromPosition(pos) + corr, pix)
        #
        # Trim the CCD and try again
        #
        trimmedImage = trimCcd(ccd)

        if display:
            ds9.mtv(trimmedImage, title='Trimmed')
            cameraGeomUtils.showCcd(ccd, trimmedImage)
            ds9.incrDefaultFrame()

        a = ccd.findAmp(cameraGeom.Id("ID%d" % ccdInfo["ampIdMin"]))
        self.assertEqual(a.getDataSec(), afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                                       afwGeom.Extent2I(ccdInfo["ampWidth"], ccdInfo["ampHeight"])))

        self.assertEqual(ccd.getSize().getMm()[0], ccdInfo["pixelSize"]*ccdInfo["trimmedWidth"])
        self.assertEqual(ccd.getSize().getMm()[1], ccdInfo["pixelSize"]*ccdInfo["trimmedHeight"])
        #
        # Test mapping pixel <--> mm
        #
        pix = afwGeom.Point2D(99.5, 203.5)            # wrt bottom left
        pos = cameraGeom.FpPoint(0.00, 1.02)             # pixel center wrt CCD center
        posll = cameraGeom.FpPoint(0.00, 1.02)           # llc of pixel wrt CCD center
        
        self.assertEqual(ccd.getPixelFromPosition(pos), pix)
        self.assertEqual(ccd.getPositionFromPixel(pix).getMm(), posll.getMm())
Beispiel #30
0
def rotateBBoxBy90(bbox, n90, dimensions):
    """!Rotate a bounding box by an integer multiple of 90 degrees

    @todo document dimensions better; what does it specify?

    @param bbox  bbox to rotate
    @param n90  number of quarter rotations to perform
    @param dimensions  dimensions of the parent grid
    @return rotated bounding box
    """
    while n90 < 0:
        n90 += 4
    n90 %= 4

    # sin/cos of the rotation angle
    s = 0
    c = 0
    if n90 == 0:
        s = 0
        c = 1
    elif n90 == 1:
        s = 1
        c = 0
    elif n90 == 2:
        s = 0
        c = -1
    elif n90 == 3:
        s = -1
        c = 0
    else:
        raise ValueError("n90 must be an integer")

    centerPixel = afwGeom.Point2I(int(dimensions[0]/2), int(dimensions[1]/2))

    xCorner = numpy.array([(corner.getX() - centerPixel[0])
                           for corner in bbox.getCorners()])
    yCorner = numpy.array([(corner.getY() - centerPixel[1])
                           for corner in bbox.getCorners()])
    x0 = int((c*xCorner - s*yCorner).min())
    y0 = int((s*xCorner + c*yCorner).min())
    x1 = int((c*xCorner - s*yCorner).max())
    y1 = int((s*xCorner + c*yCorner).max())

    # Fiddle things a little if the detector has an even number of pixels so that square BBoxes
    # will map into themselves

    if n90 == 1:
        if dimensions[0]%2 == 0:
            x0 -= 1
            x1 -= 1
    elif n90 == 2:
        if dimensions[0]%2 == 0:
            x0 -= 1
            x1 -= 1
        if dimensions[1]%2 == 0:
            y0 -= 1
            y1 -= 1
    elif n90 == 3:
        if dimensions[1]%2 == 0:
            y0 -= 1
            y1 -= 1

    LLC = afwGeom.Point2I(centerPixel[0] + x0, centerPixel[1] + y0)
    URC = afwGeom.Point2I(centerPixel[0] + x1, centerPixel[1] + y1)

    newBbox = afwGeom.Box2I(LLC, URC)

    dxy0 = centerPixel[0] - centerPixel[1]
    if n90%2 == 1 and not dxy0 == 0:
        newBbox.shift(afwGeom.Extent2I(-dxy0, dxy0))

    return newBbox