def test1(self): wcsfn = os.path.join(self.datadir, 'imsim-v85518312-fu-R43-S12.wcs2') hdr = readMetadata(wcsfn) wcs1 = afwGeom.makeSkyWcs(hdr) crval = wcs1.getSkyOrigin() cd = wcs1.getCdMatrix() print(cd) crval_p = lsst.geom.Point2D(crval.getLongitude().asDegrees(), crval.getLatitude().asDegrees()) origin = wcs1.getPixelOrigin() print(crval_p) print(origin) wcs2 = afwGeom.makeSkyWcs(crpix=origin, crval=crval, cdMatrix=cd) for wcs in [wcs1, wcs2]: print(wcs) print('x, y, RA, Dec, pixscale("/pix), pixscale2') for x, y in [(0, 0), (300, 0), (350, 0), (360, 0), (370, 0), (380, 0), (400, 0)]: pixPos = lsst.geom.PointD(x, y) radec = wcs.pixelToSky(pixPos) ra = radec.getLongitude().asDegrees() dec = radec.getLatitude().asDegrees() pixscale = wcs.getPixelScale(pixPos).asArcseconds() print(x, y, ra, dec, pixscale) self.assertLess(abs(pixscale - 0.2), 1e-3)
def testInputInvariance(self): pl = headerToPropertyList(self.header) makeSkyWcs(pl, strip=False) for key, value in self.header.items(): self.assertEqual( value, pl.get(key), "%s not invariant: %s vs %s" % (key, value, pl.get(key)))
def test1(self): wcsfn = os.path.join(self.datadir, 'imsim-v85518312-fu-R43-S12.wcs2') hdr = readMetadata(wcsfn) wcs1 = afwGeom.makeSkyWcs(hdr) crval = wcs1.getSkyOrigin() cd = wcs1.getCdMatrix() print(cd) crval_p = afwGeom.Point2D(crval.getLongitude().asDegrees(), crval.getLatitude().asDegrees()) origin = wcs1.getPixelOrigin() print(crval_p) print(origin) wcs2 = afwGeom.makeSkyWcs(crpix=origin, crval=crval, cdMatrix=cd) for wcs in [wcs1, wcs2]: print(wcs) print('x, y, RA, Dec, pixscale("/pix), pixscale2') for x, y in [(0, 0), (300, 0), (350, 0), (360, 0), (370, 0), (380, 0), (400, 0)]: pixPos = afwGeom.PointD(x, y) radec = wcs.pixelToSky(pixPos) ra = radec.getLongitude().asDegrees() dec = radec.getLatitude().asDegrees() pixscale = wcs.getPixelScale(pixPos).asArcseconds() print(x, y, ra, dec, pixscale) self.assertLess(abs(pixscale - 0.2), 1e-3)
def testSmallSrc(self): """Verify that a source image that is too small will not raise an exception This tests another bug that was fixed in ticket #2441 """ fromWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(359, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.0e-8*lsst.geom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(1, 1), fromWcs) toWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(358, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.1e-8*lsst.geom.degrees), ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0) imArr, maskArr, varArr = toExp.getMaskedImage().getArrays() self.assertTrue(np.all(np.isnan(imArr))) self.assertTrue(np.all(np.isinf(varArr))) noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA") self.assertTrue(np.all(maskArr == noDataBitMask))
def stripMetadata(self): """Remove metadata entries that are parsed into components. This is only called when just the metadata is requested; stripping entries there forces code that wants other components to ask for those components directly rather than trying to extract them from the metadata manually, which is fragile. This behavior is an intentional change from Gen2. Parameters ---------- metadata : `~lsst.daf.base.PropertyList` Header metadata, to be modified in-place. """ # TODO: make sure this covers everything, by delegating to something # that doesn't yet exist in afw.image.ExposureInfo. from lsst.afw.image import bboxFromMetadata from lsst.afw.geom import makeSkyWcs # Protect against the metadata being missing try: bboxFromMetadata(self.metadata) # always strips except LookupError: pass try: makeSkyWcs(self.metadata, strip=True) except Exception: pass
def testSmallSrc(self): """Verify that a source image that is too small will not raise an exception This tests another bug that was fixed in ticket #2441 """ fromWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(359, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.0e-8 * lsst.geom.degrees), ) fromExp = afwImage.ExposureF(afwImage.MaskedImageF(1, 1), fromWcs) toWcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(0, 0), crval=lsst.geom.SpherePoint(358, 0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=1.1e-8 * lsst.geom.degrees), ) toExp = afwImage.ExposureF(afwImage.MaskedImageF(10, 10), toWcs) warpControl = afwMath.WarpingControl("lanczos3") # if a bug described in ticket #2441 is present, this will raise an # exception: numGoodPix = afwMath.warpExposure(toExp, fromExp, warpControl) self.assertEqual(numGoodPix, 0) imArr, maskArr, varArr = toExp.getMaskedImage().getArrays() self.assertTrue(np.all(np.isnan(imArr))) self.assertTrue(np.all(np.isinf(varArr))) noDataBitMask = afwImage.Mask.getPlaneBitMask("NO_DATA") self.assertTrue(np.all(maskArr == noDataBitMask))
def testTransform(self): dims = lsst.geom.Extent2I(512, 512) bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dims) radius = 5 offset = lsst.geom.Extent2D(123, 456) crval = lsst.geom.SpherePoint(0, 0, lsst.geom.degrees) crpix = lsst.geom.Point2D(0, 0) cdMatrix = np.array([1.0e-5, 0.0, 0.0, 1.0e-5]) cdMatrix.shape = (2, 2) source = afwGeom.makeSkyWcs(crval=crval, crpix=crpix, cdMatrix=cdMatrix) target = afwGeom.makeSkyWcs(crval=crval, crpix=crpix + offset, cdMatrix=cdMatrix) sourceSpanSet = afwGeom.SpanSet.fromShape(radius, afwGeom.Stencil.CIRCLE) sourceSpanSet = sourceSpanSet.shiftedBy(12, 34) fpSource = afwDetect.Footprint(sourceSpanSet, bbox) fpTarget = fpSource.transform(source, target, bbox) self.assertEqual(len(fpSource.getSpans()), len(fpTarget.getSpans())) self.assertEqual(fpSource.getArea(), fpTarget.getArea()) imSource = afwImage.ImageU(dims) fpSource.spans.setImage(imSource, 1) imTarget = afwImage.ImageU(dims) fpTarget.spans.setImage(imTarget, 1) subSource = imSource.Factory(imSource, fpSource.getBBox()) subTarget = imTarget.Factory(imTarget, fpTarget.getBBox()) self.assertTrue(np.all(subSource.getArray() == subTarget.getArray())) # make a bbox smaller than the target footprint bbox2 = lsst.geom.Box2I(fpTarget.getBBox()) bbox2.grow(-1) fpTarget2 = fpSource.transform(source, target, bbox2) # this one clips fpTarget3 = fpSource.transform(source, target, bbox2, False) # this one doesn't self.assertTrue(bbox2.contains(fpTarget2.getBBox())) self.assertFalse(bbox2.contains(fpTarget3.getBBox())) self.assertNotEqual(fpTarget.getArea(), fpTarget2.getArea()) self.assertEqual(fpTarget.getArea(), fpTarget3.getArea()) # Test that peakCatalogs get Transformed correctly truthList = [(x, y, 10) for x, y in zip(range(-2, 2), range(-1, 3))] for value in truthList: fpSource.addPeak(*value) scaleFactor = 2 linTrans = lsst.geom.LinearTransform( np.array([[scaleFactor, 0], [0, scaleFactor]], dtype=float)) linTransFootprint = fpSource.transform(linTrans, fpSource.getBBox(), False) for peak, truth in zip(linTransFootprint.peaks, truthList): # Multiplied by two because that is the linear transform scaling # factor self.assertEqual(peak.getIx(), truth[0] * scaleFactor) self.assertEqual(peak.getIy(), truth[1] * scaleFactor)
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 setUp(self): # Test geometry: # # -100,99 99,99 # +--------------------+ # |AAAAAAAAAACCCCCDDDDD| A == only in epoch A # |AAAAAAAAAACCCCCDDDDD| B == only in epoch B # |AAAAAAAAAACCCCCDDDDD| C == in both epoch A and epoch B # |AAAAAAAAAACCCCCDDDDD| D == in epoch A; in B's bbox but outside its ValidPolygon # |AAAAAAAAAACCCCCDDDDD| # | BBBBBBBBBB| All WCSs have the same CRVAL and CD. # | BBBBBBBBBB| # | BBBBBBBBBB| Coadd has CRPIX=(0, 0) # | BBBBBBBBBB| Epoch A has CRPIX=(0, -50) # | BBBBBBBBBB| Epoch B has CRPIX=(-50, 0) # +--------------------+ # -100,-100 99,-100 # self.rng = np.random.RandomState(50) crval = SpherePoint(45.0, 45.0, degrees) cdMatrix = makeCdMatrix(scale=5E-5 * degrees, flipX=True) self.wcsCoadd = makeSkyWcs(crpix=Point2D(0.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.wcsA = makeSkyWcs(crpix=Point2D(0.0, -50.0), crval=crval, cdMatrix=cdMatrix) self.wcsB = makeSkyWcs(crpix=Point2D(-50.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.bboxCoadd = Box2I(Point2I(-100, -100), Point2I(99, 99)) self.bboxA = Box2I(Point2I(-100, -50), Point2I(99, 49)) self.bboxB = Box2I(Point2I(-50, -100), Point2I(49, 99)) self.polygonA = None polygonD = Polygon(Box2D(Box2I(Point2I(0, 0), Point2I(49, 99)))) self.polygonB, = polygonD.symDifference(Polygon(Box2D(self.bboxB))) self.curveA = makeRandomTransmissionCurve(self.rng) self.curveB = makeRandomTransmissionCurve(self.rng) self.weightA = 0.6 self.weightB = 0.2 schema = ExposureTable.makeMinimalSchema() weightKey = schema.addField("weight", type=float, doc="relative weight of image in Coadd") catalog = ExposureCatalog(schema) recordA = catalog.addNew() recordA[weightKey] = self.weightA recordA.setWcs(self.wcsA) recordA.setValidPolygon(self.polygonA) recordA.setBBox(self.bboxA) recordA.setTransmissionCurve(self.curveA) recordB = catalog.addNew() recordB[weightKey] = self.weightB recordB.setWcs(self.wcsB) recordB.setValidPolygon(self.polygonB) recordB.setBBox(self.bboxB) recordB.setTransmissionCurve(self.curveB) self.curveCoadd = makeCoaddTransmissionCurve(self.wcsCoadd, catalog)
def testFitsMetadata(self): """Test that getFitsMetadata works for TAN-SIP """ skyWcs = makeSkyWcs(self.metadata, strip=False) self.assertTrue(skyWcs.isFits) fitsMetadata = skyWcs.getFitsMetadata(precise=True) skyWcsCopy = makeSkyWcs(fitsMetadata) self.assertWcsAlmostEqualOverBBox(skyWcs, skyWcsCopy, self.bbox) self.checkPersistence(skyWcs, bbox=self.bbox)
def makeitLsst(prefs, context, saveWcs=False, plot=dict()): """This is the python wrapper that reads lsst tables """ # Create an array of PSFs (one PSF for each extension) if prefs.getVerboseType() != prefs.QUIET: print("----- %d input catalogues:" % prefs.getNcat()) if saveWcs: # only needed for making plots wcssList = [] fields = psfexLib.vectorField() for cat in prefs.getCatalogs(): field = psfexLib.Field(cat) wcss = [] wcssList.append(wcss) with fits.open(cat): # Hack: I want the WCS so I'll guess where the calexp is to be # found calexpFile = guessCalexp(cat) md = readMetadata(calexpFile) wcs = afwGeom.makeSkyWcs(md) if not wcs: cdMatrix = np.array([1.0, 0.0, 0.0, 1.0]) cdMatrix.shape = (2, 2) wcs = afwGeom.makeSkyWcs(crpix=geom.PointD(0, 0), crval=geom.SpherePoint( 0.0, 0.0, geom.degrees), cdMatrix=cdMatrix) naxis1, naxis2 = md.getScalar("NAXIS1"), md.getScalar("NAXIS2") # Find how many rows there are in the catalogue md = readMetadata(cat) field.addExt(wcs, naxis1, naxis2, md.getScalar("NAXIS2")) if saveWcs: wcss.append((wcs, naxis1, naxis2)) field.finalize() fields.append(field) fields[0].getNext() # number of extensions prefs.getPsfStep() sets = psfexLib.vectorSet() for set in load_samplesLsst(prefs, context, plot=plot): sets.append(set) psfexLib.makeit(fields, sets) ret = [[f.getPsfs() for f in fields], sets] if saveWcs: ret.append(wcssList) return ret
def makeitLsst(prefs, context, saveWcs=False, plot=dict()): """This is the python wrapper that reads lsst tables """ # Create an array of PSFs (one PSF for each extension) if prefs.getVerboseType() != prefs.QUIET: print("----- %d input catalogues:" % prefs.getNcat()) if saveWcs: # only needed for making plots wcssList = [] fields = psfexLib.vectorField() for cat in prefs.getCatalogs(): field = psfexLib.Field(cat) wcss = [] wcssList.append(wcss) with fits.open(cat): # Hack: I want the WCS so I'll guess where the calexp is to be found calexpFile = guessCalexp(cat) md = readMetadata(calexpFile) wcs = afwGeom.makeSkyWcs(md) if not wcs: cdMatrix = np.array([1.0, 0.0, 0.0, 1.0]) cdMatrix.shape = (2, 2) wcs = afwGeom.makeSkyWcs(crpix=afwGeom.PointD(0, 0), crval=afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees), cdMatrix=cdMatrix) naxis1, naxis2 = md.getScalar("NAXIS1"), md.getScalar("NAXIS2") # Find how many rows there are in the catalogue md = readMetadata(cat) field.addExt(wcs, naxis1, naxis2, md.getScalar("NAXIS2")) if saveWcs: wcss.append((wcs, naxis1, naxis2)) field.finalize() fields.append(field) fields[0].getNext() # number of extensions prefs.getPsfStep() sets = psfexLib.vectorSet() for set in load_samplesLsst(prefs, context, plot=plot): sets.append(set) psfexLib.makeit(fields, sets) ret = [[f.getPsfs() for f in fields], sets] if saveWcs: ret.append(wcssList) return ret
def make_dm_wcs(galsim_wcs): """ convert galsim wcs to stack wcs Parameters ---------- galsim_wcs: galsim WCS Should be TAN or TAN-SIP Returns ------- DM Stack sky wcs """ if galsim_wcs.wcs_type == 'TAN': crpix = galsim_wcs.crpix # DM uses 0 offset, galsim uses FITS 1 offset stack_crpix = Point2D(crpix[0] - 1, crpix[1] - 1) cd_matrix = galsim_wcs.cd crval = geom.SpherePoint( galsim_wcs.center.ra / coord.radians, galsim_wcs.center.dec / coord.radians, geom.radians, ) stack_wcs = makeSkyWcs( crpix=stack_crpix, crval=crval, cdMatrix=cd_matrix, ) elif galsim_wcs.wcs_type == 'TAN-SIP': # No currently supported # this works with the 1-offset assumption from galsim # # this is not used if the lower bounds are 1, but the extra keywords # GS_{X,Y}MIN are set which we will remove below fake_bounds = galsim.BoundsI(1, 10, 1, 10) hdr = {} galsim_wcs.writeToFitsHeader(hdr, fake_bounds) del hdr["GS_XMIN"] del hdr["GS_YMIN"] metadata = PropertyList() for key, value in hdr.items(): metadata.set(key, value) stack_wcs = makeSkyWcs(metadata) return stack_wcs
def setUp(self): self.config = MakeDiscreteSkyMapConfig() self.task = MakeDiscreteSkyMapTask(config=self.config) self.cd_matrix = afwGeom.makeCdMatrix(scale=0.2*lsst.geom.arcseconds) self.crpix = lsst.geom.Point2D(100, 100) self.crval1 = lsst.geom.SpherePoint(10.0*lsst.geom.degrees, 0.0*lsst.geom.degrees) self.wcs1 = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval1, cdMatrix=self.cd_matrix) self.bbox = lsst.geom.Box2I(corner=lsst.geom.Point2I(0, 0), dimensions=lsst.geom.Extent2I(200, 200)) self.crval2 = lsst.geom.SpherePoint(11.0*lsst.geom.degrees, 1.0*lsst.geom.degrees) self.wcs2 = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval2, cdMatrix=self.cd_matrix) self.crval3 = lsst.geom.SpherePoint(20.0*lsst.geom.degrees, 10.0*lsst.geom.degrees) self.wcs3 = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval3, cdMatrix=self.cd_matrix)
def setUp(self): # Test geometry: # # -100,99 99,99 # +--------------------+ # |AAAAAAAAAACCCCCDDDDD| A == only in epoch A # |AAAAAAAAAACCCCCDDDDD| B == only in epoch B # |AAAAAAAAAACCCCCDDDDD| C == in both epoch A and epoch B # |AAAAAAAAAACCCCCDDDDD| D == in epoch A; in B's bbox but outside its ValidPolygon # |AAAAAAAAAACCCCCDDDDD| # | BBBBBBBBBB| All WCSs have the same CRVAL and CD. # | BBBBBBBBBB| # | BBBBBBBBBB| Coadd has CRPIX=(0, 0) # | BBBBBBBBBB| Epoch A has CRPIX=(0, -50) # | BBBBBBBBBB| Epoch B has CRPIX=(-50, 0) # +--------------------+ # -100,-100 99,-100 # self.rng = np.random.RandomState(50) crval = SpherePoint(45.0, 45.0, degrees) cdMatrix = makeCdMatrix(scale=5E-5*degrees, flipX=True) self.wcsCoadd = makeSkyWcs(crpix=Point2D(0.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.wcsA = makeSkyWcs(crpix=Point2D(0.0, -50.0), crval=crval, cdMatrix=cdMatrix) self.wcsB = makeSkyWcs(crpix=Point2D(-50.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.bboxCoadd = Box2I(Point2I(-100, -100), Point2I(99, 99)) self.bboxA = Box2I(Point2I(-100, -50), Point2I(99, 49)) self.bboxB = Box2I(Point2I(-50, -100), Point2I(49, 99)) self.polygonA = None polygonD = Polygon(Box2D(Box2I(Point2I(0, 0), Point2I(49, 99)))) self.polygonB, = polygonD.symDifference(Polygon(Box2D(self.bboxB))) self.curveA = makeRandomTransmissionCurve(self.rng) self.curveB = makeRandomTransmissionCurve(self.rng) self.weightA = 0.6 self.weightB = 0.2 schema = ExposureTable.makeMinimalSchema() weightKey = schema.addField("weight", type=float, doc="relative weight of image in Coadd") catalog = ExposureCatalog(schema) recordA = catalog.addNew() recordA[weightKey] = self.weightA recordA.setWcs(self.wcsA) recordA.setValidPolygon(self.polygonA) recordA.setBBox(self.bboxA) recordA.setTransmissionCurve(self.curveA) recordB = catalog.addNew() recordB[weightKey] = self.weightB recordB.setWcs(self.wcsB) recordB.setValidPolygon(self.polygonB) recordB.setBBox(self.bboxB) recordB.setTransmissionCurve(self.curveB) self.curveCoadd = makeCoaddTransmissionCurve(self.wcsCoadd, catalog)
def testMultiPlaneFitsReaders(self): """Run tests for MaskedImageFitsReader and ExposureFitsReader. """ metadata = PropertyList() metadata.add("FIVE", 5) metadata.add("SIX", 6.0) wcs = makeSkyWcs(Point2D(2.5, 3.75), SpherePoint(40.0 * degrees, 50.0 * degrees), np.array([[1E-5, 0.0], [0.0, -1E-5]])) defineFilter("test_readers_filter", lambdaEff=470.0) calib = PhotoCalib(2.5E4) psf = GaussianPsf(21, 21, 8.0) polygon = Polygon(Box2D(self.bbox)) apCorrMap = ApCorrMap() visitInfo = VisitInfo(exposureTime=5.0) transmissionCurve = TransmissionCurve.makeIdentity() coaddInputs = CoaddInputs(ExposureTable.makeMinimalSchema(), ExposureTable.makeMinimalSchema()) detector = DetectorWrapper().detector record = coaddInputs.ccds.addNew() record.setWcs(wcs) record.setPhotoCalib(calib) record.setPsf(psf) record.setValidPolygon(polygon) record.setApCorrMap(apCorrMap) record.setVisitInfo(visitInfo) record.setTransmissionCurve(transmissionCurve) record.setDetector(detector) for n, dtypeIn in enumerate(self.dtypes): with self.subTest(dtypeIn=dtypeIn): exposureIn = Exposure(self.bbox, dtype=dtypeIn) shape = exposureIn.image.array.shape exposureIn.image.array[:, :] = np.random.randint(low=1, high=5, size=shape) exposureIn.mask.array[:, :] = np.random.randint(low=1, high=5, size=shape) exposureIn.variance.array[:, :] = np.random.randint(low=1, high=5, size=shape) exposureIn.setMetadata(metadata) exposureIn.setWcs(wcs) exposureIn.setFilter(Filter("test_readers_filter")) exposureIn.setFilterLabel( FilterLabel(physical="test_readers_filter")) exposureIn.setPhotoCalib(calib) exposureIn.setPsf(psf) exposureIn.getInfo().setValidPolygon(polygon) exposureIn.getInfo().setApCorrMap(apCorrMap) exposureIn.getInfo().setVisitInfo(visitInfo) exposureIn.getInfo().setTransmissionCurve(transmissionCurve) exposureIn.getInfo().setCoaddInputs(coaddInputs) exposureIn.setDetector(detector) with lsst.utils.tests.getTempFilePath(".fits") as fileName: exposureIn.writeFits(fileName) self.checkMaskedImageFitsReader(exposureIn, fileName, self.dtypes[n:]) self.checkExposureFitsReader(exposureIn, fileName, self.dtypes[n:])
def getWcsForCcd(self, dataRef): try: md = dataRef.get("calexp_md") return afwGeom.makeSkyWcs(md) except Exception as e: print("Failed to read: %s for %s" % (e, dataRef.dataId)) return None
def setUp(self): # Pick arbitrary numbers to create a detector object, and a synthetic # dataset. The particular numbers have no special meaning to the test # and be anything as long as they are self consistent (i.e. the # fake source is inside the bounding box) self.center = lsst.geom.Point2D(50.1, 49.8) self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-20, -30), lsst.geom.Extent2I(140, 160)) self.dataset = lsst.meas.base.tests.TestDataset(self.bbox) self.dataset.addSource(100000.0, self.center) md = dafBase.PropertyList() for k, v in ( ("EQUINOX", 2000.0), ("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'), ): md.set(k, v) self.wcs = makeSkyWcs(md)
def testTicket2872(self): """Test that CoaddPsf.getAveragePosition() is always a position at which we can call computeImage(). """ scale = 0.2*lsst.geom.arcseconds cdMatrix = afwGeom.makeCdMatrix(scale=scale) wcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(50, 50), crval=lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees), cdMatrix=cdMatrix, ) kernel = measAlg.DoubleGaussianPsf(7, 7, 2.0).getKernel() psf1 = measAlg.KernelPsf(kernel, lsst.geom.Point2D(0, 50)) psf2 = measAlg.KernelPsf(kernel, lsst.geom.Point2D(100, 50)) record1 = self.mycatalog.addNew() record1.setPsf(psf1) record1.setWcs(wcs) record1.setD(self.weightKey, 1.0) record1.setBBox(lsst.geom.Box2I(lsst.geom.Point2I(-40, 0), lsst.geom.Point2I(40, 100))) record2 = self.mycatalog.addNew() record2.setPsf(psf2) record2.setWcs(wcs) record2.setD(self.weightKey, 1.0) record2.setBBox(lsst.geom.Box2I(lsst.geom.Point2I(60, 0), lsst.geom.Point2I(140, 100))) coaddPsf = measAlg.CoaddPsf(self.mycatalog, wcs) naiveAvgPos = lsst.geom.Point2D(50, 50) with self.assertRaises(pexExceptions.InvalidParameterError): coaddPsf.computeKernelImage(naiveAvgPos) # important test is that this doesn't throw: coaddPsf.computeKernelImage()
def setUp(self): # Construct an arbitrary WCS for testing. crval = lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees) scale = 0.2*lsst.geom.arcseconds crpix = lsst.geom.PointD(100, 100) self.wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=afwGeom.makeCdMatrix(scale=scale))
def testDefaultSize(self): """Test of both default size and specified size.""" print("DefaultSizeTest") sigma0 = 5 # set the peak of the outer guassian to 0 so this is really a single gaussian. psf = measAlg.DoubleGaussianPsf(60, 60, 1.5*sigma0, 1, 0.0) # Now make the catalog record = self.mycatalog.getTable().makeRecord() psf = measAlg.DoubleGaussianPsf(100, 100, 10.0, 1.00, 1.0) record.setPsf(psf) wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) record.setWcs(wcs) record['weight'] = 1.0 record['id'] = 1 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000)) record.setBBox(bbox) self.mycatalog.append(record) mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref) # , 'weight') m1coadd, m2coadd = getCoaddSecondMoments(mypsf, lsst.geom.Point2D(0, 0)) m1, m2 = getPsfSecondMoments(mypsf, lsst.geom.Point2D(1000, 1000)) self.assertAlmostEqual(m1, m1coadd, delta=.01) self.assertAlmostEqual(m2, m2coadd, delta=.01)
def testValidPolygonPsf(self): """Demonstrate that we can use the validPolygon on Exposures in the CoaddPsf.""" # Create 9 separate records, each with its own peculiar Psf, Wcs, # weight, bounding box, and valid region. for i in range(1, 10): record = self.mycatalog.getTable().makeRecord() record.setPsf(measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)) crpix = lsst.geom.PointD(1000-10.0*i, 1000.0-10.0*i) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=self.crval, cdMatrix=self.cdMatrix) record.setWcs(wcs) record['weight'] = 1.0*(i + 1) record['id'] = i record.setBBox(lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(1000, 1000))) validPolygon = afwGeom.Polygon(lsst.geom.Box2D(lsst.geom.Point2D(0, 0), lsst.geom.Extent2D(i*100, i*100))) record.setValidPolygon(validPolygon) self.mycatalog.append(record) # Create the CoaddPsf and check at three different points to ensure that the validPolygon is working mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref, 'weight') for position in [lsst.geom.Point2D(50, 50), lsst.geom.Point2D(500, 500), lsst.geom.Point2D(850, 850)]: m1coadd, m2coadd = getCoaddSecondMoments(mypsf, position, True) m1, m2 = getPsfSecondMoments(mypsf, position) self.assertAlmostEqual(m1, m1coadd, delta=0.01) self.assertAlmostEqual(m2, m2coadd, delta=0.01)
def testBBox(self): """Check that computeBBox returns same BBox as realized Kernel Image and resized raises a Not Implemented Error""" sigma0 = 5 size = [50, 60, 70, 80] for i in range(4): record = self.mycatalog.getTable().makeRecord() psf = measAlg.DoubleGaussianPsf(size[i], size[i], sigma0, 1.00, 0.0) record.setPsf(psf) wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) record.setWcs(wcs) record['weight'] = 1.0 * (i + 1) record['id'] = i bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000)) record.setBBox(bbox) self.mycatalog.append(record) mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref, 'weight') self.assertEqual(mypsf.computeKernelImage().getBBox(), mypsf.computeBBox()) with self.assertRaises(pexExceptions.LogicError): mypsf.resized(100, 100)
def initialWcs(self, matches, wcs): """Generate a guess Wcs from the astrometric matches We create a Wcs anchored at the center of the matches, with the scale of the input Wcs. This is necessary because matching returns only matches with no estimated Wcs, and the input Wcs is a wild guess. We're using the best of each: positions from the matches, and scale from the input Wcs. Parameters ---------- matches : `list` of `lsst.afw.table.ReferenceMatch` List of sources matched to references. wcs : `lsst.afw.geom.SkyWcs` Current WCS. Returns ------- newWcs : `lsst.afw.geom.SkyWcs` Initial WCS guess from estimated crpix and crval. """ crpix = lsst.geom.Extent2D(0, 0) crval = lsst.sphgeom.Vector3d(0, 0, 0) for mm in matches: crpix += lsst.geom.Extent2D(mm.second.getCentroid()) crval += mm.first.getCoord().getVector() crpix /= len(matches) crval /= len(matches) newWcs = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(crpix), crval=lsst.geom.SpherePoint(crval), cdMatrix=wcs.getCdMatrix()) return newWcs
def makeFocalPlaneWcs(pixelSize, referencePixel): """Make a WCS for the focal plane geometry (i.e. one that returns positions in "mm") Parameters ---------- pixelSize : `float` Size of the image pixels in physical units referencePixel : `lsst.geom.Point2D` Pixel for origin of WCS Returns ------- `lsst.afw.geom.Wcs` Wcs object for mapping between pixels and focal plane. """ md = dafBase.PropertySet() if referencePixel is None: referencePixel = lsst.geom.PointD(0, 0) for i in range(2): md.set("CRPIX%d"%(i + 1), referencePixel[i]) md.set("CRVAL%d"%(i + 1), 0.) md.set("CDELT1", pixelSize[0]) md.set("CDELT2", pixelSize[1]) md.set("CTYPE1", "CAMERA_X") md.set("CTYPE2", "CAMERA_Y") md.set("CUNIT1", "mm") md.set("CUNIT2", "mm") return afwGeom.makeSkyWcs(md)
def testGeometry(self): bigBox = lsst.geom.Box2D(lsst.geom.Box2I(self.bbox0)) bigBox.include(lsst.geom.Box2D(self.bbox1)) points = (np.random.rand(100, 2)*np.array([bigBox.getWidth(), bigBox.getHeight()]) + np.array([bigBox.getMinX(), bigBox.getMinY()])) # make a very slightly perturbed wcs so the celestial transform isn't a # no-op crval2 = self.wcs.getSkyOrigin() crval2 = lsst.geom.SpherePoint(crval2.getLongitude() + 5*arcseconds, crval2.getLatitude() - 5*arcseconds) wcs2 = makeSkyWcs( crval=crval2, crpix=self.wcs.getPixelOrigin() + lsst.geom.Extent2D(30.0, -50.0), cdMatrix=self.wcs.getCdMatrix()*1.1, ) for x1, y1 in points: p1 = lsst.geom.Point2D(x1, y1) c = self.wcs.pixelToSky(p1) p2 = wcs2.skyToPixel(c) subset1 = self.cat.subsetContaining(c) subset2 = self.cat.subsetContaining(p2, wcs2) for record in self.cat: inside = lsst.geom.Box2D(record.getBBox()).contains(p1) self.assertEqual(inside, record.contains(c)) self.assertEqual(inside, record.contains(p2, wcs2)) self.assertEqual(inside, record.contains(p1, self.wcs)) self.assertEqual(inside, record in subset1) self.assertEqual(inside, record in subset2) crazyPoint = lsst.geom.SpherePoint(crval2.getLongitude() + np.pi*radians, crval2.getLatitude()) subset3 = self.cat.subsetContaining(crazyPoint) self.assertEqual(len(subset3), 0)
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 self.wcs = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(1500, 1500), crval=lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=5.1e-5*lsst.geom.degrees)) self.bboxD = lsst.geom.Box2D(lsst.geom.Point2D(10, 100), lsst.geom.Extent2D(1000, 1500)) self.numMatches = 25 sourceSchema = afwTable.SourceTable.makeMinimalSchema() # add centroid (and many other unwanted fields) to sourceSchema 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 = [lsst.geom.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 makeTestExposure(self, xNumPix, yNumPix): """ Create and return an exposure that is completely covered by the database: test_select_lsst_images """ metadata = lsst.daf.base.PropertySet() metadata.set("NAXIS", 2) metadata.set("RADECSYS", "ICRS") metadata.set("EQUINOX", 2000.) metadata.setDouble("CRVAL1", 60.000000000000) metadata.setDouble("CRVAL2", 10.812316963572) metadata.setDouble("CRPIX1", 700000.00000000) metadata.setDouble("CRPIX2", 601345.00000000) metadata.set("CTYPE1", "RA---STG") metadata.set("CTYPE2", "DEC--STG") metadata.setDouble("CD1_1", -5.5555555555556e-05) metadata.setDouble("CD1_2", 0.0000000000000) metadata.setDouble("CD2_2", 5.5555555555556e-05) metadata.setDouble("CD2_1", 0.0000000000000) metadata.set("CUNIT1", "deg") metadata.set("CUNIT2", "deg") # exposure needs a wcs and a bbox wcs = afwGeom.makeSkyWcs(metadata) bbox = afwGeom.Box2I(afwGeom.Point2I(327750, 235750), afwGeom.Extent2I(xNumPix, yNumPix)) exposure = afwImage.ExposureF(bbox, wcs) mi = exposure.getMaskedImage() mi.set(1.0) mi.getVariance().set(1.0) return exposure
def testRotatePsf(self): """Check that we can create a CoaddPsf with 10 elements.""" print("RotatePsfTest") cdMatrix = afwGeom.makeCdMatrix( scale=5.55555555e-05*lsst.geom.degrees, orientation=90*lsst.geom.degrees, flipX=True, ) wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=cdMatrix) # make a single record with an oblong Psf record = self.mycatalog.getTable().makeRecord() psf = makeBiaxialGaussianPsf(100, 100, 1.0, 6.0, 0.0) record.setPsf(psf) record.setWcs(wcs) record['weight'] = 1.0 record['id'] = 1 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000)) record.setBBox(bbox) self.mycatalog.append(record) mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref) m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments(psf, lsst.geom.Point2D(0.25, 0.75)) cm0, cxbar, cybar, cmxx, cmyy, cx0, cy0 = getPsfMoments(mypsf, lsst.geom.Point2D(0.25, 0.75)) self.assertAlmostEqual(mxx, cmyy, delta=0.01) self.assertAlmostEqual(myy, cmxx, delta=0.01)
def testLoadPixelBox(self): """Test LoadIndexedReferenceObjectsTask.loadPixelBox with default config.""" loader = LoadIndexedReferenceObjectsTask(butler=self.testButler) numFound = 0 for tupl, idList in self.compCats.items(): cent = make_coord(*tupl) bbox = lsst.geom.Box2I(lsst.geom.Point2I(30, -5), lsst.geom.Extent2I(1000, 1004)) # arbitrary ctr_pix = bbox.getCenter() # catalog is sparse, so set pixel scale such that bbox encloses region # used to generate compCats pixel_scale = 2*self.searchRadius/max(bbox.getHeight(), bbox.getWidth()) cdMatrix = afwGeom.makeCdMatrix(scale=pixel_scale) wcs = afwGeom.makeSkyWcs(crval=cent, crpix=ctr_pix, cdMatrix=cdMatrix) result = loader.loadPixelBox(bbox=bbox, wcs=wcs, filterName="a") # The following is to ensure the reference catalog coords are # getting corrected for proper motion when an epoch is provided. # Use an extreme epoch so that differences in corrected coords # will be significant. Note that this simply tests that the coords # do indeed change when the epoch is passed. It makes no attempt # at assessing the correctness of the change. This is left to the # explicit testProperMotion() test below. resultWithEpoch = loader.loadPixelBox(bbox=bbox, wcs=wcs, filterName="a", epoch=astropy.time.Time(20000, format='mjd', scale="tai")) self.assertFloatsNotEqual(result.refCat["coord_ra"], resultWithEpoch.refCat["coord_ra"], rtol=1.0e-4) self.assertFloatsNotEqual(result.refCat["coord_dec"], resultWithEpoch.refCat["coord_dec"], rtol=1.0e-4) self.assertFalse("camFlux" in result.refCat.schema) self.assertGreaterEqual(len(result.refCat), len(idList)) numFound += len(result.refCat) self.assertGreater(numFound, 0)
def setUp(self): np.random.seed(12345) self.config = measAstrom.MatchPessimisticBTask.ConfigClass() # Value below is to assure all matches are selected. The # original test is set for a 3 arcsecond max match distance # using matchOptimisticB. self.config.minMatchDistPixels = 2.0 self.MatchPessimisticB = measAstrom.MatchPessimisticBTask( config=self.config) self.wcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(791.4, 559.7), crval=lsst.geom.SpherePoint(36.930640, -4.939560, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=5.17e-5 * lsst.geom.degrees)) self.distortedWcs = self.wcs self.filename = os.path.join(os.path.dirname(__file__), "cat.xy.fits") self.tolArcsec = .4 self.tolPixel = .1 # 3 of the objects are removed by the source selector and are used in # matching hence the 183 number vs the total of 186. This is also why # these three objects are missing in the testReferenceFilter test. self.expectedMatches = 183
def setUp(self): np.random.seed(12345) self.config = measAstrom.MatchPessimisticBTask.ConfigClass() # Value below is to assure all matches are selected. The # original test is set for a 3 arcsecond max match distance # using matchOptimisticB. self.config.minMatchDistPixels = 2.0 self.MatchPessimisticB = measAstrom.MatchPessimisticBTask( config=self.config) self.wcs = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(791.4, 559.7), crval=lsst.geom.SpherePoint(36.930640, -4.939560, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=5.17e-5*lsst.geom.degrees)) self.distortedWcs = self.wcs self.filename = os.path.join(os.path.dirname(__file__), "cat.xy.fits") self.tolArcsec = .4 self.tolPixel = .1 # 3 of the objects are removed by the source selector and are used in # matching hence the 183 number vs the total of 186. This is also why # these three objects are missing in the testReferenceFilter test. self.expectedMatches = 183
def std_raw(self, item, dataId): #This creates an approximate wcs based on RA-TEL and DEC-TEL. raw = super(GotoMapper, self).std_raw(item, dataId) md = raw.getMetadata() ra_deg = (coordinates.Angle(md.get('RA-TEL'), unit=units.hour).deg) de_deg = (coordinates.Angle(md.get('DEC-TEL'), unit=units.deg).deg) md.setDouble("CRVAL1", ra_deg) md.setDouble("CRVAL2", de_deg) md.setDouble("CRPIX1", 0.) md.setDouble("CRPIX2", 0.) md.setDouble('CDELT1',1.0) md.setDouble('CDELT2',1.0) md.set("CUNIT1",'deg') md.set("CUNIT2",'deg') md.setDouble("CD1_1", 1.0E-6) md.setDouble("CD1_2", -3.4E-04) md.setDouble("CD2_1", 3.4E-04) md.setDouble("CD2_2", 1.0E-6) md.set("CTYPE1", 'RA---TAN-SIP') md.set("CTYPE2", 'DEC--TAN-SIP') wcs = afwGeom.makeSkyWcs(md) raw.setWcs(wcs) return raw
def test(self): schema = afwTable.ExposureTable.makeMinimalSchema() schema.addField("ccd", np.int32, doc="CCD number") schema.addField("visit", np.int32, doc="Visit number") schema.addField("goodpix", np.int32, doc="Number of good pixels") schema.addField("weight", float, doc="Weighting for this CCD") ccds = afwTable.ExposureCatalog(schema) scale = 1.0e-4*lsst.geom.degrees wcs = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(0.0, 0.0), crval=lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees), cdMatrix=afwGeom.makeCdMatrix(scale=scale)) new = ccds.addNew() new.set("id", 0) new.set("bbox_min_x", 0) new.set("bbox_min_y", 0) new.set("bbox_max_x", 1024) new.set("bbox_max_y", 1024) # The following lines are critical for reproducing the bug, because # the code is reading a double starting at the 'ccd' (offset 24), and # it sees a zero (from the zero in 'ccd' and the leading zeros in 'visit'). new.set("ccd", 0) new.set("visit", 6789) new.set("goodpix", 987654321) new.set("weight", 1.0) new.setPsf(measAlg.SingleGaussianPsf(23, 23, 2.345)) new.setWcs(wcs) # In the presence of the bug, the following fails with # lsst::pex::exceptions::RuntimeError thrown in src/CoaddPsf.cc # with message: "Could not find a valid average position for CoaddPsf" measAlg.CoaddPsf(ccds, wcs)
def testLargeTransform(self): """Test that images with bad astrometry are identified""" multiplier = 1000.0 # CD matrix multiplier for bad input badId = 1 # ID of bad input for ii in range(3): record = self.mycatalog.addNew() record.setPsf(measAlg.DoubleGaussianPsf(50, 50, 5.0, 1.00, 0.0)) cdMatrix = self.cdMatrix if ii == badId: # This image has bad astrometry: cdMatrix *= multiplier record['id'] = ii record['weight'] = 1.0 record.setWcs( afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=cdMatrix)) record.setBBox( lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000))) coaddPsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref) with self.assertRaises(pexExceptions.RangeError) as cm: coaddPsf.computeKernelImage() self.assertIn("id=%d" % (badId, ), str(cm.exception))
def makeWcs(offset=0): """ Make a fake Wcs Parameters ---------- offset : float offset the Wcs by this many pixels. """ # taken from $AFW_DIR/tests/testMakeWcs.py metadata = dafBase.PropertySet() metadata.set("SIMPLE", "T") metadata.set("BITPIX", -32) metadata.set("NAXIS", 2) metadata.set("NAXIS1", 1024) metadata.set("NAXIS2", 1153) metadata.set("RADESYS", 'FK5') metadata.set("EQUINOX", 2000.) metadata.setDouble("CRVAL1", 215.604025685476) metadata.setDouble("CRVAL2", 53.1595451514076) metadata.setDouble("CRPIX1", 1109.99981456774 + offset) metadata.setDouble("CRPIX2", 560.018167811613 + offset) metadata.set("CTYPE1", 'RA---SIN') metadata.set("CTYPE2", 'DEC--SIN') 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) return afwGeom.makeSkyWcs(metadata)
def getWcsFromDetector(detector, boresight, rotation=0 * geom.degrees, flipX=False): """Given a detector and (boresight, rotation), return that detector's WCS Parameters ---------- camera : `lsst.afw.cameraGeom.Camera` The camera containing the detector. detector : `lsst.afw.cameraGeom.Detector` A detector in a camera. boresight : `lsst.afw.geom.SpherePoint` The boresight of the observation. rotation : `lsst.afw.geom.Angle`, optional The rotation angle of the camera. The rotation is "rotskypos", the angle of sky relative to camera coordinates (from North over East). flipX : `bool`, optional Flip the X axis? Returns ------- wcs : `lsst::afw::geom::SkyWcs` The calculated WCS. """ trans = detector.getTransform( detector.makeCameraSys(cameraGeom.PIXELS), detector.makeCameraSys(cameraGeom.FIELD_ANGLE)) wcs = afwGeom.makeSkyWcs(trans, rotation, flipX, boresight) return wcs
def makeFocalPlaneWcs(pixelSize, referencePixel): """Make a WCS for the focal plane geometry (i.e. one that returns positions in "mm") Parameters ---------- pixelSize : `float` Size of the image pixels in physical units referencePixel : `lsst.geom.Point2D` Pixel for origin of WCS Returns ------- `lsst.afw.geom.Wcs` Wcs object for mapping between pixels and focal plane. """ md = dafBase.PropertySet() if referencePixel is None: referencePixel = lsst.geom.PointD(0, 0) for i in range(2): md.set("CRPIX%d" % (i + 1), referencePixel[i]) md.set("CRVAL%d" % (i + 1), 0.) md.set("CDELT1", pixelSize[0]) md.set("CDELT2", pixelSize[1]) md.set("CTYPE1", "CAMERA_X") md.set("CTYPE2", "CAMERA_Y") md.set("CUNIT1", "mm") md.set("CUNIT2", "mm") return afwGeom.makeSkyWcs(md)
def getSwarpedImage(self, kernelName, useSubregion=False, useDeepCopy=False): """ Inputs: - kernelName: name of kernel in the form used by afwImage.makeKernel - useSubregion: if True then the original source exposure (from which the usual test exposure was extracted) is read and the correct subregion extracted - useDeepCopy: if True then the copy of the subimage is a deep copy, else it is a shallow copy; ignored if useSubregion is False Returns: - originalExposure - swarpedImage - swarpedWcs """ if useSubregion: originalFullExposure = afwImage.ExposureF(originalExposurePath) # "medsub" is a subregion of med starting at 0-indexed pixel (40, 150) of size 145 x 200 bbox = lsst.geom.Box2I(lsst.geom.Point2I(40, 150), lsst.geom.Extent2I(145, 200)) originalExposure = afwImage.ExposureF( originalFullExposure, bbox, afwImage.LOCAL, useDeepCopy) swarpedImageName = "medsubswarp1%s.fits" % (kernelName,) else: originalExposure = afwImage.ExposureF(originalExposurePath) swarpedImageName = "medswarp1%s.fits" % (kernelName,) swarpedImagePath = os.path.join(dataDir, swarpedImageName) swarpedDecoratedImage = afwImage.DecoratedImageF(swarpedImagePath) swarpedImage = swarpedDecoratedImage.getImage() swarpedMetadata = swarpedDecoratedImage.getMetadata() swarpedWcs = afwGeom.makeSkyWcs(swarpedMetadata) return (originalExposure, swarpedImage, swarpedWcs)
def makeDummyWcs(self, rotAngle, pixelScale, crval, flipX=True): """Make a World Coordinate System object for testing. Parameters ---------- rotAngle : `lsst.geom.Angle` rotation of the CD matrix, East from North pixelScale : `lsst.geom.Angle` Pixel scale of the projection. crval : `lsst.afw.geom.SpherePoint` Coordinates of the reference pixel of the wcs. flipX : `bool`, optional Flip the direction of increasing Right Ascension. Returns ------- `lsst.afw.geom.skyWcs.SkyWcs` A wcs that matches the inputs. """ crpix = geom.Box2D(self.bbox).getCenter() cdMatrix = afwGeom.makeCdMatrix(scale=pixelScale, orientation=rotAngle, flipX=flipX) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cdMatrix) return wcs
def _create_wcs(bbox, pixel_scale, ra, dec, sky_rotation): """Create a wcs (coordinate system). Parameters ---------- bbox : lsst.afw.geom.Box2I object A bounding box. pixel_scale : lsst.afw.geom.Angle Plate scale, as an Angle. ra : lsst.afw.geom.Angle Right Ascension of the reference pixel, as an `Angle`. dec : lsst.afw.geom.Angle Declination of the reference pixel, as an Angle. sky_rotation : lsst.afw.geom.Angle Rotation of the image axis, East from North. Returns ------- Returns a lsst.afw.image.wcs object. """ crval = afwGeom.SpherePoint(ra, dec) crpix = afwGeom.Box2D(bbox).getCenter() cd_matrix = makeCdMatrix(scale=pixel_scale, orientation=sky_rotation, flipX=True) wcs = makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd_matrix) return(wcs)
def makeLocalTransformMatrix(self, wcs, center, skyCenter): """Create a local, linear approximation of the wcs transformation matrix. The approximation is created as if the center is at RA=0, DEC=0. All comparing x,y coordinate are relative to the position of center. Matrix is initially calculated with units arcseconds and then converted to degrees. This yields higher precision results due to quirks in AST. Parameters ---------- wcs : `lsst.afw.geom.SkyWcs` Wcs to approximate center : `lsst.geom.Point2D` Point at which to evaluate the LocalWcs. skyCenter : `lsst.geom.SpherePoint` Point on sky to approximate the Wcs. Returns ------- localMatrix : `numpy.ndarray` Matrix representation the local wcs approximation with units degrees. """ blankCDMatrix = [[self._scale, 0], [0, self._scale]] localGnomonicWcs = afwGeom.makeSkyWcs(center, skyCenter, blankCDMatrix) measurementToLocalGnomonic = wcs.getTransform().then( localGnomonicWcs.getTransform().inverted()) localMatrix = measurementToLocalGnomonic.getJacobian(center) return localMatrix / 3600
def bypass_instcal(self, datasetType, pythonType, butlerLocation, dataId): # Workaround until I can access the butler instcalMap = self.map_instcal(dataId) dqmaskMap = self.map_dqmask(dataId) wtmapMap = self.map_wtmap(dataId) instcalType = getattr(afwImage, instcalMap.getPythonType().split(".")[-1]) dqmaskType = getattr(afwImage, dqmaskMap.getPythonType().split(".")[-1]) wtmapType = getattr(afwImage, wtmapMap.getPythonType().split(".")[-1]) instcal = instcalType(instcalMap.getLocationsWithRoot()[0]) dqmask = dqmaskType(dqmaskMap.getLocationsWithRoot()[0]) wtmap = wtmapType(wtmapMap.getLocationsWithRoot()[0]) mask = self.translate_dqmask(dqmask) variance = self.translate_wtmap(wtmap) mi = afwImage.MaskedImageF(afwImage.ImageF(instcal.getImage()), mask, variance) md = readMetadata(instcalMap.getLocationsWithRoot()[0]) wcs = makeSkyWcs(md, strip=True) exp = afwImage.ExposureF(mi, wcs) exp.setPhotoCalib( afwImage.makePhotoCalibFromCalibZeroPoint( 10**(0.4 * md.getScalar("MAGZERO")), 0)) visitInfo = self.makeRawVisitInfo(md=md) exp.getInfo().setVisitInfo(visitInfo) for kw in ('LTV1', 'LTV2'): md.remove(kw) exp.setMetadata(md) return exp
def testValidPolygonPsf(self): """Demonstrate that we can use the validPolygon on Exposures in the CoaddPsf.""" # Create 9 separate records, each with its own peculiar Psf, Wcs, # weight, bounding box, and valid region. for i in range(1, 10): record = self.mycatalog.getTable().makeRecord() record.setPsf(measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)) crpix = lsst.geom.PointD(1000 - 10.0 * i, 1000.0 - 10.0 * i) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=self.crval, cdMatrix=self.cdMatrix) record.setWcs(wcs) record['weight'] = 1.0 * (i + 1) record['id'] = i record.setBBox( lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(1000, 1000))) validPolygon = afwGeom.Polygon( lsst.geom.Box2D(lsst.geom.Point2D(0, 0), lsst.geom.Extent2D(i * 100, i * 100))) record.setValidPolygon(validPolygon) self.mycatalog.append(record) # Create the CoaddPsf and check at three different points to ensure that the validPolygon is working mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref, 'weight') for position in [ lsst.geom.Point2D(50, 50), lsst.geom.Point2D(500, 500), lsst.geom.Point2D(850, 850) ]: m1coadd, m2coadd = getCoaddSecondMoments(mypsf, position, True) m1, m2 = getPsfSecondMoments(mypsf, position) self.assertAlmostEqual(m1, m1coadd, delta=0.01) self.assertAlmostEqual(m2, m2coadd, delta=0.01)
def testTicket2872(self): """Test that CoaddPsf.getAveragePosition() is always a position at which we can call computeImage(). """ scale = 0.2 * lsst.geom.arcseconds cdMatrix = afwGeom.makeCdMatrix(scale=scale) wcs = afwGeom.makeSkyWcs( crpix=lsst.geom.Point2D(50, 50), crval=lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees), cdMatrix=cdMatrix, ) kernel = measAlg.DoubleGaussianPsf(7, 7, 2.0).getKernel() psf1 = measAlg.KernelPsf(kernel, lsst.geom.Point2D(0, 50)) psf2 = measAlg.KernelPsf(kernel, lsst.geom.Point2D(100, 50)) record1 = self.mycatalog.addNew() record1.setPsf(psf1) record1.setWcs(wcs) record1.setD(self.weightKey, 1.0) record1.setBBox( lsst.geom.Box2I(lsst.geom.Point2I(-40, 0), lsst.geom.Point2I(40, 100))) record2 = self.mycatalog.addNew() record2.setPsf(psf2) record2.setWcs(wcs) record2.setD(self.weightKey, 1.0) record2.setBBox( lsst.geom.Box2I(lsst.geom.Point2I(60, 0), lsst.geom.Point2I(140, 100))) coaddPsf = measAlg.CoaddPsf(self.mycatalog, wcs) naiveAvgPos = lsst.geom.Point2D(50, 50) with self.assertRaises(pexExceptions.InvalidParameterError): coaddPsf.computeKernelImage(naiveAvgPos) # important test is that this doesn't throw: coaddPsf.computeKernelImage(coaddPsf.getAveragePosition())
def testDefaultSize(self): """Test of both default size and specified size.""" print("DefaultSizeTest") sigma0 = 5 # set the peak of the outer guassian to 0 so this is really a single gaussian. psf = measAlg.DoubleGaussianPsf(60, 60, 1.5 * sigma0, 1, 0.0) # Now make the catalog record = self.mycatalog.getTable().makeRecord() psf = measAlg.DoubleGaussianPsf(100, 100, 10.0, 1.00, 1.0) record.setPsf(psf) wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) record.setWcs(wcs) record['weight'] = 1.0 record['id'] = 1 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000)) record.setBBox(bbox) self.mycatalog.append(record) mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref) # , 'weight') m1coadd, m2coadd = getCoaddSecondMoments(mypsf, lsst.geom.Point2D(0, 0)) m1, m2 = getPsfSecondMoments(mypsf, lsst.geom.Point2D(1000, 1000)) self.assertAlmostEqual(m1, m1coadd, delta=.01) self.assertAlmostEqual(m2, m2coadd, delta=.01)
def testRotatePsf(self): """Check that we can create a CoaddPsf with 10 elements.""" print("RotatePsfTest") cdMatrix = afwGeom.makeCdMatrix( scale=5.55555555e-05 * lsst.geom.degrees, orientation=90 * lsst.geom.degrees, flipX=True, ) wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=cdMatrix) # make a single record with an oblong Psf record = self.mycatalog.getTable().makeRecord() psf = makeBiaxialGaussianPsf(100, 100, 1.0, 6.0, 0.0) record.setPsf(psf) record.setWcs(wcs) record['weight'] = 1.0 record['id'] = 1 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(2000, 2000)) record.setBBox(bbox) self.mycatalog.append(record) mypsf = measAlg.CoaddPsf(self.mycatalog, self.wcsref) m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments( psf, lsst.geom.Point2D(0.25, 0.75)) cm0, cxbar, cybar, cmxx, cmyy, cx0, cy0 = getPsfMoments( mypsf, lsst.geom.Point2D(0.25, 0.75)) self.assertAlmostEqual(mxx, cmyy, delta=0.01) self.assertAlmostEqual(myy, cmxx, delta=0.01)
def setUp(self): crval = lsst.geom.SpherePoint(44, 45, lsst.geom.degrees) crpix = lsst.geom.Point2D(15000, 4000) scale = 1 * lsst.geom.arcseconds cdMatrix = afwGeom.makeCdMatrix(scale=scale, flipX=True) self.tanWcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cdMatrix) self.loadData()
def std_raw_md(self, md, dataId): if False: # no std_raw_md in baseclass md = super(HscMapper, self).std_raw_md(md, dataId) # not present in baseclass # # We need to flip the WCS defined by the metadata in case anyone ever constructs a Wcs from it # wcs = afwGeom.makeSkyWcs(md) wcs = self._flipChipsLR(None, wcs, dataId, dims=afwImage.bboxFromMetadata(md).getDimensions())[1] wcsR = afwGeom.makeSkyWcs(crpix=wcs.getPixelOrigin(), crval=wcs.getSkyOrigin(), cdMatrix=wcs.getCdMatrix()*0.992) wcsMd = wcsR.getFitsMetadata() for k in wcsMd.names(): md.set(k, wcsMd.getScalar(k)) return md
def setUp(self): self.crPix = lsst.geom.Point2D(15000, 4000) dimd = lsst.geom.Extent2D(4000, 4000) bboxd = lsst.geom.Box2D(self.crPix - dimd/2, dimd) self.bbox = lsst.geom.Box2I(bboxd) self.tanWcs = afwGeom.makeSkyWcs(crpix=self.crPix, crval=lsst.geom.SpherePoint(215.5, 53.0, lsst.geom.degrees), cdMatrix=np.array([[5.10808596133527E-05, 1.85579539217196E-07], [-8.27440751733828E-07, -5.10281493481982E-05]]))
def makeit(prefs, context, saveWcs=False, plot=dict()): """This is the python wrapper for the original psfex that reads SExtractor outputs """ # Create an array of PSFs (one PSF for each extension) if prefs.getVerboseType() != prefs.QUIET: print("----- %d input catalogues:" % prefs.getNcat()) if saveWcs: # only needed for making plots wcssList = [] fields = psfexLib.vectorField() for cat in prefs.getCatalogs(): field = psfexLib.Field(cat) wcss = [] wcssList.append(wcss) with fits.open(cat) as pf: for hdu in pf: if hdu.name == "PRIMARY": pass elif hdu.name == "LDAC_IMHEAD": hdr = hdu.data[0][0] # the fits header from the original fits image md = PropertySet() for line in hdr: try: md.set(*splitFitsCard(line)) except AttributeError: continue if not md.exists("CRPIX1"): # no WCS; try WCSA for k in md.names(): if re.search(r"A$", k): md.set(k[:-1], md.getScalar(k)) wcs = afwGeom.makeSkyWcs(md) naxis1, naxis2 = md.getScalar("NAXIS1"), md.getScalar("NAXIS2") elif hdu.name == "LDAC_OBJECTS": nobj = len(hdu.data) assert wcs, "LDAC_OBJECTS comes after LDAC_IMHEAD" field.addExt(wcs, naxis1, naxis2, nobj) if saveWcs: wcss.append((wcs, naxis1, naxis2)) wcs = None field.finalize() fields.append(field) sets = psfexLib.vectorSet() for set in load_samples(prefs, context, plot=plot): sets.append(set) psfexLib.makeit(fields, sets) ret = [[f.getPsfs() for f in fields], sets] if saveWcs: ret.append(wcssList) return ret
def setUp(self): scale = 5.55555555e-05*lsst.geom.degrees self.cdMatrix = afwGeom.makeCdMatrix(scale=scale, flipX=True) self.crpix = lsst.geom.PointD(1000, 1000) self.crval = lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees) self.wcsref = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) schema = afwTable.ExposureTable.makeMinimalSchema() self.weightKey = schema.addField("weight", type="D", doc="Coadd weight") self.mycatalog = afwTable.ExposureCatalog(schema)
def extractCtorArgs(md): wcs = makeSkyWcs(makePropertyListFromDict(md)) kwds = { "pixelToIwc": getPixelToIntermediateWorldCoords(wcs), "bbox": Box2D(Box2I(Point2I(0, 0), Extent2I(md["NAXES1"], md["NAXES2"]))), "crpix": Point2D(md["CRPIX1"] - 1.0, md["CRPIX2"] - 1.0), # -1 for LSST vs. FITS conventions "cd": np.array([[md["CD1_1"], md["CD1_2"]], [md["CD2_1"], md["CD2_2"]]]), } return kwds
def makeCcdMosaic(dir, basename, e, c, aList, imageFactory=afwImage.MaskedImageF, verbose=0): """Return an image of all the specified amplifiers, aList, for the given CCD E.g. sl = makeCcdMosaic("/lsst/DC3root/rlp1173", "v704897", 0, 3, range(8)) """ try: aList[0] except TypeError: aList = [aList] for what in ("header", "data"): if what == "header": bbox = lsst.geom.Box2I() ampBBox = {} wcs = {} else: ccdImage = imageFactory(bbox.getWidth(), bbox.getHeight()) ccdImage.set(0) ccdImage.setXY0(bbox.getLLC()) for a in aList: filename = os.path.join(dir, "IPSD", "output", "sci", "%s-e%d" % (basename, e), "%s-e%d-c%03d-a%02d.sci" % (basename, e, c, a)) if verbose and what == "header": print(filename) if what == "header": md = readMetadata(filename + "_img.fits") xy0 = lsst.geom.Point2I(md.getScalar("CRVAL1A"), md.getScalar("CRVAL2A")) xy1 = xy0 + lsst.geom.Extent2I(md.getScalar("NAXIS1") - 1, md.getScalar("NAXIS2") - 1) bbox.grow(xy0) bbox.grow(xy1) ampBBox[a] = lsst.geom.Box2I(xy0, xy1) wcs[a] = afwGeom.makeSkyWcs(md) else: try: data = imageFactory(filename + "_img.fits") except Exception: data = imageFactory(filename) ampImage = ccdImage.Factory(ccdImage, ampBBox[a]) ampImage[:] = data del ampImage try: ccdImage.getMask() if 0 in wcs: ccdImage = afwImage.ExposureF(ccdImage, wcs[0]) except AttributeError: pass return ccdImage
def testMaskedImage(self): scale = 1.0*lsst.geom.arcseconds wcs = afwGeom.makeSkyWcs(crval=lsst.geom.SpherePoint(0.0*lsst.geom.degrees, 0.0*lsst.geom.degrees), crpix=lsst.geom.Point2D(0.0, 0.0), cdMatrix=afwGeom.makeCdMatrix(scale=scale)) for MaskedImage in (afwImage.MaskedImageF, afwImage.MaskedImageD, ): image = self.createMaskedImage(MaskedImage) self.checkMaskedImages(image) exposure = afwImage.makeExposure(image, wcs) self.checkExposures(exposure)
def makeGalaxy(width, height, flux, a, b, theta, dx=0.0, dy=0.0, xy0=None, xcen=None, ycen=None): """Make a fake galaxy image. """ gal = afwImage.ImageF(width, height) if xcen is None: xcen = 0.5*width + dx if ycen is None: ycen = 0.5*height + dy I0 = flux/(2*math.pi*a*b) if xy0 is not None: gal.setXY0(xy0) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) ii, iuu, ivv = 0.0, 0.0, 0.0 for y in range(height): for x in range(width): dx, dy = x + gal.getX0() - xcen, y + gal.getY0() - ycen if math.hypot(dx, dy) < 10.5: nsample = 5 subZ = np.linspace(-0.5*(1 - 1/nsample), 0.5*(1 - 1/nsample), nsample) else: nsample = 1 subZ = [0.0] val = 0 for sx in subZ: for sy in subZ: u = c*(dx + sx) + s*(dy + sy) v = -s*(dx + sx) + c*(dy + sy) val += I0*math.exp(-0.5*((u/a)**2 + (v/b)**2)) if val < 0: val = 0 gal[afwGeom.Point2I(x, y), afwImage.LOCAL] = val/nsample**2 ii += val iuu += val*u**2 ivv += val*v**2 iuu /= ii ivv /= ii exp = afwImage.makeExposure(afwImage.makeMaskedImage(gal)) exp.getMaskedImage().getVariance().set(1.0) scale = 1.0e-4*afwGeom.degrees cdMatrix = afwGeom.makeCdMatrix(scale=scale, flipX=True) exp.setWcs(afwGeom.makeSkyWcs(crpix=afwGeom.Point2D(0.0, 0.0), crval=afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees), cdMatrix=cdMatrix)) # add a dummy Psf. The new SdssCentroid needs one exp.setPsf(afwDetection.GaussianPsf(11, 11, 0.01)) return exp