Пример #1
0
    def logSkyMapInfo(self, skyMap):
        """!Log information about a sky map

        @param[in] skyMap  sky map (an lsst.skyMap.SkyMap)
        """
        self.log.info("sky map has %s tracts" % (len(skyMap), ))
        for tractInfo in skyMap:
            wcs = tractInfo.getWcs()
            posBox = geom.Box2D(tractInfo.getBBox())
            pixelPosList = (
                posBox.getMin(),
                geom.Point2D(posBox.getMaxX(), posBox.getMinY()),
                posBox.getMax(),
                geom.Point2D(posBox.getMinX(), posBox.getMaxY()),
            )
            skyPosList = [
                wcs.pixelToSky(pos).getPosition(geom.degrees)
                for pos in pixelPosList
            ]
            posStrList = [
                "(%0.3f, %0.3f)" % tuple(skyPos) for skyPos in skyPosList
            ]
            self.log.info(
                "tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
                (tractInfo.getId(), ", ".join(posStrList),
                 tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
Пример #2
0
 def testAccessors(self):
     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)
     box = geom.Box2D(pmin, pmax, True)
     self.assertEqual(pmin, box.getMin())
     self.assertEqual(pmax, box.getMax())
     self.assertEqual(box.getMinX(), xmin)
     self.assertEqual(box.getMinY(), ymin)
     self.assertEqual(box.getMaxX(), xmax)
     self.assertEqual(box.getMaxY(), ymax)
     self.assertEqual(box.getDimensions(), (pmax - pmin))
     self.assertEqual(box.getWidth(), (xmax - xmin))
     self.assertEqual(box.getHeight(), (ymax - ymin))
     self.assertEqual(box.getArea(), box.getWidth() * box.getHeight())
     self.assertEqual(box.getCenterX(), 0.5 * (pmax.getX() + pmin.getX()))
     self.assertEqual(box.getCenterY(), 0.5 * (pmax.getY() + pmin.getY()))
     self.assertEqual(box.getCenter().getX(), box.getCenterX())
     self.assertEqual(box.getCenter().getY(), box.getCenterY())
     corners = box.getCorners()
     self.assertEqual(corners[0], box.getMin())
     self.assertEqual(corners[1].getX(), box.getMaxX())
     self.assertEqual(corners[1].getY(), box.getMinY())
     self.assertEqual(corners[2], box.getMax())
     self.assertEqual(corners[3].getX(), box.getMinX())
     self.assertEqual(corners[3].getY(), box.getMaxY())
Пример #3
0
    def _validateWcs(self, templateExposure, scienceExposure):
        """Return True if the WCS of the two Exposures have the same origin and extent.
        """
        templateWcs = templateExposure.getWcs()
        scienceWcs = scienceExposure.getWcs()
        templateBBox = templateExposure.getBBox()
        scienceBBox = scienceExposure.getBBox()

        # LLC
        templateOrigin = templateWcs.pixelToSky(geom.Point2D(templateBBox.getBegin()))
        scienceOrigin = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getBegin()))

        # URC
        templateLimit = templateWcs.pixelToSky(geom.Point2D(templateBBox.getEnd()))
        scienceLimit = scienceWcs.pixelToSky(geom.Point2D(scienceBBox.getEnd()))

        self.log.info("Template Wcs : %f,%f -> %f,%f",
                      templateOrigin[0], templateOrigin[1],
                      templateLimit[0], templateLimit[1])
        self.log.info("Science Wcs : %f,%f -> %f,%f",
                      scienceOrigin[0], scienceOrigin[1],
                      scienceLimit[0], scienceLimit[1])

        templateBBox = geom.Box2D(templateOrigin.getPosition(geom.degrees),
                                  templateLimit.getPosition(geom.degrees))
        scienceBBox = geom.Box2D(scienceOrigin.getPosition(geom.degrees),
                                 scienceLimit.getPosition(geom.degrees))
        if not (templateBBox.overlaps(scienceBBox)):
            raise RuntimeError("Input images do not overlap at all")

        if ((templateOrigin != scienceOrigin)
            or (templateLimit != scienceLimit)
                or (templateExposure.getDimensions() != scienceExposure.getDimensions())):
            return False
        return True
