def testTransform(self):
        """Test pixelToSky, skyToPixel, getTanWcs and getPixelToTanPixel
        """
        pixelsToTanPixels = afwGeom.RadialXYTransform([0, 1.001, 0.00003])
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs, pixelsToTanPixels)
        tanWcsCopy = distortedWcs.getTanWcs()
        pixToTanCopy = distortedWcs.getPixelToTanPixel()

        for x in (0, 1000, 5000):
            for y in (0, 560, 2000):
                pixPos = afwGeom.Point2D(x, y)
                tanPixPos = pixelsToTanPixels.forwardTransform(pixPos)

                tanPixPosCopy = pixToTanCopy.forwardTransform(pixPos)
                self.assertEqual(tanPixPos, tanPixPosCopy)

                predSky = self.tanWcs.pixelToSky(tanPixPos)
                predSkyCopy = tanWcsCopy.pixelToSky(tanPixPos)
                self.assertEqual(predSky, predSkyCopy)

                measSky = distortedWcs.pixelToSky(pixPos)
                self.assertLess(
                    predSky.angularSeparation(measSky).asRadians(), 1e-7)

                pixPosRoundTrip = distortedWcs.skyToPixel(measSky)
                for i in range(2):
                    self.assertAlmostEqual(pixPos[i], pixPosRoundTrip[i])
Example #2
0
    def testLargeDistortion(self):
        # This transform is about as extreme as I can get:
        # using 0.0005 in the last value appears to produce numerical issues.
        # It produces a maximum deviation of 459 pixels, which should be sufficient.
        pixelsToTanPixels = afwGeom.RadialXYTransform([0.0, 1.1, 0.0004])
        self.distortedWcs = afwImage.DistortedTanWcs(self.wcs,
                                                     pixelsToTanPixels)

        def applyDistortion(src):
            out = src.table.copyRecord(src)
            out.set(out.table.getCentroidKey(),
                    pixelsToTanPixels.reverseTransform(src.getCentroid()))
            return out

        self.singleTestInstance(self.filename, applyDistortion)
    def testUsedFlag(self):
        """Test that the solver will record number of sources used to table
           if it is passed a schema on initialization.
        """
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs,
                                                afwGeom.IdentityXYTransform())
        self.exposure.setWcs(distortedWcs)
        loadRes = self.refObjLoader.loadPixelBox(bbox=self.bbox,
                                                 wcs=distortedWcs,
                                                 filterName="r")
        refCat = loadRes.refCat
        refCentroidKey = afwTable.Point2DKey(refCat.schema["centroid"])
        refFluxRKey = refCat.schema["r_flux"].asKey()

        sourceSchema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(
            schema=sourceSchema)  # expand the schema
        config = AstrometryTask.ConfigClass()
        config.wcsFitter.order = 2
        config.wcsFitter.numRejIter = 0
        # schema must be passed to the solver task constructor
        solver = AstrometryTask(config=config,
                                refObjLoader=self.refObjLoader,
                                schema=sourceSchema)
        sourceCat = afwTable.SourceCatalog(sourceSchema)
        sourceCentroidKey = afwTable.Point2DKey(sourceSchema["slot_Centroid"])
        sourceFluxKey = sourceSchema["slot_ApFlux_flux"].asKey()
        sourceFluxSigmaKey = sourceSchema["slot_ApFlux_fluxSigma"].asKey()

        for refObj in refCat:
            src = sourceCat.addNew()
            src.set(sourceCentroidKey, refObj.get(refCentroidKey))
            src.set(sourceFluxKey, refObj.get(refFluxRKey))
            src.set(sourceFluxSigmaKey, refObj.get(refFluxRKey) / 100)

        results = solver.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        # check that the used flag is set the right number of times
        count = 0
        for source in sourceCat:
            if source.get('calib_astrometryUsed'):
                count += 1
        self.assertEqual(count, len(results.matches))
    def testBasics(self):
        pixelsToTanPixels = afwGeom.RadialXYTransform([0, 1.001, 0.00003])
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs, pixelsToTanPixels)
        tanWcsCopy = distortedWcs.getTanWcs()

        self.assertEqual(self.tanWcs, tanWcsCopy)
        self.assertFalse(self.tanWcs.hasDistortion())
        self.assertTrue(distortedWcs.hasDistortion())
        try:
            self.tanWcs == distortedWcs
            self.fail("== should not be implemented for DistortedTanWcs")
        except Exception:
            pass
        try:
            distortedWcs == self.tanWcs
            self.fail("== should not be implemented for DistortedTanWcs")
        except Exception:
            pass
Example #5
0
    def doTest(self, name, xyTransform, order=3, doPlot=False):
        """Create a DistortedTanWcs from the specified transform and fit it
        """
        wcs = afwImage.DistortedTanWcs(self.tanWcs, xyTransform)

        fitWcs = approximateWcs(
            wcs=wcs,
            bbox=self.bbox,
            order=order,
        )

        if doPlot:
            self.plotWcs(wcs, fitWcs, self.bbox, xyTransform)

        msg = "ERROR: %s failed with order %s" % (name, order)
        self.assertWcsAlmostEqualOverBBox(wcs,
                                          fitWcs,
                                          self.bbox,
                                          maxDiffSky=0.001 *
                                          afwGeom.arcseconds,
                                          maxDiffPix=0.02,
                                          msg=msg)
