Ejemplo n.º 1
0
    def testLoadVersion0(self):
        """Test reading a pre-written format_version=0 (Jy flux) catalog.
        It should be converted to have nJy fluxes.
        """
        path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data',
                            'version0', 'ref_cats', 'cal_ref_cat')

        filenames = sorted(glob.glob(os.path.join(path, '????.fits')))

        loader = MockReferenceObjectLoaderFromFiles(filenames,
                                                    name='cal_ref_cat',
                                                    htmLevel=4)
        result = loader.loadSkyCircle(ingestIndexTestBase.make_coord(10, 20),
                                      5 * lsst.geom.degrees, 'a')

        self.assertTrue(hasNanojanskyFluxUnits(result.refCat.schema))
        catalog = afwTable.SimpleCatalog.readFits(filenames[0])
        self.assertFloatsEqual(catalog['a_flux'] * 1e9,
                               result.refCat['a_flux'])
        self.assertFloatsEqual(catalog['a_fluxSigma'] * 1e9,
                               result.refCat['a_fluxErr'])
        self.assertFloatsEqual(catalog['b_flux'] * 1e9,
                               result.refCat['b_flux'])
        self.assertFloatsEqual(catalog['b_fluxSigma'] * 1e9,
                               result.refCat['b_fluxErr'])
Ejemplo n.º 2
0
 def setUp(self):
     np.random.seed(12345)
     filenames = sorted(
         glob.glob(
             os.path.join(RefCatDir, 'ref_cats', 'cal_ref_cat',
                          '??????.fits')))
     self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                            htmLevel=8)
     center = lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees)
     radius = 0.5 * lsst.geom.degrees
     self.filter = "r"
     self.references = self.refObjLoader.loadSkyCircle(
         center, radius, self.filter).refCat
Ejemplo n.º 3
0
    def setUp(self):
        refCatDir = os.path.join(os.path.dirname(__file__), "data",
                                 "sdssrefcat")

        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.FilterLabel(band="r", physical="rTest"))
        filenames = sorted(
            glob.glob(
                os.path.join(refCatDir, 'ref_cats', 'cal_ref_cat',
                             '??????.fits')))
        self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                               htmLevel=8)
Ejemplo n.º 4
0
class DirectMatchTestCase(lsst.utils.tests.TestCase):
    """Tests for lsst.meas.astrom.DirectMatchTask"""
    def setUp(self):
        np.random.seed(12345)
        filenames = sorted(
            glob.glob(
                os.path.join(RefCatDir, 'ref_cats', 'cal_ref_cat',
                             '??????.fits')))
        self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                               htmLevel=8)
        center = lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees)
        radius = 0.5 * lsst.geom.degrees
        self.filter = "r"
        self.references = self.refObjLoader.loadSkyCircle(
            center, radius, self.filter).refCat

    def tearDown(self):
        del self.refObjLoader
        del self.references

    def checkMatching(self, catalog):
        config = lsst.meas.astrom.DirectMatchConfig()
        task = lsst.meas.astrom.DirectMatchTask(config=config,
                                                refObjLoader=self.refObjLoader)
        results = task.run(catalog, self.filter)

        self.assertEqual(len(results.matches), len(catalog))
        for match in results.matches:
            self.assertEqual(match.first.getId(), match.second.getId())
        maxDistance = max(match.distance for match in results.matches)
        self.assertLess(maxDistance,
                        config.matchRadius)  # match.distance is in arcsec

        self.assertIsNotNone(results.matchMeta)
        names = results.matchMeta.names()
        for key in ("RA", "DEC", "RADIUS", "SMATCHV", "FILTER"):
            self.assertIn(key, names)

    def testWithoutNoise(self):
        """Match the reference catalog against itself"""
        self.checkMatching(self.references)

    def testWithNoise(self):
        """Match the reference catalog against a noised version of itself"""
        references = self.references.copy(True)
        offset = (0.1 * lsst.geom.arcseconds).asRadians()
        num = len(references)
        ra, dec = references["coord_ra"], references["coord_dec"]
        cosDec = np.cos(dec.mean())
        ra += offset / cosDec * np.random.uniform(-1.0, 1.0, num)
        dec += offset * np.random.uniform(-1.0, 1.0, num)
        self.checkMatching(references)