Пример #4
0
    def testSymmetry(self):
        """Verify that the projection is symmetrical about the equator
        """
        for minDec in (-5.0, -1.0, 0.5):
            maxDec = minDec + 2.0
            config = EquatSkyMap.ConfigClass()
            config.decRange = minDec, maxDec
            skyMap = EquatSkyMap(config)
            for tractInfo in skyMap[0:1]:
                numPatches = tractInfo.getNumPatches()
                midXIndex = numPatches[0]//2
                minPixelPosList = []
                maxPixelPosList = []
                maxYInd = numPatches[1] - 1
                for xInd in (0, midXIndex, numPatches[0] - 1):
                    minDecPatchInfo = tractInfo.getPatchInfo((xInd, 0))
                    minDecPosBox = geom.Box2D(minDecPatchInfo.getOuterBBox())
                    minPixelPosList += [
                        minDecPosBox.getMin(),
                        geom.Point2D(minDecPosBox.getMaxX(), minDecPosBox.getMinY()),
                    ]

                    maxDecPatchInfo = tractInfo.getPatchInfo((xInd, maxYInd))
                    maxDecPosBox = geom.Box2D(maxDecPatchInfo.getOuterBBox())
                    maxPixelPosList += [
                        maxDecPosBox.getMax(),
                        geom.Point2D(maxDecPosBox.getMinX(), maxDecPosBox.getMaxY()),
                    ]
                wcs = tractInfo.getWcs()
                minDecList = [wcs.pixelToSky(pos).getPosition(geom.degrees)[1] for pos in minPixelPosList]
                maxDecList = [wcs.pixelToSky(pos).getPosition(geom.degrees)[1] for pos in maxPixelPosList]
                self.assertTrue(numpy.allclose(minDecList, minDecList[0]))
                self.assertTrue(numpy.allclose(maxDecList, maxDecList[0]))
                self.assertTrue(minDecList[0] <= minDec)
                self.assertTrue(maxDecList[0] >= maxDec)
