def testRequestForeignFilter(self):
        """The user requests a filter not in the astrometry.net catalog.

        In that case, we must specify a mapping in the AstrometryConfig to point
        to an alternative filter (e.g., g instead of B).
        We should expect the returned catalog to contain references
        to the filterNameList that are in the catalog.
        """
        filterNameList = ['u', 'g', 'r', 'i', 'z']
        andConfig = AstrometryNetDataConfig()
        andConfig.load(os.path.join(self.datapath, 'andConfig2.py'))
        self.config.filterMap = dict(('my_' + b, b) for b in filterNameList)
        loadANetObj = LoadAstrometryNetObjectsTask(config=self.config,
                                                   andConfig=andConfig)

        loadRes = loadANetObj.loadPixelBox(bbox=self.bbox,
                                           wcs=self.wcs,
                                           filterName="my_r")
        refCat = loadRes.refCat
        self.assertEqual(loadRes.fluxField, "my_r_camFlux")
        self.assertEqual(len(refCat), self.desNumStarsInPixelBox)
        self.assertObjInBBox(refCat=refCat, bbox=self.bbox, wcs=self.wcs)
        schema = refCat.getSchema()
        for filterName in filterNameList:
            schema.find(filterName + "_flux")
            schema.find(filterName + '_fluxSigma')
    def testDifferentMagNames(self):
        """The astrometry.net catalog's magnitude columns are not named after filters.

        In that case, the AstrometryNetDataConfig has a mapping to point to the correct columns.
        We should expect that the returned catalog refers to the filter
        requested (not the implementation-dependent column names).
        """
        andConfig = AstrometryNetDataConfig()
        andConfig.load(os.path.join(self.datapath, 'andConfig2.py'))
        baseNameList = ('u', 'g', 'r', 'i', 'z')
        filterNameList = ["my_" + b for b in baseNameList]
        andConfig.magColumnMap = dict(("my_" + b, b) for b in baseNameList)
        andConfig.magErrorColumnMap = dict([('my_' + b, b + "_err")
                                            for b in baseNameList])
        loadANetObj = LoadAstrometryNetObjectsTask(config=self.config,
                                                   andConfig=andConfig)

        loadRes = loadANetObj.loadPixelBox(bbox=self.bbox,
                                           wcs=self.wcs,
                                           filterName="my_r")
        refCat = loadRes.refCat
        self.assertEqual(loadRes.fluxField, "my_r_flux")
        self.assertEqual(len(refCat), self.desNumStarsInPixelBox)
        self.assertObjInBBox(refCat=refCat, bbox=self.bbox, wcs=self.wcs)
        schema = refCat.getSchema()
        for nm in filterNameList:
            schema.find(nm + "_flux")
            schema.find(nm + '_fluxSigma')
Exemplo n.º 3
0
    def testNoMagErrs(self):
        """Exclude magnitude errors from the found catalog
        """
        andConfig = AstrometryNetDataConfig()
        andConfig.load(os.path.join(self.datapath, 'andConfig2.py'))
        andConfig.magErrorColumnMap = {}
        loadANetObj = LoadAstrometryNetObjectsTask(config=self.config, andConfig=andConfig)

        loadRes = loadANetObj.loadPixelBox(bbox=self.bbox, wcs=self.wcs, filterName="r")
        refCat = loadRes.refCat
        self.assertEqual(loadRes.fluxField, "r_flux")
        self.assertEqual(len(refCat), self.desNumStarsInPixelBox)
        self.assertObjInBBox(refCat=refCat, bbox=self.bbox, wcs=self.wcs)
        schema = refCat.getSchema()
        for filterName in ['u', 'g', 'r', 'i', 'z']:
            schema.find(filterName + "_flux")
            with self.assertRaises(KeyError):
                schema.find(filterName + "_fluxSigma")
