예제 #1
0
 def testMutators(self):
     box = geom.Box2D(geom.Point2D(-2, -3), geom.Point2D(2, 1), True)
     box.grow(1)
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-3, -4), geom.Point2D(3, 2), True))
     box.grow(geom.Extent2D(2, 3))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-5, -7), geom.Point2D(5, 5), True))
     box.shift(geom.Extent2D(3, 2))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-2, -5), geom.Point2D(8, 7), True))
     box.include(geom.Point2D(-4, 2))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-4, -5), geom.Point2D(8, 7), True))
     self.assertTrue(box.contains(geom.Point2D(-4, 2)))
     box.include(geom.Point2D(0, -6))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-4, -6), geom.Point2D(8, 7), True))
     box.include(geom.Box2D(geom.Point2D(0, 0), geom.Point2D(10, 11), True))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(-4, -6), geom.Point2D(10, 11), True))
     box.clip(geom.Box2D(geom.Point2D(0, 0), geom.Point2D(11, 12), True))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(0, 0), geom.Point2D(10, 11), True))
     box.clip(geom.Box2D(geom.Point2D(-1, -2), geom.Point2D(5, 4), True))
     self.assertEqual(
         box, geom.Box2D(geom.Point2D(0, 0), geom.Point2D(5, 4), True))
예제 #2
0
    def fromCamera(cls, config, camera):
        """Construct from a camera object

        Parameters
        ----------
        config : `FocalPlaneBackgroundConfig`
            Configuration for measuring backgrounds.
        camera : `lsst.afw.cameraGeom.Camera`
            Camera for which to measure backgrounds.
        """
        cameraBox = geom.Box2D()
        for ccd in camera:
            for point in ccd.getCorners(afwCameraGeom.FOCAL_PLANE):
                cameraBox.include(point)

        width, height = cameraBox.getDimensions()
        # Offset so that we run from zero
        offset = geom.Extent2D(cameraBox.getMin()) * -1
        # Add an extra pixel buffer on either side
        dims = geom.Extent2I(
            int(numpy.ceil(width / config.xSize)) + 2,
            int(numpy.ceil(height / config.ySize)) + 2)
        # Transform takes us from focal plane coordinates --> sample coordinates
        transform = (
            geom.AffineTransform.makeTranslation(geom.Extent2D(1, 1)) *
            geom.AffineTransform.makeScaling(1.0 / config.xSize,
                                             1.0 / config.ySize) *
            geom.AffineTransform.makeTranslation(offset))

        return cls(config, dims, afwGeom.makeTransform(transform))
예제 #3
0
    def testFindTract(self):
        """Test the SkyMap.findTract method
        """
        for numTracts in (2, 4):
            config = EquatSkyMap.ConfigClass()
            config.numTracts = numTracts
            skyMap = EquatSkyMap(config)
            decRange = skyMap.config.decRange
            decList = (
                (decRange[0] * 0.999) + (decRange[1] * 0.901),
                (decRange[0] * 0.500) + (decRange[1] * 0.500),
                (decRange[0] * 0.091) + (decRange[1] * 0.999),
            )
            for tractInfo0 in skyMap:
                tractId0 = tractInfo0.getId()
                ctrCoord0 = tractInfo0.getCtrCoord()

                for tractInfo1 in self.getNeighborTracts(skyMap, tractId0):

                    tractId1 = tractInfo1.getId()
                    ctrCoord1 = tractInfo1.getCtrCoord()

                    for deltaFrac in (-0.001, 0.001):
                        v0 = ctrCoord0.getVector() * (0.5 + deltaFrac)
                        v1 = ctrCoord1.getVector() * (0.5 - deltaFrac)
                        testVec = v0 + v1
                        testRa = geom.SpherePoint(testVec).getRa()

                        if deltaFrac > 0.0:
                            expectedTractId = tractId0
                        else:
                            expectedTractId = tractId1

                        for testDecDeg in decList:
                            testDec = geom.Angle(testDecDeg, geom.degrees)
                            testCoord = geom.SpherePoint(testRa, testDec)

                            nearestTractInfo = skyMap.findTract(testCoord)
                            nearestTractId = nearestTractInfo.getId()

                            self.assertEqual(nearestTractId, expectedTractId)

                            patchInfo = nearestTractInfo.findPatch(testCoord)
                            pixelInd = geom.Point2I(nearestTractInfo.getWcs().skyToPixel(testCoord))
                            self.assertTrue(patchInfo.getInnerBBox().contains(pixelInd))

                # find a point outside the tract and make sure it fails
                tractInfo = tractInfo0
                wcs = tractInfo.getWcs()
                bbox = geom.Box2D(tractInfo.getBBox())
                outerPixPosList = [
                    bbox.getMin() - geom.Extent2D(1, 1),
                    geom.Point2D(bbox.getMaxX(), bbox.getMinY()) - geom.Extent2D(1, 1),
                    bbox.getMax() + geom.Extent2D(1, 1),
                    geom.Point2D(bbox.getMinX(), bbox.getMaxY()) + geom.Extent2D(1, 1),
                ]
                for outerPixPos in outerPixPosList:
                    testCoord = wcs.pixelToSky(outerPixPos)
                    self.assertRaises(LookupError, tractInfo.findPatch, testCoord)