Пример #5
0
    def logSkyMapInfo(self, log):
        """Write information about a sky map to supplied log

        Parameters
        ----------
        log : `lsst.log.Log`
            Log object that information about skymap will be written
        """
        log.info("sky map has %s tracts" % (len(self), ))
        for tractInfo in self:
            wcs = tractInfo.getWcs()
            posBox = geom.Box2D(tractInfo.getBBox())
            pixelPosList = (
                posBox.getMin(),
                geom.Point2D(posBox.getMaxX(), posBox.getMinY()),
                posBox.getMax(),
                geom.Point2D(posBox.getMinX(), posBox.getMaxY()),
            )
            skyPosList = [
                wcs.pixelToSky(pos).getPosition(geom.degrees)
                for pos in pixelPosList
            ]
            posStrList = [
                "(%0.3f, %0.3f)" % tuple(skyPos) for skyPos in skyPosList
            ]
            log.info(
                "tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
                (tractInfo.getId(), ", ".join(posStrList),
                 tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
Пример #6
0
 def testConversion(self):
     for n in range(10):
         xmin, xmax, ymin, ymax = np.random.uniform(low=-10,
                                                    high=10,
                                                    size=4)
         if xmin > xmax:
             xmin, xmax = xmax, xmin
         if ymin > ymax:
             ymin, ymax = ymax, ymin
         fpMin = geom.Point2D(xmin, ymin)
         fpMax = geom.Point2D(xmax, ymax)
         if any((fpMax - fpMin).lt(3)):
             continue  # avoid empty boxes
         with self.subTest(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax):
             fpBox = geom.Box2D(fpMin, fpMax)
             intBoxBig = geom.Box2I(fpBox, geom.Box2I.EXPAND)
             fpBoxBig = geom.Box2D(intBoxBig)
             intBoxSmall = geom.Box2I(fpBox, geom.Box2I.SHRINK)
             fpBoxSmall = geom.Box2D(intBoxSmall)
             self.assertTrue(fpBoxBig.contains(fpBox))
             self.assertTrue(fpBox.contains(fpBoxSmall))
             self.assertTrue(intBoxBig.contains(intBoxSmall))
             self.assertTrue(geom.Box2D(intBoxBig))
             self.assertEqual(geom.Box2I(fpBoxBig, geom.Box2I.SHRINK),
                              intBoxBig)
             self.assertEqual(geom.Box2I(fpBoxSmall, geom.Box2I.SHRINK),
                              intBoxSmall)
     self.assertTrue(geom.Box2I(geom.Box2D()).isEmpty())
     self.assertRaises(
         lsst.pex.exceptions.InvalidParameterError, geom.Box2I,
         geom.Box2D(geom.Point2D(), geom.Point2D(float("inf"),
                                                 float("inf"))))
def get_amp_patches(det, amps=None):
    """
    Return a list of Rectangle patches in focalplane coordinates
    corresponding to the amplifier segments in a detector object.

    Parameters
    ----------
    det: `lsst.afw.cameraGeom.detector.detector.Detector`
        Detector object.
    amps: container-type object [None]
        Python container that can be queried like `'C01 in amps'`
        to see if a particular channel is included for plotting.
        If None, then use all channels in det.

    Returns
    -------
    list of matplotlib.patches.Rectangle objects
    """
    transform = det.getTransform(cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE)
    bbox = list(det)[0].getBBox()
    dy, dx = bbox.getHeight(), bbox.getWidth()
    patches = []
    for amp in det:
        if amps is not None and amp.getName() not in amps:
            continue
        j, i = tuple(int(_) for _ in amp.getName()[1:])
        y, x = j * dy, i * dx
        x0, y0 = transform.applyForward(lsstGeom.Point2D(x, y))
        x1, y1 = transform.applyForward(lsstGeom.Point2D(x + dx, y + dy))
        patches.append(Rectangle((x0, y0), x1 - x0, y1 - y0))
    return patches
Пример #8
0
def reportSkyMapInfo(skyMap):
    paramDict = skyMap.config.toDict()
    paramNameList = sorted(paramDict)
    print("Sky Map parameters:")
    for paramName in paramNameList:
        param = paramDict[paramName]
        print("skyMap.config.%s = %s" % (paramName, param))

    print("\nSkyMap has %d tracts:" % (len(skyMap)))
    for tractInfo in skyMap:
        wcs = tractInfo.getWcs()
        posBox = geom.Box2D(tractInfo.getBBox())
        pixelPosList = (
            posBox.getMin(),
            geom.Point2D(posBox.getMaxX(), posBox.getMinY()),
            posBox.getMax(),
            geom.Point2D(posBox.getMinX(), posBox.getMaxY()),
        )
        skyPosList = [
            wcs.pixelToSky(pos).getPosition(geom.degrees)
            for pos in pixelPosList
        ]
        posStrList = [
            "(%0.3f, %0.3f)" % tuple(skyPos) for skyPos in skyPosList
        ]
        print("tract %s has corners %s (RA, Dec deg) and %s x %s patches" %
              (tractInfo.getId(), ", ".join(posStrList),
               tractInfo.getNumPatches()[0], tractInfo.getNumPatches()[1]))
Пример #9
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)
    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
Пример #11
0
    def addCcd(self, exposure):
        """Add CCD to model

        We measure the background on the CCD (clipped mean), and record
        the results in the model.  For simplicity, measurements are made
        in a box on the CCD corresponding to the warped coordinates of the
        superpixel rather than accounting for little rotations, etc.
        We also record the number of pixels used in the measurement so we
        can have a measure of confidence in each bin's value.

        Parameters
        ----------
        exposure : `lsst.afw.image.Exposure`
            CCD exposure to measure
        """
        detector = exposure.getDetector()
        transform = detector.getTransformMap().getTransform(
            detector.makeCameraSys(afwCameraGeom.PIXELS),
            detector.makeCameraSys(afwCameraGeom.FOCAL_PLANE))
        image = exposure.getMaskedImage()
        maskVal = image.getMask().getPlaneBitMask(self.config.mask)

        # Warp the binned image to the focal plane
        toSample = transform.then(
            self.transform)  # CCD pixels --> focal plane --> sample

        warped = afwImage.ImageF(self._values.getBBox())
        warpedCounts = afwImage.ImageF(self._numbers.getBBox())
        width, height = warped.getDimensions()

        stats = afwMath.StatisticsControl()
        stats.setAndMask(maskVal)
        stats.setNanSafe(True)
        # Iterating over individual pixels in python is usually bad because it's slow, but there aren't many.
        pixels = itertools.product(range(width), range(height))
        for xx, yy in pixels:
            llc = toSample.applyInverse(geom.Point2D(xx - 0.5, yy - 0.5))
            urc = toSample.applyInverse(geom.Point2D(xx + 0.5, yy + 0.5))
            bbox = geom.Box2I(geom.Point2I(llc), geom.Point2I(urc))
            bbox.clip(image.getBBox())
            if bbox.isEmpty():
                continue
            subImage = image.Factory(image, bbox)
            result = afwMath.makeStatistics(subImage,
                                            afwMath.MEANCLIP | afwMath.NPOINT,
                                            stats)
            mean = result.getValue(afwMath.MEANCLIP)
            num = result.getValue(afwMath.NPOINT)
            if not numpy.isfinite(mean) or not numpy.isfinite(num):
                continue
            warped[xx, yy, afwImage.LOCAL] = mean * num
            warpedCounts[xx, yy, afwImage.LOCAL] = num

        self._values += warped
        self._numbers += warpedCounts
Пример #12
0
    def maskVignetting(self, mask, detector):
        """Mask vignetted pixels in-place

        @param mask: Mask image to modify
        @param detector: Detector for transformation to focal plane coords
        """
        mask.addMaskPlane(self.config.maskPlane)
        bitMask = mask.getPlaneBitMask(self.config.maskPlane)
        bbox = mask.getBBox(afwImage.LOCAL)
        w, h = bbox.getDimensions()
        numCorners = 0  # Number of corners outside radius
        pixelsToFocalPlane = detector.getTransform(afwcg.PIXELS,
                                                   afwcg.FOCAL_PLANE)
        pixelCorners = [geom.Point2D(pos) for pos in bbox.getCorners()]
        fpCorners = pixelsToFocalPlane.applyForward(pixelCorners)
        fpCenter = geom.Point2D(self.config.vignette.xCenter,
                                self.config.vignette.yCenter)
        numCorners = sum(
            math.hypot(*(fpPos - fpCenter)) > self.config.vignette.radius
            for fpPos in fpCorners)
        if numCorners == 0:
            # Nothing to be masked
            self.log.info("Detector %d is unvignetted", detector.getId())
            return
        if numCorners == 4:
            # Everything to be masked
            # We ignore the question of how we're getting any data from a CCD
            # that's totally vignetted...
            self.log.warning("Detector %d is completely vignetted",
                             detector.getId())
            mask |= bitMask
            return
        # We have to go pixel by pixel
        numPixels = bbox.getArea()
        xx, yy = np.meshgrid(np.arange(0, w, dtype=int),
                             np.arange(0, h, dtype=int))
        xyDetector = [
            geom.Point2D(x, y)
            for x, y in zip(xx.reshape(numPixels), yy.reshape(numPixels))
        ]
        xyFocalPlane = pixelsToFocalPlane.applyForward(xyDetector)
        origin = geom.Point2D(self.config.vignette.xCenter,
                              self.config.vignette.yCenter)
        r2 = np.array([pp.distanceSquared(origin) for pp in xyFocalPlane])
        isBad = (r2 > self.config.vignette.radius**2).reshape((h, w))
        self.log.info("Detector %d has %f%% pixels vignetted",
                      detector.getId(),
                      isBad.sum() / float(isBad.size) * 100.0)
        maskArray = mask.getArray()
        maskArray[yy[isBad], xx[isBad]] |= bitMask
Пример #13
0
    def __init__(self, config=None):
        BaseSkyMap.__init__(self, config)

        decRange = tuple(geom.Angle(dr, geom.degrees) for dr in self.config.decRange)
        midDec = (decRange[0] + decRange[1]) / 2.0
        tractWidthRA = geom.Angle(360.0 / self.config.numTracts, geom.degrees)
        tractOverlap = geom.Angle(self.config.tractOverlap, geom.degrees)

        for id in range(self.config.numTracts):
            begRA = tractWidthRA * id
            endRA = begRA + tractWidthRA
            vertexCoordList = (
                geom.SpherePoint(begRA, decRange[0]),
                geom.SpherePoint(endRA, decRange[0]),
                geom.SpherePoint(endRA, decRange[1]),
                geom.SpherePoint(begRA, decRange[1]),
            )

            midRA = begRA + tractWidthRA / 2.0
            ctrCoord = geom.SpherePoint(midRA, midDec)

            # CRVal must have Dec=0 for symmetry about the equator
            crValCoord = geom.SpherePoint(midRA, geom.Angle(0.0))

            # make initial WCS; don't worry about crPixPos because TractInfo will shift it as required
            wcs = self._wcsFactory.makeWcs(crPixPos=geom.Point2D(0, 0), crValCoord=crValCoord)

            self._tractInfoList.append(TractInfo(
                id=id,
                tractBuilder=self._tractBuilder,
                ctrCoord=ctrCoord,
                vertexCoordList=vertexCoordList,
                tractOverlap=tractOverlap,
                wcs=wcs,
            ))
Пример #14
0
    def _makeStarImage(self,
                       xc=[15.3],
                       yc=[18.6],
                       flux=[2500],
                       schema=None,
                       randomSeed=None):
        """Generate an exposure and catalog with the given stellar source(s).
        """
        from lsst.meas.base.tests import TestDataset
        bbox = geom.Box2I(geom.Point2I(0, 0),
                          geom.Point2I(self.w - 1, self.h - 1))
        dataset = TestDataset(bbox, psfSigma=self.psfSigma, threshold=1.)

        for i in range(len(xc)):
            dataset.addSource(instFlux=flux[i],
                              centroid=geom.Point2D(xc[i], yc[i]))

        if schema is None:
            schema = TestDataset.makeMinimalSchema()
        exposure, catalog = dataset.realize(noise=self.noise,
                                            schema=schema,
                                            randomSeed=randomSeed)

        if self.gradientParams is not None:
            y, x = np.mgrid[:self.w, :self.h]
            gp = self.gradientParams
            gradient = gp[0] + gp[1] * x + gp[2] * y
            if len(self.gradientParams
                   ) > 3:  # it includes a set of 2nd-order polynomial params
                gradient += gp[3] * x * y + gp[4] * x * x + gp[5] * y * y
            imgArr = exposure.getMaskedImage().getArrays()[0]
            imgArr += gradient

        return exposure, catalog
Пример #15
0
    def _testCoaddPsf(self, newExposure):
        """Test that the new CoaddPsf of the `newExposure` returns PSF images
        ~identical to the input PSF of `self.exposure` across a grid
        covering the entire exposure bounding box.
        """
        origPsf = self.exposure.getPsf()
        newPsf = newExposure.getPsf()
        self.assertTrue(isinstance(newPsf, measAlg.CoaddPsf))
        extentX = int(self.exposure.getWidth()*0.05)
        extentY = int(self.exposure.getHeight()*0.05)
        for x in np.linspace(extentX, self.exposure.getWidth()-extentX, 10):
            for y in np.linspace(extentY, self.exposure.getHeight()-extentY, 10):
                point = geom.Point2D(np.rint(x), np.rint(y))
                oPsf = origPsf.computeImage(point).getArray()
                nPsf = newPsf.computeImage(point).getArray()
                if oPsf.shape[0] < nPsf.shape[0]:  # sometimes CoaddPsf does this.
                    oPsf = np.pad(oPsf, ((1, 1), (0, 0)), mode='constant')
                elif oPsf.shape[0] > nPsf.shape[0]:
                    nPsf = np.pad(nPsf, ((1, 1), (0, 0)), mode='constant')
                if oPsf.shape[1] < nPsf.shape[1]:  # sometimes CoaddPsf does this.
                    oPsf = np.pad(oPsf, ((0, 0), (1, 1)), mode='constant')
                elif oPsf.shape[1] > nPsf.shape[1]:
                    nPsf = np.pad(nPsf, ((0, 0), (1, 1)), mode='constant')
                # pixel-wise comparison -- pretty stringent
                self.assertFloatsAlmostEqual(oPsf, nPsf, atol=1e-4, msg='Failed on Psf')

                origMmts = np.array(getPsfSecondMoments(oPsf))
                newMmts = np.array(getPsfSecondMoments(nPsf))
                self.assertFloatsAlmostEqual(origMmts, newMmts, atol=1e-4, msg='Failed on Psf')
Пример #16
0
    def ampPixelToFocalMm(self, ampX, ampY, channel, detectorName=None):
        r"""Given position within an amplifier return the focal plane position

        ampX : `int`
           column on amp segment
        ampY : `int`
           row on amp segment
        channel: `int`
           Channel number of amplifier (1-indexed; identical to HDU)
        detectorName : `str`
           Name of detector (or default from setDetectorName() if None)

        N.b. all pixel coordinates have the centre of the bottom-left pixel
        at (0.0, 0.0), and CCD columns are taken to be vertical, with "R00"
        in the bottom left of the image

        Returns
        -------
        focalPlaneX : `float`
           The x-focal plane position (mm) relative to the centre of the camera
        focalPlaneY : `float`
           The y-focal plane position (mm) relative to the centre of the camera

        Raises
        ------
        RuntimeError
            If the requested pixel doesn't lie on the detector
        """

        detector = self.getDetector(detectorName)

        ccdX, ccdY = ampPixelToCcdPixel(ampX, ampY, detector, channel)

        return detector.transform(geom.Point2D(ccdX, ccdY), cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE)
Пример #17
0
    def ccdPixelToFocalMm(self, ccdX, ccdY, detectorName=None):
        r"""Given position within a detector return the focal plane position

        Parameters
        ----------
        ccdX : `int`
           column pixel position within detector
        ccdY : `int`
           row pixel position within detector
        detectorName : `str`
           Name of detector (or default from setDetectorName() if None)

        N.b. all pixel coordinates have the centre of the bottom-left pixel
        at (0.0, 0.0), and CCD columns are taken to be vertical, with "R00"
        in the bottom left of the image

        Returns
        -------
        focalPlaneX : `float`
           The x-focal plane position (mm) relative to the centre of the camera
        focalPlaneY : `float`
           The y-focal plane position (mm) relative to the centre of the camera
        """
        detector = self.getDetector(detectorName)

        return detector.transform(geom.Point2D(ccdX, ccdY), cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE)
Пример #18
0
    def getReferences(self, butler, exposure):
        """!
        Get reference catalogs from all patch,tract combinations that overlaps this exposure

        This method will filter out any rferences that are not in the inner tract,patch region
        so that there will be no duplicates across boundaries.
        @param[in]  butler     An lsst.daf.persistence.Butler.  This is used to get
                               the references
        @param[in]  exposure   A deepDiff_exposure on which to run the measurements

        @return    Dictionary of tract, reference catalogs

        """
        skyMap = butler.get(f"{self.config.coaddName}Coadd_skyMap")

        wcs = exposure.getWcs()
        imagePixelCorners = exposure.getBBox().getCorners()
        imageSkyCorners = [wcs.pixelToSky(geom.Point2D(a)) for a in imagePixelCorners]

        # get initial list of tracts and patches
        tractList = skyMap.findTractPatchList(imageSkyCorners)

        tractRefCat = dict()
        for tract, patchList in tractList:
            usePatchList = []
            for patch in patchList:
                patchPoly = patch.getInnerSkyPolygon(tract.getWcs())
                imagePoly = sphgeom.ConvexPolygon.convexHull([coord.getVector() for coord in imageSkyCorners])
                if patchPoly.intersects(imagePoly):
                    usePatchList.append(patch)

            refCat = self.fetchInPatches(butler, exposure, tract, usePatchList)
            tractRefCat[tract] = refCat

        return tractRefCat
Пример #19
0
 def generateTract(self, index):
     """Generate TractInfo for the specified tract index."""
     center = geom.SpherePoint(self.config.raList[index], self.config.decList[index], geom.degrees)
     radius = self.config.radiusList[index]
     wcs = self._wcsFactory.makeWcs(crPixPos=geom.Point2D(0, 0), crValCoord=center)
     return ExplicitTractInfo(index, self.config.patchInnerDimensions, self.config.patchBorder, center,
                              radius*geom.degrees, self.config.tractOverlap*geom.degrees, wcs)
Пример #20
0
    def setUp(self):

        nSources = 10
        # CFHT Filters from the camera mapper.
        afwImageUtils.resetFilters()
        afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301")
        afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401")
        afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601")
        afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701")
        afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801")

        self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(1024, 1153))
        dataset = measTests.TestDataset(self.bbox)
        for srcIdx in range(nSources):
            dataset.addSource(100000.0, geom.Point2D(100, 100))
        self.inputCatalogNoFlags, _ = make_input_source_catalog(dataset, False)
        self.inputCatalog, self.exposure = \
            make_input_source_catalog(dataset, True)

        detector = DetectorWrapper(id=23,
                                   bbox=self.exposure.getBBox()).detector
        visit = afwImage.VisitInfo(exposureId=4321,
                                   exposureTime=200.,
                                   date=dafBase.DateTime(nsecs=1400000000 *
                                                         10**9))
        self.exposure.setDetector(detector)
        self.exposure.getInfo().setVisitInfo(visit)
        self.exposure.setFilter(afwImage.Filter('g.MP9401'))
        scale = 2
        scaleErr = 1
        self.photoCalib = afwImage.PhotoCalib(scale, scaleErr)
        self.exposure.setPhotoCalib(self.photoCalib)
