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')
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 testLoadSkyCircle(self): loadANetObj = LoadAstrometryNetObjectsTask(config=self.config) ctrCoord = self.wcs.pixelToSky(afwGeom.Point2D(self.ctrPix)) radius = ctrCoord.angularSeparation(self.wcs.pixelToSky(afwGeom.Box2D(self.bbox).getMin())) loadRes = loadANetObj.loadSkyCircle(ctrCoord=ctrCoord, radius=radius, filterName="r") self.assertEqual(len(loadRes.refCat), self.desNumStarsInSkyCircle)
def prep_reference_loader(center, radius): """ Return an astrometry.net reference loader. Parameters ---------- center: lsst.afw.SpherePoint The center of the field you're testing on. radius: lsst.afw.geom.angle The radius to load objects around center. """ refLoader = LoadAstrometryNetObjectsTask(LoadAstrometryNetObjectsConfig()) # Make a copy of the reference catalog for in-memory contiguity. return refLoader.loadSkyCircle(center, radius, filterName='r').refCat.copy()
def _prep_reference_loader(self, center, radius): """ Setup an astrometry.net reference loader. Parameters ---------- center : afw.coord The center of the field you're testing on. radius : afw.geom.angle The radius to load objects around center. """ refLoader = LoadAstrometryNetObjectsTask(LoadAstrometryNetObjectsConfig()) # Make a copy of the reference catalog for in-memory contiguity. self.reference = refLoader.loadSkyCircle(center, radius, filterName='r').refCat.copy()
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 setUp(self): # Set up local astrometry_net_data self.datapath = setupAstrometryNetDataDir('photocal') self.config = LoadAstrometryNetObjectsTask.ConfigClass() self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(3001, 3001)) self.ctrPix = afwGeom.Point2I(1500, 1500) metadata = PropertySet() metadata.set("RADECSYS", "FK5") metadata.set("EQUINOX", 2000.0) metadata.set("CTYPE1", "RA---TAN") metadata.set("CTYPE2", "DEC--TAN") metadata.set("CUNIT1", "deg") metadata.set("CUNIT2", "deg") metadata.set("CRVAL1", 215.5) metadata.set("CRVAL2", 53.0) metadata.set("CRPIX1", self.ctrPix[0] + 1) metadata.set("CRPIX2", self.ctrPix[1] + 1) metadata.set("CD1_1", 5.1e-05) metadata.set("CD1_2", 0.0) metadata.set("CD2_2", -5.1e-05) metadata.set("CD2_1", 0.0) self.wcs = makeWcs(metadata) self.desNumStarsInPixelBox = 270 self.desNumStarsInSkyCircle = 410
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")
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