Example #6
0
 def testWarnings(self):
     """Test that approximateWcs raises a UserWarning when it cannot achieve desired tolerance"""
     radialTransform = afwGeom.RadialXYTransform([0, 2.0, 3.0])
     wcs = afwImage.DistortedTanWcs(self.tanWcs, radialTransform)
     with self.assertRaises(UserWarning):
         approximateWcs(wcs=wcs, bbox=self.bbox, order=2)
    def testGetDistortedWcs(self):
        """Test utils.getDistortedWcs
        """
        dw = DetectorWrapper()
        detector = dw.detector

        # the standard case: the exposure's WCS is pure TAN WCS and distortion information is available;
        # return a DistortedTanWcs
        exposure = afwImage.ExposureF(10, 10)
        exposure.setDetector(detector)
        exposure.setWcs(self.tanWcs)
        self.assertFalse(self.tanWcs.hasDistortion())
        outWcs = getDistortedWcs(exposure.getInfo())
        self.assertTrue(outWcs.hasDistortion())
        self.assertIsInstance(outWcs, afwImage.DistortedTanWcs)
        del exposure  # avoid accidental reuse
        del outWcs

        # return the original WCS if the exposure's WCS has distortion
        pixelsToTanPixels = afwGeom.RadialXYTransform([0, 1.001, 0.00003])
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs, pixelsToTanPixels)
        self.assertTrue(distortedWcs.hasDistortion())
        exposure = afwImage.ExposureF(10, 10)
        exposure.setWcs(distortedWcs)
        exposure.setDetector(detector)
        outWcs = getDistortedWcs(exposure.getInfo())
        self.assertTrue(outWcs.hasDistortion())
        self.assertIsInstance(outWcs, afwImage.DistortedTanWcs)
        del exposure
        del distortedWcs
        del outWcs

        # raise an exception if exposure has no WCS
        exposure = afwImage.ExposureF(10, 10)
        exposure.setDetector(detector)
        with self.assertRaises(Exception):
            getDistortedWcs(exposure.getInfo())
        del exposure

        # return the original pure TAN WCS if the exposure has no detector
        exposure = afwImage.ExposureF(10, 10)
        exposure.setWcs(self.tanWcs)
        outWcs = getDistortedWcs(exposure.getInfo())
        self.assertFalse(outWcs.hasDistortion())
        self.assertIsInstance(outWcs, afwImage.TanWcs)
        self.assertNotIsInstance(outWcs, afwImage.DistortedTanWcs)
        del exposure
        del outWcs

        # return the original pure TAN WCS if the exposure's detector has no
        # TAN_PIXELS transform
        def removeTanPixels(detectorWrapper):
            tanPixSys = detector.makeCameraSys(TAN_PIXELS)
            detectorWrapper.transMap.pop(tanPixSys)

        detectorNoTanPix = DetectorWrapper(modFunc=removeTanPixels).detector
        exposure = afwImage.ExposureF(10, 10)
        exposure.setWcs(self.tanWcs)
        exposure.setDetector(detectorNoTanPix)
        outWcs = getDistortedWcs(exposure.getInfo())
        self.assertFalse(outWcs.hasDistortion())
        self.assertIsInstance(outWcs, afwImage.TanWcs)
        self.assertNotIsInstance(outWcs, afwImage.DistortedTanWcs)
        del exposure
        del outWcs
    def doTest(self, pixelsToTanPixels, order=3):
        """Test using pixelsToTanPixels to distort the source positions
        """
        distortedWcs = afwImage.DistortedTanWcs(self.tanWcs, pixelsToTanPixels)
        self.exposure.setWcs(distortedWcs)
        sourceCat = self.makeSourceCat(distortedWcs)
        config = AstrometryTask.ConfigClass()
        config.wcsFitter.order = order
        config.wcsFitter.numRejIter = 0
        solver = AstrometryTask(config=config, refObjLoader=self.refObjLoader)
        results = solver.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        fitWcs = self.exposure.getWcs()
        self.assertRaises(Exception, self.assertWcsAlmostEqualOverBBox, fitWcs,
                          distortedWcs)
        self.assertWcsAlmostEqualOverBBox(distortedWcs,
                                          fitWcs,
                                          self.bbox,
                                          maxDiffSky=0.01 * afwGeom.arcseconds,
                                          maxDiffPix=0.02)

        srcCoordKey = afwTable.CoordKey(sourceCat.schema["coord"])
        refCoordKey = afwTable.CoordKey(results.refCat.schema["coord"])
        refCentroidKey = afwTable.Point2DKey(results.refCat.schema["centroid"])
        maxAngSep = afwGeom.Angle(0)
        maxPixSep = 0
        for refObj, src, d in results.matches:
            refCoord = refObj.get(refCoordKey)
            refPixPos = refObj.get(refCentroidKey)
            srcCoord = src.get(srcCoordKey)
            srcPixPos = src.getCentroid()

            angSep = refCoord.angularSeparation(srcCoord)
            maxAngSep = max(maxAngSep, angSep)

            pixSep = math.hypot(*(srcPixPos - refPixPos))
            maxPixSep = max(maxPixSep, pixSep)
        print("max angular separation = %0.4f arcsec" %
              (maxAngSep.asArcseconds(), ))
        print("max pixel separation = %0.3f" % (maxPixSep, ))
        self.assertLess(maxAngSep.asArcseconds(), 0.0026)
        self.assertLess(maxPixSep, 0.015)

        # try again, but without fitting the WCS
        config.forceKnownWcs = True
        solverNoFit = AstrometryTask(config=config,
                                     refObjLoader=self.refObjLoader)
        self.exposure.setWcs(distortedWcs)
        resultsNoFit = solverNoFit.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        self.assertIsNone(resultsNoFit.scatterOnSky)

        # fitting should result in matches that are at least as good
        # (strictly speaking fitting might result in a larger match list with
        # some outliers, but in practice this test passes)
        meanFitDist = np.mean([match.distance for match in results.matches])
        meanNoFitDist = np.mean(
            [match.distance for match in resultsNoFit.matches])
        self.assertLessEqual(meanFitDist, meanNoFitDist)