Пример #21
0
def test_ps_dmpsf_smoke():
    rng = np.random.RandomState(7812)
    dim = 20
    masked_image = afw_image.MaskedImageF(dim, dim)
    exp = afw_image.ExposureF(masked_image)

    psf_dim = 15
    wcs = make_sim_wcs(dim)

    pspsf = make_ps_psf(rng=rng, dim=dim)
    fpsf = make_dm_psf(psf=pspsf, psf_dim=psf_dim, wcs=wcs)
    exp.setPsf(fpsf)

    psf = exp.getPsf()

    x = 8.5
    y = 10.1
    pos = geom.Point2D(x=x, y=y)
    gs_pos = galsim.PositionD(x=x, y=y)

    # this one is always centered
    msim = psf.computeKernelImage(pos)
    assert msim.array.shape == (psf_dim, psf_dim)

    gspsf = pspsf.getPSF(gs_pos)
    gsim = gspsf.drawImage(
        nx=psf_dim,
        ny=psf_dim,
        wcs=wcs.local(image_pos=gs_pos),
    )

    assert np.allclose(msim.array, gsim.array)
Пример #22
0
    def subtractStars(self, exposure, catalog, chi_lim=-1):
        """Subtract the exposure's PSF from all the sources in catalog"""
        mi, psf = exposure.getMaskedImage(), exposure.getPsf()

        subtracted = mi.Factory(mi, True)
        for s in catalog:
            xc, yc = s.getX(), s.getY()
            bbox = subtracted.getBBox(afwImage.PARENT)
            if bbox.contains(geom.PointI(int(xc), int(yc))):
                try:
                    measAlg.subtractPsf(psf, subtracted, xc, yc)
                except Exception:
                    pass
        chi = subtracted.Factory(subtracted, True)
        var = subtracted.getVariance()
        np.sqrt(var.getArray(), var.getArray())  # inplace sqrt
        chi /= var

        if display:
            afwDisplay.Display(frame=1).mtv(subtracted, title="Subtracted")
            afwDisplay.Display(frame=2).mtv(chi, title="Chi")
            xc, yc = exposure.getWidth() // 2, exposure.getHeight() // 2
            afwDisplay.Display(frame=3).mtv(psf.computeImage(
                geom.Point2D(xc, yc)),
                                            title="Psf %.1f,%.1f" % (xc, yc))

        chi_min, chi_max = np.min(chi.getImage().getArray()), np.max(
            chi.getImage().getArray())
        if False:
            print(chi_min, chi_max)

        if chi_lim > 0:
            self.assertGreater(chi_min, -chi_lim)
            self.assertLess(chi_max, chi_lim)