Ejemplo n.º 5
0
    def setUp(self):

        # Load sample input from disk
        testDir = os.path.dirname(__file__)
        self.srcCat = afwTable.SourceCatalog.readFits(
            os.path.join(testDir, "data", "v695833-e0-c000.xy.fits"))

        self.srcCat["slot_ApFlux_instFluxErr"] = 1
        self.srcCat["slot_PsfFlux_instFluxErr"] = 1

        # The .xy.fits file has sources in the range ~ [0,2000],[0,4500]
        # which is bigger than the exposure
        self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(2048, 4612))
        smallExposure = afwImage.ExposureF(
            os.path.join(testDir, "data", "v695833-e0-c000-a00.sci.fits"))
        self.exposure = afwImage.ExposureF(self.bbox)
        self.exposure.setWcs(smallExposure.getWcs())
        self.exposure.setFilter(
            afwImage.FilterLabel(band="i", physical="test-i"))
        self.exposure.setPhotoCalib(smallExposure.getPhotoCalib())

        coordKey = self.srcCat.getCoordKey()
        centroidKey = self.srcCat.getCentroidSlot().getMeasKey()
        wcs = self.exposure.getWcs()
        for src in self.srcCat:
            src.set(coordKey, wcs.pixelToSky(src.get(centroidKey)))

        # Make a reference loader
        filenames = sorted(
            glob.glob(
                os.path.join(RefCatDir, 'ref_cats', 'cal_ref_cat',
                             '??????.fits')))
        self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                               htmLevel=8)
        self.log = logging.getLogger('lsst.testPhotoCal')
        self.log.setLevel(TRACE)

        self.config = PhotoCalConfig()
        self.config.match.matchRadius = 0.5
        self.config.match.referenceSelection.doMagLimit = True
        self.config.match.referenceSelection.magLimit.maximum = 22.0
        self.config.match.referenceSelection.magLimit.fluxField = "i_flux"
        self.config.match.referenceSelection.doFlags = True
        self.config.match.referenceSelection.flags.good = ['photometric']
        self.config.match.referenceSelection.flags.bad = ['resolved']
        self.config.match.sourceSelection.doUnresolved = False  # Don't have star/galaxy in the srcCat

        # The test and associated data have been prepared on the basis that we
        # use the PsfFlux to perform photometry.
        self.config.fluxField = "base_PsfFlux_instFlux"
    def setUp(self):
        # Load sample input from disk
        testDir = os.path.dirname(__file__)

        self.srcSet = SourceCatalog.readFits(
            os.path.join(testDir, "v695833-e0-c000.xy.fits"))

        self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                                    lsst.geom.Extent2I(2048,
                                                       4612))  # approximate
        # create an exposure with the right metadata; the closest thing we have is
        # apparently v695833-e0-c000-a00.sci.fits, which is much too small
        smallExposure = ExposureF(
            os.path.join(testDir, "v695833-e0-c000-a00.sci.fits"))
        self.exposure = ExposureF(self.bbox)
        self.exposure.setWcs(smallExposure.getWcs())
        self.exposure.setFilter(smallExposure.getFilter())
        # copy the pixels we can, in case the user wants a debug display
        mi = self.exposure.getMaskedImage()
        mi.assign(smallExposure.getMaskedImage(), smallExposure.getBBox())

        logLevel = logging.INFO
        refCatDir = os.path.join(testDir, "data", "sdssrefcat")
        filenames = sorted(
            glob.glob(
                os.path.join(refCatDir, 'ref_cats', 'cal_ref_cat',
                             '??????.fits')))
        refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                          htmLevel=8)
        astrometryConfig = AstrometryTask.ConfigClass()
        self.astrom = AstrometryTask(config=astrometryConfig,
                                     refObjLoader=refObjLoader)
        self.astrom.log.setLevel(logLevel)
        # Since our sourceSelector is a registry object we have to wait for it to be created
        # before setting default values.
        self.astrom.sourceSelector.config.minSnr = 0