Exemplo n.º 4
0
    def testLoadPixelBox(self):
        """Test loadPixelBox
        """
        loadANetObj = LoadAstrometryNetObjectsTask(config=self.config)

        loadRes = loadANetObj.loadPixelBox(bbox=self.bbox, wcs=self.wcs, filterName="r")
        refCat = loadRes.refCat
        if DoPlot:
            self.plotStars(refCat, bbox=self.bbox)
        self.assertEqual(loadRes.fluxField, "r_flux")
        self.assertEqual(len(refCat), self.desNumStarsInPixelBox)
        self.assertObjInBBox(refCat=refCat, bbox=self.bbox, wcs=self.wcs)
        schema = refCat.getSchema()
        filterNameList = ['u', 'g', 'r', 'i', 'z']
        for filterName in filterNameList:
            schema.find(filterName + "_flux").key
            schema.find(filterName + "_fluxSigma").key
        for fieldName in ("coord_ra", "coord_dec", "centroid_x", "centroid_y", "hasCentroid",
                          "photometric", "resolved"):
            schema.find(fieldName)
class TestAstrometricSolver(lsst.utils.tests.TestCase):

    def setUp(self):
        self.datapath = setupAstrometryNetDataDir('photocal')

        self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3001, 3001))
        crpix = lsst.geom.Box2D(self.bbox).getCenter()
        self.tanWcs = afwGeom.makeSkyWcs(crpix=crpix,
                                         crval=lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees),
                                         cdMatrix=afwGeom.makeCdMatrix(scale=5.1e-5*lsst.geom.degrees))
        self.exposure = afwImage.ExposureF(self.bbox)
        self.exposure.setWcs(self.tanWcs)
        self.exposure.setFilter(afwImage.Filter("r", True))
        andConfig = AstrometryNetDataConfig()
        andConfig.load(os.path.join(self.datapath, 'andConfig2.py'))
        andConfig.magErrorColumnMap = {}
        self.refObjLoader = LoadAstrometryNetObjectsTask(andConfig=andConfig)

    def tearDown(self):
        del self.tanWcs
        del self.exposure
        del self.refObjLoader

    def testTrivial(self):
        """Test fit with no distortion
        """
        self.doTest(afwGeom.makeIdentityTransform())

    def testRadial(self):
        """Test fit with radial distortion

        The offset comes from the fact that the CCD is not centered
        """
        self.doTest(afwGeom.makeRadialTransform([0, 1.01, 1e-7]))

    def makeSourceSchema(self):
        schema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(schema=schema)  # expand the schema
        return schema

    def doTest(self, pixelsToTanPixels):
        """Test using pixelsToTanPixels to distort the source positions
        """
        distortedWcs = afwGeom.makeModifiedWcs(pixelTransform=pixelsToTanPixels, wcs=self.tanWcs,
                                               modifyActualPixels=False)
        self.exposure.setWcs(distortedWcs)
        sourceCat = self.makeSourceCat(distortedWcs)
        print("number of stars =", len(sourceCat))
        config = ANetAstrometryTask.ConfigClass()
        solver = ANetAstrometryTask(config=config, refObjLoader=self.refObjLoader,
                                    schema=self.makeSourceSchema())
        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*lsst.geom.arcseconds, maxDiffPix=0.02)

        srcCoordKey = afwTable.CoordKey(sourceCat.schema["coord"])
        refCoordKey = afwTable.CoordKey(results.refCat.schema["coord"])
        maxAngSep = 0*lsst.geom.radians
        maxPixSep = 0
        for refObj, src, d in results.matches:
            refCoord = refObj.get(refCoordKey)
            refPixPos = fitWcs.skyToPixel(refCoord)
            srcCoord = src.get(srcCoordKey)
            srcPixPos = src.getCentroid()

            angSep = refCoord.separation(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.005)
        self.assertLess(maxPixSep, 0.03)

        # try again, but without fitting the WCS
        config.forceKnownWcs = True
        solverNoFit = ANetAstrometryTask(config=config, refObjLoader=self.refObjLoader,
                                         schema=self.makeSourceSchema())
        self.exposure.setWcs(distortedWcs)
        noFitResults = solverNoFit.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        self.assertGreater(len(noFitResults.refCat), 300)

    def makeSourceCat(self, distortedWcs):
        """Make a source catalog by reading the position reference stars and distorting the positions
        """
        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 = self.makeSourceSchema()
        sourceCat = afwTable.SourceCatalog(sourceSchema)
        sourceCentroidKey = afwTable.Point2DKey(sourceSchema["slot_Centroid"])
        sourceFluxKey = sourceSchema["slot_PsfFlux_instFlux"].asKey()
        sourceFluxErrKey = sourceSchema["slot_PsfFlux_instFluxErr"].asKey()

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