Пример #23
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])
Пример #24
0
    def __init__(self, config=None):
        BaseSkyMap.__init__(self, config)
        self._dodecahedron = detail.Dodecahedron(
            withFacesOnPoles=self.config.withTractsOnPoles)

        tractOverlap = geom.Angle(self.config.tractOverlap, geom.degrees)

        for id in range(12):
            tractVec = self._dodecahedron.getFaceCtr(id)
            tractCoord = detail.coordFromVec(tractVec, defRA=geom.Angle(0))
            tractRA = tractCoord.getLongitude()
            vertexVecList = self._dodecahedron.getVertices(id)

            # make initial WCS; don't worry about crPixPos because TractInfo will shift it as required
            wcs = self._wcsFactory.makeWcs(crPixPos=geom.Point2D(0, 0),
                                           crValCoord=tractCoord)

            self._tractInfoList.append(
                TractInfo(
                    id=id,
                    tractBuilder=self._tractBuilder,
                    ctrCoord=tractCoord,
                    vertexCoordList=[
                        detail.coordFromVec(vec, defRA=tractRA)
                        for vec in vertexVecList
                    ],
                    tractOverlap=tractOverlap,
                    wcs=wcs,
                ))
Пример #25
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 = geom.Box2I(geom.Point2I(0, 0), geom.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(geom.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)
Пример #26
0
def pupilCoordsFromFocalPlaneCoords(xFocal, yFocal, camera=None):
    """
    Get the pupil coordinates in radians from the focal plane
    coordinates in millimeters

    @param [in] xFocal the x focal plane coordinates in millimeters.
    Can be a float or a numpy array.

    @param [in] yFocal the y focal plane coordinates in millimeters.
    Can be a float or a numpy array.

    @param [in] camera is an afw.cameraGeom camera object

    @param [out] a 2-D numpy array in which the first row is the x
    pupil coordinate and the second row is the y pupil
    coordinate (both in radians)
    """

    are_arrays = _validate_inputs([xFocal, yFocal], ['xFocal', 'yFocal'],
                                  'pupilCoordsFromFocalPlaneCoords')

    if camera is None:
        raise RuntimeError(
            "You cannot calculate pupil coordinates without specifying a camera"
        )

    focal_to_field = camera.getTransformMap().getTransform(
        FOCAL_PLANE, FIELD_ANGLE)

    if are_arrays:
        focal_point_list = [geom.Point2D(x, y) for x, y in zip(xFocal, yFocal)]
        pupil_point_list = focal_to_field.applyForward(focal_point_list)
        pupil_arr = np.array([[pp.getX(), pp.getY()]
                              for pp in pupil_point_list]).transpose()
        is_nan = np.where(np.logical_or(np.isnan(xFocal), np.isnan(yFocal)))
        pupil_arr[0][is_nan] = np.NaN
        pupil_arr[1][is_nan] = np.NaN

        return pupil_arr

    # if not are_arrays
    if np.isfinite(xFocal) and np.isfinite(yFocal):
        pupPoint = focal_to_field.applyForward(geom.Point2D(xFocal, yFocal))
        return np.array([pupPoint.getX(), pupPoint.getY()])

    return np.array([np.NaN, np.NaN])
Пример #27
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)
Пример #28
0
def bboxToRaDec(bbox, wcs):
    """Get the corners of a BBox and convert them to lists of RA and Dec."""
    corners = []
    for corner in bbox.getCorners():
        p = geom.Point2D(corner.getX(), corner.getY())
        coord = wcs.pixelToSky(p)
        corners.append([coord.getRa().asDegrees(), coord.getDec().asDegrees()])
    ra, dec = zip(*corners)
    return ra, dec