Ejemplo n.º 7
0
class TestAstrometricSolver(lsst.utils.tests.TestCase):
    def setUp(self):
        refCatDir = os.path.join(os.path.dirname(__file__), "data",
                                 "sdssrefcat")

        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.FilterLabel(band="r", physical="rTest"))
        filenames = sorted(
            glob.glob(
                os.path.join(refCatDir, 'ref_cats', 'cal_ref_cat',
                             '??????.fits')))
        self.refObjLoader = MockReferenceObjectLoaderFromFiles(filenames,
                                                               htmLevel=8)

    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 testUsedFlag(self):
        """Test that the solver will record number of sources used to table
           if it is passed a schema on initialization.
        """
        self.exposure.setWcs(self.tanWcs)
        config = AstrometryTask.ConfigClass()
        config.wcsFitter.order = 2
        config.wcsFitter.numRejIter = 0

        sourceSchema = afwTable.SourceTable.makeMinimalSchema()
        measBase.SingleFrameMeasurementTask(
            schema=sourceSchema)  # expand the schema
        # schema must be passed to the solver task constructor
        solver = AstrometryTask(config=config,
                                refObjLoader=self.refObjLoader,
                                schema=sourceSchema)
        sourceCat = self.makeSourceCat(self.tanWcs, sourceSchema=sourceSchema)

        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_astrometry_used'):
                count += 1
        self.assertEqual(count, len(results.matches))

    def testMaxMeanDistance(self):
        """If the astrometric fit does not satisfy the maxMeanDistanceArcsec
        threshold, ensure task raises an lsst.pipe.base.TaskError.
        """
        self.exposure.setWcs(self.tanWcs)
        config = AstrometryTask.ConfigClass()
        config.maxMeanDistanceArcsec = 0.0  # To ensure a "deemed" WCS failure
        solver = AstrometryTask(config=config, refObjLoader=self.refObjLoader)
        sourceCat = self.makeSourceCat(self.tanWcs, doScatterCentroids=True)

        with self.assertRaisesRegex(pipeBase.TaskError,
                                    "Fatal astrometry failure detected"):
            solver.run(sourceCat=sourceCat, exposure=self.exposure)

    def doTest(self, pixelsToTanPixels, order=3):
        """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)
        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 *
                                          lsst.geom.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 = 0 * lsst.geom.radians
        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.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.0038)
        self.assertLess(maxPixSep, 0.021)

        # try again, invoking the reference selector
        config.referenceSelector.doUnresolved = True
        config.referenceSelector.unresolved.name = 'resolved'
        solverRefSelect = AstrometryTask(config=config,
                                         refObjLoader=self.refObjLoader)
        self.exposure.setWcs(distortedWcs)
        resultsRefSelect = solverRefSelect.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        self.assertLess(len(resultsRefSelect.matches), len(results.matches))

        # try again, allowing magnitude outlier rejection.
        config.doMagnitudeOutlierRejection = True
        solverMagOutlierRejection = AstrometryTask(
            config=config, refObjLoader=self.refObjLoader)
        self.exposure.setWcs(distortedWcs)
        resultsMagOutlierRejection = solverMagOutlierRejection.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        self.assertLess(len(resultsMagOutlierRejection.matches),
                        len(resultsRefSelect.matches))
        config.doMagnitudeOutlierRejection = False

        # try again, but without fitting the WCS, no reference selector
        config.referenceSelector.doUnresolved = False
        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)

        # try once again, without fitting the WCS, with the reference selector
        # (this goes through a different code path)
        config.referenceSelector.doUnresolved = True
        solverNoFitRefSelect = AstrometryTask(config=config,
                                              refObjLoader=self.refObjLoader)
        resultsNoFitRefSelect = solverNoFitRefSelect.run(
            sourceCat=sourceCat,
            exposure=self.exposure,
        )
        self.assertLess(len(resultsNoFitRefSelect.matches),
                        len(resultsNoFit.matches))

    def makeSourceCat(self, wcs, sourceSchema=None, doScatterCentroids=False):
        """Make a source catalog by reading the position reference stars using
        the proviced WCS.

        Optionally provide a schema for the source catalog (to allow
        AstrometryTask in the test methods to update it with the
        "calib_astrometry_used" flag).  Otherwise, a minimal SourceTable
        schema will be created.

        Optionally, via doScatterCentroids, add some scatter to the centroids
        assiged to the source catalog (otherwise they will be identical to
        those of the reference catalog).
        """
        loadRes = self.refObjLoader.loadPixelBox(bbox=self.bbox,
                                                 wcs=wcs,
                                                 filterName="r")
        refCat = loadRes.refCat

        if sourceSchema is None:
            sourceSchema = afwTable.SourceTable.makeMinimalSchema()
            measBase.SingleFrameMeasurementTask(
                schema=sourceSchema)  # expand the schema
        sourceCat = afwTable.SourceCatalog(sourceSchema)

        sourceCat.resize(len(refCat))
        scatterFactor = 1.0
        if doScatterCentroids:
            np.random.seed(12345)
            scatterFactor = np.random.uniform(0.999, 1.001, len(sourceCat))
        sourceCat["slot_Centroid_x"] = scatterFactor * refCat["centroid_x"]
        sourceCat["slot_Centroid_y"] = scatterFactor * refCat["centroid_y"]
        sourceCat["slot_ApFlux_instFlux"] = refCat["r_flux"]
        sourceCat["slot_ApFlux_instFluxErr"] = refCat["r_flux"] / 100

        # Deliberately add some outliers to check that the magnitude
        # outlier rejection code is being run.
        sourceCat["slot_ApFlux_instFlux"][0:4] *= 1000.0

        return sourceCat