def testCD_PC(self): """Test that we can read a FITS file with both CD and PC keys (like early Suprimecam files)""" md = PropertyList() for k, v in ( ("EQUINOX", 2000.0), ("RADESYS", "ICRS"), ("CRPIX1", 5353.0), ("CRPIX2", -35.0), ("CD1_1", 0.0), ("CD1_2", -5.611E-05), ("CD2_1", -5.611E-05), ("CD2_2", -0.0), ("CRVAL1", 4.5789875), ("CRVAL2", 16.30004444), ("CUNIT1", "deg"), ("CUNIT2", "deg"), ("CTYPE1", "RA---TAN"), ("CTYPE2", "DEC--TAN"), ("CDELT1", -5.611E-05), ("CDELT2", 5.611E-05), ): md.set(k, v) wcs = makeSkyWcs(md, strip=False) pixPos = Point2D(1000, 2000) pred_skyPos = SpherePoint(4.459815023498577 * degrees, 16.544199850984768 * degrees) skyPos = wcs.pixelToSky(pixPos) self.assertSpherePointsAlmostEqual(skyPos, pred_skyPos) for badPC in (False, True): for k, v in ( ("PC001001", 0.0), ("PC001002", -1.0 if badPC else 1.0), ("PC002001", 1.0 if badPC else -1.0), ("PC002002", 0.0), ): md.set(k, v) # Check Greisen and Calabretta A&A 395 1061 (2002), Eq. 3 if not badPC: for i in ( 1, 2, ): for j in ( 1, 2, ): self.assertEqual( md.get("CD%d_%d" % (i, j)), md.get("CDELT%d" % i) * md.get("PC00%d00%d" % (i, j))) wcs2 = makeSkyWcs(md, strip=False) skyPos2 = wcs2.pixelToSky(pixPos) self.assertSpherePointsAlmostEqual(skyPos2, pred_skyPos)
def makeDiaSources(nSources, diaObjectIds, exposure): """Make a test set of DiaSources. Parameters ---------- nSources : `int` Number of sources to create. diaObjectIds : `numpy.ndarray` Integer Ids of diaobjects to "associate" with the DiaSources. exposure : `lsst.afw.image.Exposure` Exposure to create sources over. pixelator : `lsst.sphgeom.HtmPixelization` Object to compute spatial indicies from. Returns ------- diaSources : `pandas.DataFrame` DiaSources generated across the exposure. """ bbox = geom.Box2D(exposure.getBBox()) rand_x = np.random.uniform(bbox.getMinX(), bbox.getMaxX(), size=nSources) rand_y = np.random.uniform(bbox.getMinY(), bbox.getMaxY(), size=nSources) midPointTaiMJD = exposure.getInfo().getVisitInfo().getDate().get( system=dafBase.DateTime.MJD) wcs = exposure.getWcs() ccdVisitId = exposure.getInfo().getVisitInfo().getExposureId() data = [] for idx, (x, y) in enumerate(zip(rand_x, rand_y)): coord = wcs.pixelToSky(x, y) htmIdx = 1 objId = diaObjectIds[idx % len(diaObjectIds)] # Put together the minimum values for the alert. data.append({ "ra": coord.getRa().asDegrees(), "decl": coord.getDec().asDegrees(), "x": x, "y": y, "ccdVisitId": ccdVisitId, "diaObjectId": objId, "ssObjectId": 0, "parentDiaSourceId": 0, "prv_procOrder": 0, "diaSourceId": idx, "pixelId": htmIdx, "midPointTai": midPointTaiMJD + 1.0 * idx, # TODO DM-27170: fix this [0] workaround which gets a # single character representation of the band. "filterName": exposure.getFilter().getCanonicalName()[0], "filterId": 0, "psNdata": 0, "trailNdata": 0, "dipNdata": 0, "flags": 1 }) return pd.DataFrame(data=data)
def makeDiaSources(nSources, diaObjectIds, exposure): """Make a test set of DiaSources. Parameters ---------- nSources : `int` Number of sources to create. diaObjectIds : `numpy.ndarray` Integer Ids of diaobjects to "associate" with the DiaSources. exposure : `lsst.afw.image.Exposure` Exposure to create sources over. Returns ------- diaSources : `pandas.DataFrame` DiaSources generated across the exposure. """ bbox = geom.Box2D(exposure.getBBox()) rand_x = np.random.uniform(bbox.getMinX(), bbox.getMaxX(), size=nSources) rand_y = np.random.uniform(bbox.getMinY(), bbox.getMaxY(), size=nSources) midPointTaiMJD = exposure.getInfo().getVisitInfo().getDate().get( system=dafBase.DateTime.MJD) wcs = exposure.getWcs() ccdVisitId = exposure.info.id data = [] for idx, (x, y) in enumerate(zip(rand_x, rand_y)): coord = wcs.pixelToSky(x, y) objId = diaObjectIds[idx % len(diaObjectIds)] # Put together the minimum values for the alert. data.append({ "ra": coord.getRa().asDegrees(), "decl": coord.getDec().asDegrees(), "x": x, "y": y, "ccdVisitId": ccdVisitId, "diaObjectId": objId, "ssObjectId": 0, "parentDiaSourceId": 0, "prv_procOrder": 0, "diaSourceId": idx + 1, "midPointTai": midPointTaiMJD + 1.0 * idx, "filterName": exposure.getFilter().bandLabel, "psNdata": 0, "trailNdata": 0, "dipNdata": 0, "flags": 1 }) return pd.DataFrame(data=data)
def makeDiaObjects(nObjects, exposure): """Make a test set of DiaObjects. Parameters ---------- nObjects : `int` Number of objects to create. exposure : `lsst.afw.image.Exposure` Exposure to create objects over. Returns ------- diaObjects : `pandas.DataFrame` DiaObjects generated across the exposure. """ bbox = geom.Box2D(exposure.getBBox()) rand_x = np.random.uniform(bbox.getMinX(), bbox.getMaxX(), size=nObjects) rand_y = np.random.uniform(bbox.getMinY(), bbox.getMaxY(), size=nObjects) midPointTaiMJD = exposure.getInfo().getVisitInfo().getDate().get( system=dafBase.DateTime.MJD) wcs = exposure.getWcs() data = [] for idx, (x, y) in enumerate(zip(rand_x, rand_y)): coord = wcs.pixelToSky(x, y) htmIdx = 1 newObject = { "ra": coord.getRa().asDegrees(), "decl": coord.getDec().asDegrees(), "radecTai": midPointTaiMJD, "diaObjectId": idx, "pixelId": htmIdx, "pmParallaxNdata": 0, "nearbyObj1": 0, "nearbyObj2": 0, "nearbyObj3": 0, "flags": 1, "nDiaSources": 5 } for f in ["u", "g", "r", "i", "z", "y"]: newObject["%sPSFluxNdata" % f] = 0 data.append(newObject) return pd.DataFrame(data=data)
def makePatchFiles(args, verbose=0): """ Makes patch-level region files given a skyMap, star catalogue and a recipe to draw each mask size according to the star brightness INPUT -i SKYMAP,STARCAT,RADIUSFILE OUTPUT -o directory where to put the region files """ """ LSST pipeline libraries """ sys.stderr.write("Importing LSST pipeline libraries...") import lsst.daf.persistence as dafPersist import lsst.afw.cameraGeom as camGeom import lsst.afw.coord as afwCoord import lsst.afw.geom as afwGeom import lsst.afw.image as afwImage sys.stderr.write("Done\n") fileInName = args.input.split(",") dirOutName = args.output filters = ["HSC-G", "HSC-R", "HSC-I", "HSC-Z", "HSC-Y"] """ skyMap """ sys.stderr.write("Loading sky map: {0:s}...".format(fileInName[0])) skyMap = pickle.load(open(fileInName[0], "rb")) sys.stderr.write("Done\n") NTracts = len(skyMap) """ star catalogue """ sys.stderr.write("Reading star catalogue: {0:s}...".format(fileInName[1])) stars, _ = getCols(fileInName[1], ['source_id', 'ra', 'dec', 'G_Gaia'], dictionary=True) Nstars = len(stars['source_id']) starsTree = dataTree(stars['ra'], stars['dec']) bright = stars['G_Gaia'] < MAG_LIMIT faint = stars['G_Gaia'] >= MAG_LIMIT sys.stderr.write("Done\n") """ mask radius """ sys.stderr.write("Computing masks radius from: {0:s}...".format( fileInName[2])) maskRadiusPara = ascii.read(fileInName[2], header_start=-1) a_bright = maskRadiusPara["a"][maskRadiusPara["mask_type"] == "bright"][0] b_bright = maskRadiusPara["b"][maskRadiusPara["mask_type"] == "bright"][0] a_faint = maskRadiusPara["a"][maskRadiusPara["mask_type"] == "faint"][0] b_faint = maskRadiusPara["b"][maskRadiusPara["mask_type"] == "faint"][0] sys.stderr.write("Done\n") rMask = np.zeros(Nstars) rMask[bright] = r_vs_mag(stars['G_Gaia'][bright], a_bright, b_bright) # in arcsec rMask[faint] = r_vs_mag(stars['G_Gaia'][faint], a_faint, b_faint) # in arsec rMask /= 3600.0 """ largest possible radius in star catalogue """ starMaxRadius = max(rMask) sys.stderr.write("Largest mask radius: {0:f} deg\n".format(starMaxRadius)) sys.stderr.write( "\r" + "Writing region files: {0:d}/{1:d} tracts done".format(0, NTracts)) sys.stderr.flush() #sys.stderr.write("Writing region files\n".format(starMaxRadius)) for i, tract in enumerate(skyMap): # if tract.getId() != 9376: # continue wcs = tract.getWcs() pixelScale = wcs.pixelScale().asDegrees() """ maximum radii along the diagonal of the tract and patches """ tractMaxRadius = max( tract.getBBox().getMaxX(), tract.getBBox().getMaxY()) * pixelScale * np.sqrt(2.) / 2. patchMaxRadius = ( max(tract.getPatchInnerDimensions()) + tract.getPatchBorder()) * pixelScale * np.sqrt(2.) / 2. """ find stars around tract """ raTract, decTract = tract.getCtrCoord().getRa().asDegrees( ), tract.getCtrCoord().getDec().asDegrees() starsTract = findNeighbors(starsTree, raTract, decTract, tractMaxRadius + starMaxRadius) Nstars = len(stars['ra'][starsTract]) # print "\n", Nstars if Nstars == 0: if (i + 1) % 100 == 0: sys.stderr.write( "\r" + "Writing region files: {0:d}/{1:d} tracts done".format( i + 1, NTracts)) sys.stderr.flush() continue mkdir_p(dirOutName + "/patches/{0:d}".format(tract.getId())) mkdir_p(dirOutName + "/tracts") starsRa = stars['ra'][starsTract] starsDec = stars['dec'][starsTract] starsRMasks = rMask[starsTract] starsID = stars['source_id'][starsTract] starsMag = stars['G_Gaia'][starsTract] """ write tract file """ for f in filters: fileOutName = dirOutName + "/tracts/" + args.basename + "-{0:d}-{1:s}.reg".format( tract.getId(), f) if f == "HSC-I": writeMaskFile(starsRa, starsDec, starsRMasks, starsID, fileOutName, f, tract.getId(), [-1, -1], starsMag) else: ln_sf( args.basename + "-{0:d}-{1:s}.reg".format(tract.getId(), "HSC-I"), fileOutName) """ loop over patches """ for patch in tract: bbox = patch.getOuterBBox() p = afwGeom.Point2D((bbox.getMinX() + bbox.getMaxX()) / 2.0, (bbox.getMinY() + bbox.getMaxY()) / 2.0) center = wcs.pixelToSky(p).toIcrs() raPatch, decPatch = center.getRa().asDegrees(), center.getDec( ).asDegrees() D = distAngSpherDeg(raPatch, decPatch, starsRa, starsDec) inPatch = (D < patchMaxRadius + 1.5 * starsRMasks) if len(starsDec[inPatch]) == 0: continue for f in filters: fileOutName = dirOutName + "/patches/{0:d}/{1:s}-{0:d}-{2:d},{3:d}-{4:s}.reg".format( tract.getId(), args.basename, patch.getIndex()[0], patch.getIndex()[1], f) if f == "HSC-I": writeMaskFile(starsRa[inPatch], starsDec[inPatch], starsRMasks[inPatch], starsID[inPatch], fileOutName, f, tract.getId(), patch.getIndex(), starsMag[inPatch]) else: ln_sf( args.basename + "-{0:d}-{1:d},{2:d}-{3:s}.reg".format( tract.getId(), patch.getIndex()[0], patch.getIndex()[1], "HSC-I"), fileOutName) if (i + 1) % 100 == 0: sys.stderr.write("\r" + "Writing region files: {0:d}/{1:d} tracts done". format(i + 1, NTracts)) sys.stderr.flush() sys.stderr.write("\r" + "Writing region files: {0:d}/{1:d} tracts done\n".format( NTracts, NTracts)) sys.stderr.flush() return
def checkTanWcs(self, crval, orientation, flipX): """Construct a pure TAN SkyWcs and check that it operates as specified Parameters ---------- crval : `lsst.afw.geom.SpherePoint` Desired reference sky position. Must not be at either pole. orientation : `lsst.afw.geom.Angle` Position angle of focal plane +Y, measured from N through E. At 0 degrees, +Y is along N and +X is along E/W if flipX false/true At 90 degrees, +Y is along E and +X is along S/N if flipX false/true flipX : `bool` Flip x axis? See `orientation` for details. Returns ------- wcs : `lsst.afw.geom.SkyWcs` The generated pure TAN SkyWcs """ cdMatrix = makeCdMatrix(scale=self.scale, orientation=orientation, flipX=flipX) wcs = makeSkyWcs(crpix=self.crpix, crval=crval, cdMatrix=cdMatrix) self.checkPersistence(wcs, bbox=self.bbox) self.checkMakeFlippedWcs(wcs) self.assertTrue(wcs.isFits) self.assertEqual(wcs.isFlipped, bool(flipX)) xoffAng = 0 * degrees if flipX else 180 * degrees pixelList = [ Point2D(self.crpix[0], self.crpix[1]), Point2D(self.crpix[0] + 1, self.crpix[1]), Point2D(self.crpix[0], self.crpix[1] + 1), ] skyList = wcs.pixelToSky(pixelList) # check pixels to sky predSkyList = [ crval, crval.offset(xoffAng - orientation, self.scale), crval.offset(90 * degrees - orientation, self.scale), ] self.assertSpherePointListsAlmostEqual(predSkyList, skyList) self.assertSpherePointListsAlmostEqual(predSkyList, wcs.pixelToSky(pixelList)) for pixel, predSky in zip(pixelList, predSkyList): self.assertSpherePointsAlmostEqual(predSky, wcs.pixelToSky(pixel)) self.assertSpherePointsAlmostEqual( predSky, wcs.pixelToSky(pixel[0], pixel[1])) # check sky to pixels self.assertPairListsAlmostEqual(pixelList, wcs.skyToPixel(skyList)) self.assertPairListsAlmostEqual(pixelList, wcs.skyToPixel(skyList)) for pixel, sky in zip(pixelList, skyList): self.assertPairsAlmostEqual(pixel, wcs.skyToPixel(sky)) # self.assertPairsAlmostEqual(pixel, wcs.skyToPixel(sky[0], sky[1])) # check CRVAL round trip self.assertSpherePointsAlmostEqual(wcs.getSkyOrigin(), crval, maxSep=self.tinyAngle) crpix = wcs.getPixelOrigin() self.assertPairsAlmostEqual(crpix, self.crpix, maxDiff=self.tinyPixels) self.assertFloatsAlmostEqual(wcs.getCdMatrix(), cdMatrix) pixelScale = wcs.getPixelScale() self.assertAnglesAlmostEqual(self.scale, pixelScale, maxDiff=self.tinyAngle) pixelScale = wcs.getPixelScale(self.crpix) self.assertAnglesAlmostEqual(self.scale, pixelScale, maxDiff=self.tinyAngle) # check that getFitsMetadata can operate at high precision # and has axis order RA, Dec fitsMetadata = wcs.getFitsMetadata(True) self.assertEqual(fitsMetadata.get("CTYPE1")[0:4], "RA--") self.assertEqual(fitsMetadata.get("CTYPE2")[0:4], "DEC-") # Compute a WCS with the pixel origin shifted by an arbitrary amount # The resulting sky origin should not change offset = Extent2D(500, -322) # arbitrary shiftedWcs = wcs.copyAtShiftedPixelOrigin(offset) self.assertTrue(shiftedWcs.isFits) predShiftedPixelOrigin = self.crpix + offset self.assertPairsAlmostEqual(shiftedWcs.getPixelOrigin(), predShiftedPixelOrigin, maxDiff=self.tinyPixels) self.assertSpherePointsAlmostEqual(shiftedWcs.getSkyOrigin(), crval, maxSep=self.tinyAngle) shiftedPixelList = [p + offset for p in pixelList] shiftedSkyList = shiftedWcs.pixelToSky(shiftedPixelList) self.assertSpherePointListsAlmostEqual(skyList, shiftedSkyList, maxSep=self.tinyAngle) # Check that the shifted WCS can be round tripped as FITS metadata shiftedMetadata = shiftedWcs.getFitsMetadata(precise=True) shiftedWcsCopy = makeSkyWcs(shiftedMetadata) shiftedBBox = Box2D(predShiftedPixelOrigin, predShiftedPixelOrigin + Extent2I(2000, 2000)) self.assertWcsAlmostEqualOverBBox(shiftedWcs, shiftedWcsCopy, shiftedBBox) wcsCopy = SkyWcs.readString(wcs.writeString()) self.assertTrue(wcsCopy.isFits) return wcs