Пример #29
0
 def generateTract(self, index):
     """Generate TractInfo for the specified tract index."""
     center = angToCoord(
         healpy.pix2ang(self._nside, index, nest=self.config.nest))
     wcs = self._wcsFactory.makeWcs(crPixPos=geom.Point2D(0, 0),
                                    crValCoord=center)
     return HealpixTractInfo(self._nside, index, self.config.nest,
                             self._tractBuilder, center,
                             self.config.tractOverlap * geom.degrees, wcs)
Пример #30
0
    def mkFakeStars(self, fakeCat, band, photoCalib, psf, image):
        """Make fake stars based off the properties in the fakeCat.

        Parameters
        ----------
        band : `str`
        psf : `lsst.meas.extensions.psfex.psfexPsf.PsfexPsf`
                    The PSF information to use to make the PSF images
        fakeCat : `pandas.core.frame.DataFrame`
                    The catalog of fake sources to be input
        image : `lsst.afw.image.exposure.exposure.ExposureF`
                    The image into which the fake sources should be added
        photoCalib : `lsst.afw.image.photoCalib.PhotoCalib`
                    Photometric calibration to be used to calibrate the fake sources

        Yields
        -------
        starImages : `generator`
                    A generator of tuples of `lsst.afw.image.ImageF` of fake stars and
                    `lsst.geom.Point2D` of their locations.

        Notes
        -----
        To take a given magnitude and translate to the number of counts in the image
        we use photoCalib.magnitudeToInstFlux, which returns the instrumental flux for the
        given calibration radius used in the photometric calibration step.
        Thus `calibFluxRadius` should be set to this same radius so that we can normalize
        the PSF model to the correct instrumental flux within calibFluxRadius.
        """

        self.log.info("Making %d fake star images" % len(fakeCat))

        for (index, row) in fakeCat.iterrows():
            xy = geom.Point2D(row["x"], row["y"])

            # We put these two PSF calculations within this same try block so that we catch cases
            # where the object's position is outside of the image.
            try:
                correctedFlux = psf.computeApertureFlux(
                    self.config.calibFluxRadius, xy)
                starIm = psf.computeImage(xy)
                starIm /= correctedFlux

            except InvalidParameterError:
                self.log.info("Star at %0.4f, %0.4f outside of image" %
                              (row["x"], row["y"]))
                continue

            try:
                flux = photoCalib.magnitudeToInstFlux(
                    row[self.config.magVar % band], xy)
            except LogicError:
                flux = 0

            starIm *= flux
            yield ((starIm.convertF(), xy))