def testAssertWcssNearlyEqualOverBBox(self): """Test assertWcsNearlyEqualOverBBox and wcsNearlyEqualOverBBox""" bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(3001, 3001)) ctrPix = afwGeom.Point2I(1500, 1500) metadata = dafBase.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", ctrPix[0] + 1) metadata.set("CRPIX2", 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) wcs0 = afwImage.cast_TanWcs(afwImage.makeWcs(metadata)) metadata.set("CRVAL2", 53.000001) # tweak CRVAL2 for wcs1 wcs1 = afwImage.cast_TanWcs(afwImage.makeWcs(metadata)) self.assertWcsNearlyEqualOverBBox(wcs0, wcs0, bbox, maxDiffSky=1e-7*afwGeom.arcseconds, maxDiffPix=1e-7) self.assertTrue(afwImage.wcsNearlyEqualOverBBox(wcs0, wcs0, bbox, maxDiffSky=1e-7*afwGeom.arcseconds, maxDiffPix=1e-7)) self.assertWcsNearlyEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.04*afwGeom.arcseconds, maxDiffPix=0.02) self.assertTrue(afwImage.wcsNearlyEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.04*afwGeom.arcseconds, maxDiffPix=0.02)) self.assertRaises(AssertionError, self.assertWcsNearlyEqualOverBBox, wcs0, wcs1, bbox, maxDiffSky=0.001*afwGeom.arcseconds, maxDiffPix=0.02) self.assertFalse(afwImage.wcsNearlyEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.001*afwGeom.arcseconds, maxDiffPix=0.02)) self.assertRaises(AssertionError, self.assertWcsNearlyEqualOverBBox, wcs0, wcs1, bbox, maxDiffSky=0.04*afwGeom.arcseconds, maxDiffPix=0.001) self.assertFalse(afwImage.wcsNearlyEqualOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.04*afwGeom.arcseconds, maxDiffPix=0.001)) # check that doShortCircuit works in the private implementation errStr1 = _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.001*afwGeom.arcseconds, maxDiffPix=0.001, doShortCircuit=False) errStr2 = _compareWcsOverBBox(wcs0, wcs1, bbox, maxDiffSky=0.001*afwGeom.arcseconds, maxDiffPix=0.001, doShortCircuit=True) self.assertNotEqual(errStr1, errStr2)
def setUp(self): # Set up local astrometry_net_data self.datapath = helper.setupAstrometryNetDataDir('photocal') self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(3001, 3001)) self.ctrPix = afwGeom.Point2I(1500, 1500) metadata = dafBase.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.tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(metadata)) self.exposure = afwImage.ExposureF(self.bbox) self.exposure.setWcs(self.tanWcs) self.exposure.setFilter(afwImage.Filter("r", True))
def testCreateTanSipWcs(self): self.metadata.set("CTYPE1", "RA---TAN") self.metadata.set("CTYPE2", "DEC--TAN") wcs = afwImage.cast_TanWcs(afwImage.makeWcs(self.metadata)) strRepresentation = str(wcs) self.assertNotEqual(strRepresentation.find("image::TanWcs"), -1, "non TanWcs object returned")
def testCreateTanSipWcs(self): self.metadata.set("CTYPE1", "RA---TAN") self.metadata.set("CTYPE2", "DEC--TAN") wcs = afwImage.cast_TanWcs(afwImage.makeWcs(self.metadata)) strRepresentation = str(wcs) self.assertNotEqual( strRepresentation.find("image::TanWcs"), -1, "non TanWcs object returned")
def testCreateTanWcs(self): """Check that a non-TAN projection in the header creates a base Wcs object""" self.metadata.set("CTYPE1", "RA---TAN") self.metadata.set("CTYPE2", "DEC--TAN") afwImage.makeWcs(self.metadata) wcs = afwImage.cast_TanWcs(afwImage.makeWcs(self.metadata)) strRepresentation = str(wcs) self.assertNotEqual(strRepresentation.find("image::TanWcs"), -1, "non TanWcs object returned")
def testCreateTanWcs(self): """Check that a non-TAN projection in the header creates a base Wcs object""" self.metadata.set("CTYPE1", "RA---TAN") self.metadata.set("CTYPE2", "DEC--TAN") afwImage.makeWcs(self.metadata) wcs = afwImage.cast_TanWcs(afwImage.makeWcs(self.metadata)) strRepresentation = str(wcs) self.assertNotEqual( strRepresentation.find("image::TanWcs"), -1, "non TanWcs object returned")
def setUp(self): # make a nominal match list where the distances are 0; test can then modify # source centroid, reference coord or distance field for each match, as desired ctrPix = afwGeom.Point2I(1500, 1500) metadata = dafBase.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", ctrPix[0] + 1) metadata.set("CRPIX2", 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 = afwImage.cast_TanWcs(afwImage.makeWcs(metadata)) self.bboxD = afwGeom.Box2D(afwGeom.Point2D(10, 100), afwGeom.Extent2D(1000, 1500)) self.numMatches = 25 sourceSchema = afwTable.SourceTable.makeMinimalSchema() # add centroid (and many other unwanted fields) to sourceSchema measBase.SingleFrameMeasurementTask(schema=sourceSchema) self.sourceCentroidKey = afwTable.Point2DKey(sourceSchema["slot_Centroid"]) self.sourceCat = afwTable.SourceCatalog(sourceSchema) refSchema = afwTable.SourceTable.makeMinimalSchema() self.refCoordKey = afwTable.CoordKey(refSchema["coord"]) self.refCat = afwTable.SourceCatalog(refSchema) self.matchList = [] np.random.seed(5) pixPointList = [afwGeom.Point2D(pos) for pos in np.random.random_sample([self.numMatches, 2])*self.bboxD.getDimensions() + self.bboxD.getMin()] for pixPoint in pixPointList: src = self.sourceCat.addNew() src.set(self.sourceCentroidKey, pixPoint) ref = self.refCat.addNew() ref.set(self.refCoordKey, self.wcs.pixelToSky(pixPoint)) match = afwTable.ReferenceMatch(ref, src, 0) self.matchList.append(match)
def setUp(self): #metadata taken from CFHT data #v695856-e0/v695856-e0-c000-a00.sci_img.fits metadata = dafBase.PropertySet() metadata.set("RADECSYS", 'FK5') metadata.set("EQUINOX", 2000.) metadata.setDouble("CRVAL1", 215.604025685476) metadata.setDouble("CRVAL2", 53.1595451514076) metadata.setDouble("CRPIX1", 1109.99981456774) metadata.setDouble("CRPIX2", 560.018167811613) metadata.set("CTYPE1", "RA---TAN") metadata.set("CTYPE2", "DEC--TAN") metadata.setDouble("CD1_1", 5.10808596133527E-05) metadata.setDouble("CD1_2", 1.85579539217196E-07) metadata.setDouble("CD2_2", -5.10281493481982E-05) metadata.setDouble("CD2_1", -8.27440751733828E-07) self.tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(metadata))
def setUp(self): # metadata taken from CFHT data # v695856-e0/v695856-e0-c000-a00.sci_img.fits metadata = dafBase.PropertySet() metadata.set("RADECSYS", "FK5") metadata.set("EQUINOX", 2000.0) metadata.setDouble("CRVAL1", 215.604025685476) metadata.setDouble("CRVAL2", 53.1595451514076) metadata.setDouble("CRPIX1", 1109.99981456774) metadata.setDouble("CRPIX2", 560.018167811613) metadata.set("CTYPE1", "RA---TAN") metadata.set("CTYPE2", "DEC--TAN") metadata.setDouble("CD1_1", 5.10808596133527e-05) metadata.setDouble("CD1_2", 1.85579539217196e-07) metadata.setDouble("CD2_2", -5.10281493481982e-05) metadata.setDouble("CD2_1", -8.27440751733828e-07) self.tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(metadata))
def setUp(self): metadata = dafBase.PropertySet() self.crPix = afwGeom.Point2D(15000, 4000) dimd = afwGeom.Extent2D(4000, 4000) bboxd = afwGeom.Box2D(self.crPix - dimd/2, dimd) self.bbox = afwGeom.Box2I(bboxd) metadata.set("RADECSYS", 'ICRS') metadata.set("EQUINOX", 2000.0) metadata.setDouble("CRVAL1", 215.60) metadata.setDouble("CRVAL2", 53.16) metadata.setDouble("CRPIX1", self.crPix[0]) metadata.setDouble("CRPIX2", self.crPix[1]) metadata.set("CTYPE1", "RA---TAN") metadata.set("CTYPE2", "DEC--TAN") metadata.setDouble("CD1_1", 5.10808596133527E-05) metadata.setDouble("CD1_2", 1.85579539217196E-07) metadata.setDouble("CD2_2", -5.10281493481982E-05) metadata.setDouble("CD2_1", -8.27440751733828E-07) self.tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(metadata))
def setUp(self): hdr = dafBase.PropertyList() hdr.add("NAXIS", 2) hdr.add("EQUINOX", 2000.0000000000) hdr.add("RADESYS", "FK5") hdr.add("CRPIX1", 947.04531175212) hdr.add("CRPIX2", -305.70042176782) hdr.add("CD1_1", -5.6081060666063e-05) hdr.add("CD1_2", 1.1941349711530e-10) hdr.add("CD2_1", 1.1938226362497e-10) hdr.add("CD2_2", 5.6066392248206e-05) hdr.add("CRVAL1", 5.5350859380564) hdr.add("CRVAL2", -0.57805534748292) hdr.add("CUNIT1", "deg") hdr.add("CUNIT2", "deg") hdr.add("A_ORDER", 3) hdr.add("A_0_0", -3.4299726900155e-05) hdr.add("A_0_2", 2.9999243742039e-08) hdr.add("A_0_3", 5.3160367322875e-12) hdr.add("A_1_0", -1.1102230246252e-16) hdr.add("A_1_1", 1.7804837804549e-07) hdr.add("A_1_2", -3.9117665277930e-10) hdr.add("A_2_0", 1.2614116305773e-07) hdr.add("A_2_1", 2.4753748298399e-12) hdr.add("A_3_0", -4.0559790823371e-10) hdr.add("B_ORDER", 3) hdr.add("B_0_0", -0.00040333633853922) hdr.add("B_0_2", 2.7329405108287e-07) hdr.add("B_0_3", -4.1945333823804e-10) hdr.add("B_1_1", 1.0211300606274e-07) hdr.add("B_1_2", -1.1907781112538e-12) hdr.add("B_2_0", 7.1256679698479e-08) hdr.add("B_2_1", -4.0026664120969e-10) hdr.add("B_3_0", 7.2509034631981e-14) hdr.add("AP_ORDER", 5) hdr.add("AP_0_0", 0.065169424373537) hdr.add("AP_0_1", 3.5323035231808e-05) hdr.add("AP_0_2", -2.4878457741060e-08) hdr.add("AP_0_3", -1.4288745247360e-11) hdr.add("AP_0_4", -2.0000000098183) hdr.add("AP_0_5", 4.3337569354109e-19) hdr.add("AP_1_0", 1.9993638555698) hdr.add("AP_1_1", -2.0722860000493e-07) hdr.add("AP_1_2", 4.7562056847339e-10) hdr.add("AP_1_3", -8.5172068319818e-06) hdr.add("AP_1_4", -1.3242986537057e-18) hdr.add("AP_2_0", -1.4594781790233e-07) hdr.add("AP_2_1", -2.9254828606617e-12) hdr.add("AP_2_2", -2.7203380713516e-11) hdr.add("AP_2_3", 1.5030517486646e-19) hdr.add("AP_3_0", 4.7856034999197e-10) hdr.add("AP_3_1", 1.5571061278960e-15) hdr.add("AP_3_2", -3.2422164667295e-18) hdr.add("AP_4_0", 5.8904402441647e-16) hdr.add("AP_4_1", -4.5488928339401e-20) hdr.add("AP_5_0", -1.3198044795585e-18) hdr.add("BP_ORDER", 5) hdr.add("BP_0_0", 0.00025729974056661) hdr.add("BP_0_1", -0.00060857907313083) hdr.add("BP_0_2", -3.1283728005742e-07) hdr.add("BP_0_3", 5.0413932972962e-10) hdr.add("BP_0_4", -0.0046142128142681) hdr.add("BP_0_5", -2.2359607268985e-18) hdr.add("BP_1_0", 0.0046783112625990) hdr.add("BP_1_1", -1.2304042740813e-07) hdr.add("BP_1_2", -2.3756827881344e-12) hdr.add("BP_1_3", -3.9300202582816e-08) hdr.add("BP_1_4", -9.7385290942256e-21) hdr.add("BP_2_0", -6.5238116398890e-08) hdr.add("BP_2_1", 4.7855579009100e-10) hdr.add("BP_2_2", -1.2297758131839e-13) hdr.add("BP_2_3", -3.0849793267035e-18) hdr.add("BP_3_0", -9.3923321275113e-12) hdr.add("BP_3_1", -1.3193479628568e-17) hdr.add("BP_3_2", 2.1762350028059e-19) hdr.add("BP_4_0", -5.9687252632035e-16) hdr.add("BP_4_1", -1.4096893423344e-18) hdr.add("BP_5_0", 2.8085458107813e-19) hdr.add("CTYPE1", "RA---TAN-SIP") hdr.add("CTYPE2", "DEC--TAN-SIP") self.data = afwImage.cast_TanWcs(afwImage.makeWcs(hdr))
def tanWcsFromDetector(detector_name, camera_wrapper, obs_metadata, epoch): """ Take an afw.cameraGeom detector and return a WCS which approximates the focal plane as perfectly flat (i.e. it ignores optical distortions that the telescope may impose on the image) @param [in] detector_name is the name of the detector as stored by afw @param [in] camera_wrapper is an instantionat of a GalSimCameraWrapper @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope's current pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [out] tanWcs is an instantiation of afw.image's TanWcs class representing the WCS of the detector as if there were no optical distortions imposed by the telescope. """ xTanPixMin, xTanPixMax, \ yTanPixMin, yTanPixMax = camera_wrapper.getTanPixelBounds(detector_name) x_center = 0.5 * (xTanPixMax + xTanPixMin) y_center = 0.5 * (yTanPixMax + yTanPixMin) xPixList = [] yPixList = [] nameList = [] # dx and dy are set somewhat heuristically # setting them equal to 0.1(max-min) lead to errors # on the order of 0.7 arcsec in the WCS dx = 0.5 * (xTanPixMax - xTanPixMin) dy = 0.5 * (yTanPixMax - yTanPixMin) for xx in np.arange(xTanPixMin, xTanPixMax + 0.5 * dx, dx): for yy in np.arange(yTanPixMin, yTanPixMax + 0.5 * dy, dy): xPixList.append(xx) yPixList.append(yy) nameList.append(detector_name) xPixList = np.array(xPixList) yPixList = np.array(yPixList) raList, decList = camera_wrapper._raDecFromPixelCoords( xPixList, yPixList, nameList, obs_metadata=obs_metadata, epoch=epoch, includeDistortion=False) crPix1, crPix2 = camera_wrapper._pixelCoordsFromRaDec( obs_metadata._pointingRA, obs_metadata._pointingDec, chipName=detector_name, obs_metadata=obs_metadata, epoch=epoch, includeDistortion=False) lonList, latList = _nativeLonLatFromPointing(raList, decList, obs_metadata._pointingRA, obs_metadata._pointingDec) # convert from native longitude and latitude to intermediate world coordinates # according to equations (12), (13), (54) and (55) of # # Calabretta and Greisen (2002), A&A 395, p. 1077 # radiusList = 180.0 / (np.tan(latList) * np.pi) uList = radiusList * np.sin(lonList) vList = -radiusList * np.cos(lonList) delta_xList = xPixList - crPix1 delta_yList = yPixList - crPix2 bVector = np.array([ (delta_xList * uList).sum(), (delta_yList * uList).sum(), (delta_xList * vList).sum(), (delta_yList * vList).sum() ]) offDiag = (delta_yList * delta_xList).sum() xsq = np.power(delta_xList, 2).sum() ysq = np.power(delta_yList, 2).sum() aMatrix = np.array([[xsq, offDiag, 0.0, 0.0], [offDiag, ysq, 0.0, 0.0], [0.0, 0.0, xsq, offDiag], [0.0, 0.0, offDiag, ysq]]) coeffs = np.linalg.solve(aMatrix, bVector) fitsHeader = dafBase.PropertyList() fitsHeader.set("RADESYS", "ICRS") fitsHeader.set("EQUINOX", epoch) fitsHeader.set("CRVAL1", obs_metadata.pointingRA) fitsHeader.set("CRVAL2", obs_metadata.pointingDec) fitsHeader.set("CRPIX1", crPix1 + 1) # the +1 is because LSST uses 0-indexed images fitsHeader.set("CRPIX2", crPix2 + 1) # FITS files use 1-indexed images fitsHeader.set("CTYPE1", "RA---TAN") fitsHeader.set("CTYPE2", "DEC--TAN") fitsHeader.setDouble("CD1_1", coeffs[0]) fitsHeader.setDouble("CD1_2", coeffs[1]) fitsHeader.setDouble("CD2_1", coeffs[2]) fitsHeader.setDouble("CD2_2", coeffs[3]) # 20 March 2017 # the 'try' block is required by the SWIG stack; # the 'except' block is required by the pybind11 stack. try: tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader)) except AttributeError: tanWcs = afwImage.makeWcs(fitsHeader) return tanWcs
def tanWcsFromDetector(afwDetector, afwCamera, obs_metadata, epoch): """ Take an afw.cameraGeom detector and return a WCS which approximates the focal plane as perfectly flat (i.e. it ignores optical distortions that the telescope may impose on the image) @param [in] afwDetector is an instantiation of afw.cameraGeom's Detector class which characterizes the detector for which you wish to return th WCS @param [in] afwCamera is an instantiation of afw.cameraGeom's Camera class which characterizes the camera containing afwDetector @param [in] obs_metadata is an instantiation of ObservationMetaData characterizing the telescope's current pointing @param [in] epoch is the epoch in Julian years of the equinox against which RA and Dec are measured @param [out] tanWcs is an instantiation of afw.image's TanWcs class representing the WCS of the detector as if there were no optical distortions imposed by the telescope. """ xTanPixMin, xTanPixMax, \ yTanPixMin, yTanPixMax = _getTanPixelBounds(afwDetector, afwCamera) xPixList = [] yPixList = [] nameList = [] # dx and dy are set somewhat heuristically # setting them eqal to 0.1(max-min) lead to errors # on the order of 0.7 arcsec in the WCS dx = 0.5*(xTanPixMax-xTanPixMin) dy = 0.5*(yTanPixMax-yTanPixMin) for xx in np.arange(xTanPixMin, xTanPixMax+0.5*dx, dx): for yy in np.arange(yTanPixMin, yTanPixMax+0.5*dy, dy): xPixList.append(xx) yPixList.append(yy) nameList.append(afwDetector.getName()) raList, decList = _raDecFromPixelCoords(np.array(xPixList), np.array(yPixList), nameList, camera=afwCamera, obs_metadata=obs_metadata, epoch=epoch, includeDistortion=False) crPix1, crPix2 = _pixelCoordsFromRaDec(obs_metadata._pointingRA, obs_metadata._pointingDec, chipName=afwDetector.getName(), camera=afwCamera, obs_metadata=obs_metadata, epoch=epoch, includeDistortion=False) lonList, latList = _nativeLonLatFromPointing(raList, decList, obs_metadata._pointingRA, obs_metadata._pointingDec) # convert from native longitude and latitude to intermediate world coordinates # according to equations (12), (13), (54) and (55) of # # Calabretta and Greisen (2002), A&A 395, p. 1077 # radiusList = 180.0/(np.tan(latList)*np.pi) uList = radiusList*np.sin(lonList) vList = -radiusList*np.cos(lonList) delta_xList = xPixList - crPix1 delta_yList = yPixList - crPix2 bVector = np.array([ (delta_xList*uList).sum(), (delta_yList*uList).sum(), (delta_xList*vList).sum(), (delta_yList*vList).sum() ]) offDiag = (delta_yList*delta_xList).sum() xsq = np.power(delta_xList, 2).sum() ysq = np.power(delta_yList, 2).sum() aMatrix = np.array([ [xsq, offDiag, 0.0, 0.0], [offDiag, ysq, 0.0, 0.0], [0.0, 0.0, xsq, offDiag], [0.0, 0.0, offDiag, ysq] ]) coeffs = np.linalg.solve(aMatrix, bVector) fitsHeader = dafBase.PropertyList() fitsHeader.set("RADESYS", "ICRS") fitsHeader.set("EQUINOX", epoch) fitsHeader.set("CRVAL1", obs_metadata.pointingRA) fitsHeader.set("CRVAL2", obs_metadata.pointingDec) fitsHeader.set("CRPIX1", crPix1+1) # the +1 is because LSST uses 0-indexed images fitsHeader.set("CRPIX2", crPix2+1) # FITS files use 1-indexed images fitsHeader.set("CTYPE1", "RA---TAN") fitsHeader.set("CTYPE2", "DEC--TAN") fitsHeader.setDouble("CD1_1", coeffs[0]) fitsHeader.setDouble("CD1_2", coeffs[1]) fitsHeader.setDouble("CD2_1", coeffs[2]) fitsHeader.setDouble("CD2_2", coeffs[3]) tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader)) return tanWcs
def getTanWcs(self): """ Return a WCS which approximates the focal plane as perfectly flat (i.e. it ignores optical distortions that the telescope may impose on the image) The output is an instantiation of lsst.afw.image's TanWcs class representing the WCS of the detector as if there were no optical distortions imposed by the telescope. """ xTanPixMin, xTanPixMax, yTanPixMin, yTanPixMax = self._getTanPixelBounds() xPixList = [] yPixList = [] nameList = [] # dx and dy are set somewhat heuristically. # Setting them eqal to 0.1*(max-min) lead to errors on the order of 0.7 arcsec in the WCS. # Here we use 0.5*(max-min), which is good to ~1 mas. dx = 0.5*(xTanPixMax-xTanPixMin) dy = 0.5*(yTanPixMax-yTanPixMin) for xx in np.arange(xTanPixMin, xTanPixMax+0.5*dx, dx): for yy in np.arange(yTanPixMin, yTanPixMax+0.5*dx, dx): xPixList.append(xx) yPixList.append(yy) nameList.append(self._chip_name) raList, decList = self._camera.raDecFromTanPixelCoords(np.array(xPixList), np.array(yPixList), nameList) raPointing = self._camera._pointing.ra/galsim.radians decPointing = self._camera._pointing.dec/galsim.radians camera_point_list = self._camera._get_afw_pupil_coord_list_from_float( raPointing, decPointing) crPix1, crPix2 = self._camera._tan_pixel_coord_from_point_and_name( camera_point_list, [self._chip_name]) lonList, latList = _nativeLonLatFromRaDec(raList, decList, raPointing, decPointing) # convert from native longitude and latitude to intermediate world coordinates # according to equations (12), (13), (54) and (55) of # # Calabretta and Greisen (2002), A&A 395, p. 1077 # radiusList = 180.0/(np.tan(latList)*np.pi) uList = radiusList*np.sin(lonList) vList = -radiusList*np.cos(lonList) # Now that we have converted into the intermediate world coordinates u and v # solve for the coefficients [c1, c2, c3, c4] that best (in the least-squares # sense) satisfy # # u = c1 * deltaX + c2 * deltaY # v = c3 * deltaX + c4 * deltaY # # where (x, y) is a position on the focal plain in pixel coordinates and # deltaX = (x - crPix1) and deltaY = (y - crPix2) delta_xList = xPixList - crPix1[0] delta_yList = yPixList - crPix2[0] bVector = np.array([ (delta_xList*uList).sum(), (delta_yList*uList).sum(), (delta_xList*vList).sum(), (delta_yList*vList).sum() ]) offDiag = (delta_yList*delta_xList).sum() xsq = np.power(delta_xList,2).sum() ysq = np.power(delta_yList,2).sum() aMatrix = np.array([ [xsq, offDiag, 0.0, 0.0], [offDiag, ysq, 0.0, 0.0], [0.0, 0.0, xsq, offDiag], [0.0, 0.0, offDiag, ysq] ]) coeffs = np.linalg.solve(aMatrix, bVector) fitsHeader = dafBase.PropertyList() fitsHeader.set("RADESYS", "ICRS") fitsHeader.set("EQUINOX", 2000.0) fitsHeader.set("CRVAL1", np.degrees(raPointing)) fitsHeader.set("CRVAL2", np.degrees(decPointing)) fitsHeader.set("CRPIX1", crPix1[0]+1) # the +1 is because LSST uses 0-indexed images fitsHeader.set("CRPIX2", crPix2[0]+1) # FITS files use 1-indexed images fitsHeader.set("CTYPE1", "RA---TAN") fitsHeader.set("CTYPE2", "DEC--TAN") fitsHeader.setDouble("CD1_1", coeffs[0]) fitsHeader.setDouble("CD1_2", coeffs[1]) fitsHeader.setDouble("CD2_1", coeffs[2]) fitsHeader.setDouble("CD2_2", coeffs[3]) tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader)) return tanWcs
def getTanWcs(self): """ Return a WCS which approximates the focal plane as perfectly flat (i.e. it ignores optical distortions that the telescope may impose on the image) The output is an instantiation of lsst.afw.image's TanWcs class representing the WCS of the detector as if there were no optical distortions imposed by the telescope. """ xTanPixMin, xTanPixMax, yTanPixMin, yTanPixMax = self._getTanPixelBounds( ) xPixList = [] yPixList = [] nameList = [] # dx and dy are set somewhat heuristically. # Setting them eqal to 0.1*(max-min) lead to errors on the order of 0.7 arcsec in the WCS. # Here we use 0.5*(max-min), which is good to ~1 mas. dx = 0.5 * (xTanPixMax - xTanPixMin) dy = 0.5 * (yTanPixMax - yTanPixMin) for xx in np.arange(xTanPixMin, xTanPixMax + 0.5 * dx, dx): for yy in np.arange(yTanPixMin, yTanPixMax + 0.5 * dx, dx): xPixList.append(xx) yPixList.append(yy) nameList.append(self._chip_name) raList, decList = self._camera.raDecFromTanPixelCoords( np.array(xPixList), np.array(yPixList), nameList) raPointing = self._camera._pointing.ra / galsim.radians decPointing = self._camera._pointing.dec / galsim.radians camera_point_list = self._camera._get_afw_pupil_coord_list_from_float( raPointing, decPointing) crPix1, crPix2 = self._camera._tan_pixel_coord_from_point_and_name( camera_point_list, [self._chip_name]) lonList, latList = _nativeLonLatFromRaDec(raList, decList, raPointing, decPointing) # convert from native longitude and latitude to intermediate world coordinates # according to equations (12), (13), (54) and (55) of # # Calabretta and Greisen (2002), A&A 395, p. 1077 # radiusList = 180.0 / (np.tan(latList) * np.pi) uList = radiusList * np.sin(lonList) vList = -radiusList * np.cos(lonList) # Now that we have converted into the intermediate world coordinates u and v # solve for the coefficients [c1, c2, c3, c4] that best (in the least-squares # sense) satisfy # # u = c1 * deltaX + c2 * deltaY # v = c3 * deltaX + c4 * deltaY # # where (x, y) is a position on the focal plain in pixel coordinates and # deltaX = (x - crPix1) and deltaY = (y - crPix2) delta_xList = xPixList - crPix1[0] delta_yList = yPixList - crPix2[0] bVector = np.array([ (delta_xList * uList).sum(), (delta_yList * uList).sum(), (delta_xList * vList).sum(), (delta_yList * vList).sum() ]) offDiag = (delta_yList * delta_xList).sum() xsq = np.power(delta_xList, 2).sum() ysq = np.power(delta_yList, 2).sum() aMatrix = np.array([[xsq, offDiag, 0.0, 0.0], [offDiag, ysq, 0.0, 0.0], [0.0, 0.0, xsq, offDiag], [0.0, 0.0, offDiag, ysq]]) coeffs = np.linalg.solve(aMatrix, bVector) fitsHeader = dafBase.PropertyList() fitsHeader.set("RADESYS", "ICRS") fitsHeader.set("EQUINOX", 2000.0) fitsHeader.set("CRVAL1", np.degrees(raPointing)) fitsHeader.set("CRVAL2", np.degrees(decPointing)) fitsHeader.set("CRPIX1", crPix1[0] + 1) # the +1 is because LSST uses 0-indexed images fitsHeader.set("CRPIX2", crPix2[0] + 1) # FITS files use 1-indexed images fitsHeader.set("CTYPE1", "RA---TAN") fitsHeader.set("CTYPE2", "DEC--TAN") fitsHeader.setDouble("CD1_1", coeffs[0]) fitsHeader.setDouble("CD1_2", coeffs[1]) fitsHeader.setDouble("CD2_1", coeffs[2]) fitsHeader.setDouble("CD2_2", coeffs[3]) tanWcs = afwImage.cast_TanWcs(afwImage.makeWcs(fitsHeader)) return tanWcs
def plotsForField(inButler, keys, fixup, plots=None, prefix=''): if plots is None: plots = ['photom','matches','corr','distortion'] filters = inButler.queryMetadata('raw', 'filter', **keys) print 'Filters:', filters filterName = filters[0] psources = inButler.get('icSrc', **keys) # since the butler does lazy evaluation, we don't know if it fails until... try: print 'Got sources', psources except: print '"icSrc" not found. Trying "src" instead.' psources = inButler.get('src', **keys) print 'Got sources', psources pmatches = inButler.get('icMatch', **keys) #print 'Got matches', pmatches #matchmeta = pmatches.getSourceMatchMetadata() #matches = pmatches.getSourceMatches() #print 'Match metadata:', matchmeta sources = psources.getSources() calexp = inButler.get('calexp', **keys) #print 'Got calexp', calexp wcs = calexp.getWcs() #print 'Got wcs', wcs #print wcs.getFitsMetadata().toString() wcs = afwImage.cast_TanWcs(wcs) #print 'After cast:', wcs photocal = calexp.getCalib() zp = photocal.getMagnitude(1.) print 'Zeropoint is', zp # ref sources W,H = calexp.getWidth(), calexp.getHeight() log = Log.getDefaultLog() log.setThreshold(Log.DEBUG); kwargs = {} if fixup: # ugh, mask and offset req'd because source ids are assigned at write-time # and match list code made a deep copy before that. # (see svn+ssh://svn.lsstcorp.org/DMS/meas/astrom/tickets/1491-b r18027) kwargs['sourceIdMask'] = 0xffff kwargs['sourceIdOffset'] = -1 (matches,ref) = measAstrom.generateMatchesFromMatchList( pmatches, sources, wcs, W, H, returnRefs=True, log=log, **kwargs) print 'Got', len(ref), 'reference catalog sources' # pull 'stargal' and 'referrs' arrays out of the reference sources fdict = maUtils.getDetectionFlags() starflag = int(fdict["STAR"]) stargal = [bool((r.getFlagForDetection() & starflag) > 0) for r in ref] referrs = [float(r.getPsfFluxErr() / r.getPsfFlux() * 2.5 / -np.log(10)) for r in ref] nstars = sum([1 for s in stargal if s]) print 'Number of sources with STAR set:', nstars visit = keys['visit'] raft = keys['raft'] sensor = keys['sensor'] prefix += 'imsim-v%i-r%s-s%s' % (visit, raft.replace(',',''), sensor.replace(',','')) if 'photom' in plots: print 'photometry plots...' tt = 'LSST ImSim v%i r%s s%s' % (visit, raft.replace(',',''), sensor.replace(',','')) wcsPlots.plotPhotometry(sources, ref, matches, prefix, band=filterName, zp=zp, referrs=referrs, refstargal=stargal, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix, band=filterName, zp=zp, delta=True, referrs=referrs, refstargal=stargal, title=tt) # test w/ and w/o referrs and stargal. if False: wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'A', band=filterName, zp=zp, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'B', band=filterName, zp=zp, referrs=referrs, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'C', band=filterName, zp=zp, refstargal=stargal, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'A', band=filterName, zp=zp, delta=True, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'B', band=filterName, zp=zp, delta=True, referrs=referrs, title=tt) wcsPlots.plotPhotometry(sources, ref, matches, prefix + 'C', band=filterName, zp=zp, delta=True,refstargal=stargal, title=tt) if 'matches' in plots: print 'matches...' wcsPlots.plotMatches(sources, ref, matches, wcs, W, H, prefix) if 'corr' in plots: #print 'corr...' # requires astrometry.libkd (not available in 0.30) #wcsPlots.plotCorrespondences2(sources, ref, matches, wcs, W, H, prefix) #print 'corr...' #wcsPlots.plotCorrespondences(sources, ref, matches, wcs, W, H, prefix) pass if 'distortion' in plots: print 'distortion...' wcsPlots.plotDistortion(wcs, W, H, 400, prefix, 'SIP Distortion (exaggerated x 10)', exaggerate=10.) print 'distortion...' wcsPlots.plotDistortion(wcs, W, H, 400, prefix, 'SIP Distortion (exaggerated x 100)', exaggerate=100., suffix='-distort2.')
def testNoCreateTanWcs(self): """Test than an exception is thrown if we try to upcast to a TanWcs inappropriately""" wcs = afwImage.makeWcs(self.metadata) with self.assertRaises(lsst.pex.exceptions.Exception): afwImage.cast_TanWcs(wcs)