예제 #4
0
    def testConstructors(self):
        # test extent from extent 2-d
        e1 = geom.Extent2I(1, 2)
        e2 = geom.Extent2I(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Extent2D(1.2, 3.4)
        e2 = geom.Extent2D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Extent2I(1, 2)
        e2 = geom.Extent2D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        # test extent from extent 3-d
        e1 = geom.Extent3I(1, 2, 3)
        e2 = geom.Extent3I(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Extent3D(1.2, 3.4, 5.6)
        e2 = geom.Extent3D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Extent3I(1, 2, 3)
        e2 = geom.Extent3D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        # test extent from point 2-d
        e1 = geom.Point2I(1, 2)
        e2 = geom.Extent2I(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Point2D(1.2, 3.4)
        e2 = geom.Extent2D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Point2I(1, 2)
        e2 = geom.Extent2D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        # test extent from point 3-d
        e1 = geom.Point3I(1, 2, 3)
        e2 = geom.Extent3I(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Point3D(1.2, 3.4, 5.6)
        e2 = geom.Extent3D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))

        e1 = geom.Point3I(1, 2, 3)
        e2 = geom.Extent3D(e1)
        self.assertAlmostEqual(tuple(e1), tuple(e2))
예제 #5
0
    def _getCenterOfMass(exp, nominalCentroid, boxSize):
        """Get the centre of mass around a point in the image.

        Parameters
        ----------
        exp : `lsst.afw.image.Exposure`
            The exposure in question.
        nominalCentroid : `tuple` of `float`
            Nominal location of the centroid in pixel coordinates.
        boxSize : `int`
            The size of the box around the nominalCentroid in which to measure
            the centre of mass.

        Returns
        -------
        com : `tuple` of `float`
            The locaiton of the centre of mass of the brightest source in pixel
            coordinates.
        """
        centroidPoint = geom.Point2I(nominalCentroid)
        extent = geom.Extent2I(1, 1)
        bbox = geom.Box2I(centroidPoint, extent)
        bbox = bbox.dilatedBy(int(boxSize // 2))
        bbox = bbox.clippedTo(exp.getBBox())
        data = exp[bbox].image.array
        xy0 = exp[bbox].getXY0()

        peak = ndImage.center_of_mass(data)
        peak = (peak[1], peak[0])  # numpy coords returned
        com = geom.Point2D(xy0)
        com.shift(geom.Extent2D(*peak))
        return (com[0], com[1])
예제 #6
0
    def _finalOrientation(self, bbox, wcs):
        """Determine the final orientation

        We offset everything so the lower-left corner is at 0,0
        and compute the final Wcs.

        Parameters
        ----------
        bbox : `lsst.geom.Box2I`
            Current bounding box.
        wcs : `lsst.afw.geom.SkyWcs
            Current Wcs.

        Returns
        -------
        finalBBox : `lsst.geom.Box2I`
            Revised bounding box.
        wcs : `lsst.afw.geom.SkyWcs`
            Revised Wcs.
        """
        finalBBox = geom.Box2I(geom.Point2I(0, 0), bbox.getDimensions())
        # shift the WCS by the same amount as the bbox; extra code is required
        # because simply subtracting makes an Extent2I
        pixPosOffset = geom.Extent2D(finalBBox.getMinX() - bbox.getMinX(),
                                     finalBBox.getMinY() - bbox.getMinY())
        wcs = wcs.copyAtShiftedPixelOrigin(pixPosOffset)
        return finalBBox, wcs
예제 #7
0
    def testMakeCenteredBox(self):
        dimensionsI = [
            geom.Extent2I(100, 50),
            geom.Extent2I(15, 15),
            geom.Extent2I(0, 10),
            geom.Extent2I(25, 30),
            geom.Extent2I(15, -5)
        ]
        dimensionsD = [geom.Extent2D(d) for d in dimensionsI] \
            + [geom.Extent2D(1.5, 2.1), geom.Extent2D(4, 3.7),
               geom.Extent2D(-0.1, -0.1), geom.Extent2D(5.5, 5.5),
               geom.Extent2D(-np.nan, 5.5), geom.Extent2D(4, np.inf)]
        locations = [
            geom.Point2D(0, 0),
            geom.Point2D(0.2, 0.7),
            geom.Point2D(1, 1.5),
            geom.Point2D(-0.5 + 1e-4, -0.5 + 1e-4),
            geom.Point2D(-0.5 - 1e-4, -0.5 - 1e-4),
            geom.Point2D(-np.nan, 0),
            geom.Point2D(1.0, np.inf),
        ]

        for center in locations:
            for size in dimensionsI:
                self._checkBoxConstruction(geom.Box2I, size, center,
                                           np.sqrt(0.5))
            for size in dimensionsD:
                self._checkBoxConstruction(geom.Box2D, size, center, 1e-10)
    def runMeasurement(self, algorithmName, imageid, x, y, v):
        """Run the measurement algorithm on an image"""
        # load the test image
        imgFile = os.path.join(self.dataDir, "image.%d.fits" % imageid)
        img = afwImage.ImageF(imgFile)
        img -= self.bkgd
        nx, ny = img.getWidth(), img.getHeight()
        msk = afwImage.Mask(geom.Extent2I(nx, ny), 0x0)
        var = afwImage.ImageF(geom.Extent2I(nx, ny), v)
        mimg = afwImage.MaskedImageF(img, msk, var)
        msk.getArray()[:] = np.where(np.fabs(img.getArray()) < 1.0e-8, msk.getPlaneBitMask("BAD"), 0)

        # Put it in a bigger image, in case it matters
        big = afwImage.MaskedImageF(self.offset + mimg.getDimensions())
        big.getImage().set(0)
        big.getMask().set(0)
        big.getVariance().set(v)
        subBig = afwImage.MaskedImageF(big, geom.Box2I(big.getXY0() + self.offset, mimg.getDimensions()))
        subBig <<= mimg
        mimg = big
        mimg.setXY0(self.xy0)

        exposure = afwImage.makeExposure(mimg)
        cdMatrix = np.array([1.0/(2.53*3600.0), 0.0, 0.0, 1.0/(2.53*3600.0)])
        cdMatrix.shape = (2, 2)
        exposure.setWcs(afwGeom.makeSkyWcs(crpix=geom.Point2D(1.0, 1.0),
                                           crval=geom.SpherePoint(0, 0, geom.degrees),
                                           cdMatrix=cdMatrix))

        # load the corresponding test psf
        psfFile = os.path.join(self.dataDir, "psf.%d.fits" % imageid)
        psfImg = afwImage.ImageD(psfFile)
        psfImg -= self.bkgd

        kernel = afwMath.FixedKernel(psfImg)
        kernelPsf = algorithms.KernelPsf(kernel)
        exposure.setPsf(kernelPsf)

        # perform the shape measurement
        msConfig = base.SingleFrameMeasurementConfig()
        alg = base.SingleFramePlugin.registry[algorithmName].PluginClass.AlgClass
        control = base.SingleFramePlugin.registry[algorithmName].PluginClass.ConfigClass().makeControl()
        msConfig.algorithms.names = [algorithmName]
        # Note: It is essential to remove the floating point part of the position for the
        # Algorithm._apply.  Otherwise, when the PSF is realised it will have been warped
        # to account for the sub-pixel offset and we won't get *exactly* this PSF.
        plugin, table = makePluginAndCat(alg, algorithmName, control, centroid="centroid")
        center = geom.Point2D(int(x), int(y)) + geom.Extent2D(self.offset + geom.Extent2I(self.xy0))
        source = table.makeRecord()
        source.set("centroid_x", center.getX())
        source.set("centroid_y", center.getY())
        source.setFootprint(afwDetection.Footprint(afwGeom.SpanSet(exposure.getBBox(afwImage.PARENT))))
        plugin.measure(source, exposure)

        return source
예제 #9
0
    def computeImageScaler(self, exposure, dataRef):
        """Compute image scaling object for a given exposure.

        @param[in] exposure: exposure for which scaling is desired. Only wcs and bbox are used.
        @param[in] dataRef: dataRef of exposure
                            dataRef.dataId used to retrieve all applicable fluxMag0's from a database.
        @return a SpatialImageScaler
        """

        wcs = exposure.getWcs()

        fluxMagInfoList = self.selectFluxMag0.run(
            dataRef.dataId).fluxMagInfoList

        xList = []
        yList = []
        scaleList = []

        for fluxMagInfo in fluxMagInfoList:
            # find center of field in tract coordinates
            if not fluxMagInfo.coordList:
                raise RuntimeError("no x,y data for fluxMagInfo")
            ctr = geom.Extent2D()
            for coord in fluxMagInfo.coordList:
                # accumulate x, y
                ctr += geom.Extent2D(wcs.skyToPixel(coord))
            # and find average x, y as the center of the chip
            ctr = geom.Point2D(ctr / len(fluxMagInfo.coordList))
            xList.append(ctr.getX())
            yList.append(ctr.getY())
            scaleList.append(
                self.scaleFromFluxMag0(fluxMagInfo.fluxMag0).scale)

        self.log.info("Found %d flux scales for interpolation: %s",
                      len(scaleList), [f"{s:%0.4f}" for s in scaleList])
        return SpatialImageScaler(
            interpStyle=self.config.interpStyle,
            xList=xList,
            yList=yList,
            scaleList=scaleList,
        )
예제 #10
0
    def toCcdBackground(self, detector, bbox):
        """Produce a background model for a CCD

        The superpixel background model is warped back to the
        CCD frame, for application to the individual CCD.

        Parameters
        ----------
        detector : `lsst.afw.cameraGeom.Detector`
            CCD for which to produce background model.
        bbox : `lsst.geom.Box2I`
            Bounding box of CCD exposure.

        Returns
        -------
        bg : `lsst.afw.math.BackgroundList`
            Background model for CCD.
        """
        transform = detector.getTransformMap().getTransform(
            detector.makeCameraSys(afwCameraGeom.PIXELS),
            detector.makeCameraSys(afwCameraGeom.FOCAL_PLANE))
        binTransform = (
            geom.AffineTransform.makeScaling(self.config.binning) *
            geom.AffineTransform.makeTranslation(geom.Extent2D(0.5, 0.5)))

        # Binned image on CCD --> unbinned image on CCD --> focal plane --> binned focal plane
        toSample = afwGeom.makeTransform(binTransform).then(transform).then(
            self.transform)

        focalPlane = self.getStatsImage()
        fpNorm = afwImage.ImageF(focalPlane.getBBox())
        fpNorm.set(1.0)

        image = afwImage.ImageF(bbox.getDimensions() // self.config.binning)
        norm = afwImage.ImageF(image.getBBox())
        ctrl = afwMath.WarpingControl("bilinear")
        afwMath.warpImage(image, focalPlane, toSample.inverted(), ctrl)
        afwMath.warpImage(norm, fpNorm, toSample.inverted(), ctrl)
        image /= norm

        mask = afwImage.Mask(image.getBBox())
        isBad = numpy.isnan(image.getArray())
        mask.getArray()[isBad] = mask.getPlaneBitMask("BAD")
        image.getArray()[isBad] = image.getArray()[~isBad].mean()

        return afwMath.BackgroundList(
            (afwMath.BackgroundMI(bbox, afwImage.makeMaskedImage(image, mask)),
             afwMath.stringToInterpStyle(self.config.interpolation),
             afwMath.stringToUndersampleStyle("REDUCE_INTERP_ORDER"),
             afwMath.ApproximateControl.UNKNOWN, 0, 0, False))
예제 #11
0
def createImage(
        dataId={"name": "foobar"},  # Data identifier
        center=CENTER,  # ICRS sky position of center (lsst.afw.geom.SpherePoint)
        rotateAxis=ROTATEAXIS,  # Rotation axis (lsst.afw.geom.SpherePoint)
        rotateAngle=0 *
    geom.degrees,  # Rotation angle/distance to move (Angle)
        dims=DIMS,  # Image dimensions (Extent2I)
        scale=SCALE  # Pixel scale (Angle)
):
    crpix = geom.Point2D(geom.Extent2D(dims) * 0.5)
    center = center.rotated(rotateAxis, rotateAngle)
    cdMatrix = afwGeom.makeCdMatrix(scale=scale)
    wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=center, cdMatrix=cdMatrix)
    return SelectStruct(
        DummyDataRef(dataId), wcs,
        geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(dims[0], dims[1])))
예제 #12
0
    def testWcsPostIsr(self):
        """Test the wcs of postISRCCD products

        The postISRCCD wcs should be the same as the raw wcs
        after adding camera distortion and
        adjustment of overscan/prescan trimming. Test DM-4859.
        """
        if not self.config.isr.doWrite or not self.config.isr.assembleCcd.doTrim:
            return
        expRaw = self.butler.get("raw", self.dataId, immediate=True)
        expPost = self.butler.get("postISRCCD", self.dataId, immediate=True)
        self.assertIsInstance(expPost, afwImage.ExposureF)
        wcsRaw = expRaw.getWcs()
        wcsPost = expPost.getWcs()
        # Shift WCS for trimming the prescan and overscan region
        # ccdnum 1 is S29, with overscan in the bottom
        wcsRaw = wcsRaw.copyAtShiftedPixelOrigin(geom.Extent2D(-56, -50))
        self.assertWcsAlmostEqualOverBBox(wcsRaw, wcsPost, expPost.getBBox())
예제 #13
0
 def testConstruction(self):
     for n in range(10):
         xmin, xmax, ymin, ymax = np.random.uniform(low=-5, high=5, size=4)
         if xmin > xmax:
             xmin, xmax = xmax, xmin
         if ymin > ymax:
             ymin, ymax = ymax, ymin
         pmin = geom.Point2D(xmin, ymin)
         pmax = geom.Point2D(xmax, ymax)
         # min/max constructor
         box = geom.Box2D(pmin, pmax)
         self.assertEqual(box.getMin(), pmin)
         self.assertEqual(box.getMax(), pmax)
         box = geom.Box2D(pmax, pmin)
         self.assertEqual(box.getMin(), pmin)
         self.assertEqual(box.getMax(), pmax)
         box = geom.Box2D(pmin, pmax, False)
         self.assertEqual(box.getMin(), pmin)
         self.assertEqual(box.getMax(), pmax)
         box = geom.Box2D(pmax, pmin, False)
         self.assertTrue(box.isEmpty())
         self.assertEqual(box, geom.Box2D(box))
         # min/dim constructor
         dim = pmax - pmin
         if any(dim.eq(0)):
             box = geom.Box2D(pmin, dim)
             self.assertTrue(box.isEmpty())
             box = geom.Box2D(pmin, dim, False)
             self.assertTrue(box.isEmpty())
         else:
             box = geom.Box2D(pmin, dim)
             self.assertEqual(box.getMin(), pmin)
             self.assertEqual(box.getDimensions(), dim)
             box = geom.Box2D(pmin, dim, False)
             self.assertEqual(box.getMin(), pmin)
             self.assertEqual(box.getDimensions(), dim)
             dim = -dim
             box = geom.Box2D(pmin, dim)
             self.assertEqual(box.getMin(), pmin + dim)
             self.assertFloatsAlmostEqual(
                 box.getDimensions(),
                 geom.Extent2D(abs(dim.getX()), abs(dim.getY())))
예제 #14
0
def createPatch(
    tractId=1,
    patchId=(2, 3),  # Tract and patch identifier, for dataId
    dims=DIMS,  # Patch dimensions (Extent2I)
    xy0=geom.Point2I(1234, 5678),  # Patch xy0 (Point2I)
    center=CENTER,  # ICRS sky position of center (lsst.afw.geom.SpherePoint)
    scale=SCALE  # Pixel scale (Angle)
):
    crpix = geom.Point2D(xy0) + geom.Extent2D(dims) * 0.5
    cdMatrix = afwGeom.makeCdMatrix(scale=scale)
    wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=center, cdMatrix=cdMatrix)
    patch = DummyPatch(xy0, dims)
    tract = DummyTract(patchId, patch, wcs)
    skymap = DummySkyMap(tractId, tract)
    dataRef = DummyDataRef(
        {
            'tract': tractId,
            'patch': ",".join(map(str, patchId))
        },
        deepCoadd_skyMap=skymap)
    return dataRef
예제 #15
0
    def testFlipD(self):
        parentExtent = geom.Extent2D(15.1, 20.6)
        x00, y00, x11, y11 = (8.3, 11.4, 13.2, 16.9)
        lrx00, lry00, lrx11, lry11 = (1.9, 11.4, 6.8, 16.9)
        tbx00, tby00, tbx11, tby11 = (8.3, 3.7, 13.2, 9.2)

        box0 = geom.Box2D(geom.Point2D(x00, y00), geom.Point2D(x11, y11))
        box1 = geom.Box2D(geom.Point2D(x00, y00), geom.Point2D(x11, y11))
        box0.flipLR(parentExtent[0])
        box1.flipTB(parentExtent[1])

        # test flip RL
        self.assertAlmostEqual(box0.getMinX(), lrx00, places=6)
        self.assertAlmostEqual(box0.getMinY(), lry00, places=6)
        self.assertAlmostEqual(box0.getMaxX(), lrx11, places=6)
        self.assertAlmostEqual(box0.getMaxY(), lry11, places=6)

        # test flip TB
        self.assertAlmostEqual(box1.getMinX(), tbx00, places=6)
        self.assertAlmostEqual(box1.getMinY(), tby00, places=6)
        self.assertAlmostEqual(box1.getMaxX(), tbx11, places=6)
        self.assertAlmostEqual(box1.getMaxY(), tby11, places=6)
    def _solve(self, sourceCat, wcs, bbox, pixelScale, radecCenter, searchRadius, parity, filterName=None):
        """
        @param[in] parity  True for flipped parity, False for normal parity, None to leave parity unchanged
        """
        solver = self.refObjLoader._getSolver()

        imageSize = bbox.getDimensions()
        x0, y0 = bbox.getMin()

        # select sources with valid x, y, flux
        xybb = geom.Box2D()
        goodsources = afwTable.SourceCatalog(sourceCat.table)
        badkeys = [goodsources.getSchema().find(name).key for name in self.config.badFlags]

        for s in sourceCat:
            if np.isfinite(s.getX()) and np.isfinite(s.getY()) and np.isfinite(s.getPsfInstFlux()) \
                    and self._isGoodSource(s, badkeys):
                goodsources.append(s)
                xybb.include(geom.Point2D(s.getX() - x0, s.getY() - y0))
        self.log.info("Number of selected sources for astrometry : %d" % (len(goodsources)))
        if len(goodsources) < len(sourceCat):
            self.log.debug('Keeping %i of %i sources with finite X,Y positions and PSF flux',
                           len(goodsources), len(sourceCat))
        self.log.debug('Feeding sources in range x=[%.1f, %.1f], y=[%.1f, %.1f] ' +
                       '(after subtracting x0,y0 = %.1f,%.1f) to Astrometry.net',
                       xybb.getMinX(), xybb.getMaxX(), xybb.getMinY(), xybb.getMaxY(), x0, y0)
        # setStars sorts them by PSF flux.
        solver.setStars(goodsources, x0, y0)
        solver.setMaxStars(self.config.maxStars)
        solver.setImageSize(*imageSize)
        solver.setMatchThreshold(self.config.matchThreshold)
        raDecRadius = None
        if radecCenter is not None:
            raDecRadius = (radecCenter.getLongitude().asDegrees(), radecCenter.getLatitude().asDegrees(),
                           searchRadius.asDegrees())
            solver.setRaDecRadius(*raDecRadius)
            self.log.debug('Searching for match around RA,Dec = (%g, %g) with radius %g deg' %
                           raDecRadius)

        if pixelScale is not None:
            dscale = self.config.pixelScaleUncertainty
            scale = pixelScale.asArcseconds()
            lo = scale / dscale
            hi = scale * dscale
            solver.setPixelScaleRange(lo, hi)
            self.log.debug(
                'Searching for matches with pixel scale = %g +- %g %% -> range [%g, %g] arcsec/pix',
                scale, 100.*(dscale-1.), lo, hi)

        if parity is not None:
            solver.setParity(parity)
            self.log.debug('Searching for match with parity = %s', str(parity))

        # Find and load index files within RA,Dec range and scale range.
        if radecCenter is not None:
            multiInds = self.refObjLoader._getMIndexesWithinRange(radecCenter, searchRadius)
        else:
            multiInds = self.refObjLoader.multiInds
        qlo, qhi = solver.getQuadSizeRangeArcsec()

        toload_multiInds = set()
        toload_inds = []
        for mi in multiInds:
            for i in range(len(mi)):
                ind = mi[i]
                if not ind.overlapsScaleRange(qlo, qhi):
                    continue
                toload_multiInds.add(mi)
                toload_inds.append(ind)

        import lsstDebug
        if lsstDebug.Info(__name__).display:
            # Use separate context for display, since astrometry.net can segfault if we don't...
            with LoadMultiIndexes(toload_multiInds):
                displayAstrometry(refCat=self.refObjLoader.loadPixelBox(bbox, wcs, filterName).refCat,
                                  frame=lsstDebug.Info(__name__).frame, pause=lsstDebug.Info(__name__).pause)

        with LoadMultiIndexes(toload_multiInds):
            solver.addIndices(toload_inds)
            self.memusage('Index files loaded: ')

            cpulimit = self.config.maxCpuTime
            solver.run(cpulimit)

            self.memusage('Solving finished: ')

        self.memusage('Index files unloaded: ')

        if solver.didSolve():
            self.log.debug('Solved!')
            wcs = solver.getWcs()

            if x0 != 0 or y0 != 0:
                wcs = wcs.copyAtShiftedPixelOrigin(geom.Extent2D(x0, y0))

        else:
            self.log.warn('Did not get an astrometric solution from Astrometry.net')
            wcs = None
            # Gather debugging info...

            # -are there any reference stars in the proposed search area?
            # log the number found and discard the results
            if radecCenter is not None:
                self.refObjLoader.loadSkyCircle(radecCenter, searchRadius, filterName)

        qa = solver.getSolveStats()
        self.log.debug('qa: %s', qa.toString())
        return wcs, qa
예제 #17
0
 def testRounding(self):
     e1 = geom.Extent2D(1.2, -3.4)
     self.assertEqual(e1.floor(), geom.Extent2I(1, -4))
     self.assertEqual(e1.ceil(), geom.Extent2I(2, -3))
     self.assertEqual(e1.truncate(), geom.Extent2I(1, -3))
예제 #18
0
 def testIntersect(self):
     self.check(
         createPatch(),
         createImage(rotateAngle=0.5 * geom.Extent2D(DIMS).computeNorm() *
                     SCALE), True)
예제 #19
0
 def pixelSize(self):
     """Return the pixel size as an Extent2D from the separate values.
     """
     return geom.Extent2D(self.pixelSize_x, self.pixelSize_y)
    def check(self, psfFwhm=0.5, flux=1000.0, forced=False):
        """Check that we can measure convolved fluxes

        We create an image with a Gaussian PSF and a single point source.
        Measurements of the point source should match expectations for a
        Gaussian of the known sigma and known aperture radius.

        Parameters
        ----------
        psfFwhm : `float`
            PSF FWHM (arcsec)
        flux : `float`
            Source flux (ADU)
        forced : `bool`
            Forced measurement?
        """
        bbox = geom.Box2I(geom.Point2I(12345, 6789), geom.Extent2I(200, 300))

        # We'll only achieve the target accuracy if the pixel scale is rather smaller than Gaussians
        # involved. Otherwise it's important to consider the convolution with the pixel grid, and we're
        # not doing that here.
        scale = 0.1 * geom.arcseconds

        TaskClass = measBase.ForcedMeasurementTask if forced else measBase.SingleFrameMeasurementTask

        exposure, center = makeExposure(bbox, scale, psfFwhm, flux)
        measConfig = TaskClass.ConfigClass()
        algName = "ext_convolved_ConvolvedFlux"
        measConfig.plugins.names.add(algName)
        if not forced:
            measConfig.plugins.names.add("ext_photometryKron_KronFlux")
        else:
            measConfig.copyColumns = {
                "id": "objectId",
                "parent": "parentObjectId"
            }
        values = [ii / scale.asArcseconds() for ii in (0.6, 0.8, 1.0, 1.2)]
        algConfig = measConfig.plugins[algName]
        algConfig.seeing = values
        algConfig.aperture.radii = values
        algConfig.aperture.maxSincRadius = max(
            values) + 1  # Get as exact as we can

        if forced:
            offset = geom.Extent2D(-12.3, 45.6)
            kronRadiusName = "my_Kron_Radius"
            kronRadius = 12.345
            refWcs = exposure.getWcs().copyAtShiftedPixelOrigin(offset)
            measConfig.plugins[algName].kronRadiusName = kronRadiusName
            refSchema = afwTable.SourceTable.makeMinimalSchema()
            centroidKey = afwTable.Point2DKey.addFields(refSchema,
                                                        "my_centroid",
                                                        doc="centroid",
                                                        unit="pixel")
            shapeKey = afwTable.QuadrupoleKey.addFields(
                refSchema, "my_shape", "shape")
            refSchema.getAliasMap().set("slot_Centroid", "my_centroid")
            refSchema.getAliasMap().set("slot_Shape", "my_shape")
            refSchema.addField("my_centroid_flag",
                               type="Flag",
                               doc="centroid flag")
            refSchema.addField("my_shape_flag", type="Flag", doc="shape flag")
            refSchema.addField(kronRadiusName,
                               type=float,
                               doc="my custom kron radius",
                               units="pixel")
            refCat = afwTable.SourceCatalog(refSchema)
            refSource = refCat.addNew()
            refSource.set(centroidKey, center + offset)
            refSource.set(
                shapeKey,
                afwEll.Quadrupole(afwEll.Axes(kronRadius, kronRadius, 0)))
            refSource.set(kronRadiusName, kronRadius)
            refSource.setCoord(refWcs.pixelToSky(refSource.get(centroidKey)))
            taskInitArgs = (refSchema, )
            taskRunArgs = (refCat, refWcs)
        else:
            taskInitArgs = (afwTable.SourceTable.makeMinimalSchema(), )
            taskRunArgs = ()

        # Activate undeblended measurement with the same configuration
        measConfig.undeblended.names.add(algName)
        measConfig.undeblended[algName] = measConfig.plugins[algName]

        algMetadata = dafBase.PropertyList()
        task = TaskClass(*taskInitArgs,
                         config=measConfig,
                         algMetadata=algMetadata)

        schema = task.schema
        measCat = afwTable.SourceCatalog(schema)
        source = measCat.addNew()
        source.getTable().setMetadata(algMetadata)
        ss = afwDetection.FootprintSet(exposure.getMaskedImage(),
                                       afwDetection.Threshold(0.1))
        fp = ss.getFootprints()[0]
        source.setFootprint(fp)

        task.run(measCat, exposure, *taskRunArgs)

        disp = afwDisplay.Display(frame)
        disp.mtv(exposure)
        disp.dot("x",
                 *center,
                 origin=afwImage.PARENT,
                 title="psfFwhm=%f" % (psfFwhm, ))

        self.checkSchema(schema, algConfig.getAllApertureResultNames())
        self.checkSchema(schema, algConfig.getAllKronResultNames())
        self.checkSchema(schema, algConfig.getAllResultNames())

        if not forced:
            kronRadius = source.get("ext_photometryKron_KronFlux_radius")

        self.assertFalse(source.get(algName + "_flag"))  # algorithm succeeded
        originalSeeing = psfFwhm / scale.asArcseconds()
        for ii, targetSeeing in enumerate(algConfig.seeing):
            deconvolve = targetSeeing < originalSeeing
            seeing = originalSeeing if deconvolve else targetSeeing

            def expected(radius, sigma=seeing / SIGMA_TO_FWHM):
                """Return expected flux for 2D Gaussian with nominated sigma"""
                return flux * (1.0 - math.exp(-0.5 * (radius / sigma)**2))

            for prefix in ("", "undeblended_"):
                self.assertEqual(
                    source.get(prefix + algName + "_%d_deconv" % ii),
                    deconvolve)

                # Kron succeeded and match expectation
                if not forced:
                    kronName = algConfig.getKronResultName(targetSeeing)
                    kronApRadius = algConfig.kronRadiusForFlux * kronRadius
                    self.assertFloatsAlmostEqual(source.get(prefix + kronName +
                                                            "_instFlux"),
                                                 expected(kronApRadius),
                                                 rtol=1.0e-3)
                    self.assertGreater(
                        source.get(prefix + kronName + "_instFluxErr"), 0)
                    self.assertFalse(source.get(prefix + kronName + "_flag"))

                # Aperture measurements succeeded and match expectation
                for jj, radius in enumerate(
                        measConfig.algorithms[algName].aperture.radii):
                    name = algConfig.getApertureResultName(
                        targetSeeing, radius)
                    self.assertFloatsAlmostEqual(source.get(prefix + name +
                                                            "_instFlux"),
                                                 expected(radius),
                                                 rtol=1.0e-3)
                    self.assertFalse(source.get(prefix + name + "_flag"))
                    self.assertGreater(
                        source.get(prefix + name + "_instFluxErr"), 0)