def testGainAndReadnoise(self): import lsst.afw.image as afwImage from lsst.afw.cameraGeom.testUtils import DetectorWrapper from lsst.ip.isr import IsrTask isrTask = IsrTask() detector = DetectorWrapper().detector raw = afwImage.ExposureF(detector.getBBox()) level = 10 readNoise = 1 raw.image.set(level) amp = detector[0] amp.setReadNoise(readNoise) for gain in [-1, 0, 0.1, 1]: amp.setGain(gain) isrTask.updateVariance(raw, amp) if gain <= 0: gain = 1 self.assertEqual(raw.variance[0, 0, afwImage.LOCAL], level / gain + readNoise**2)
def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = afwImage.readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwImage.makeWcs(maskedImageMD) self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) self.exposureCrWcs = afwImage.ExposureF( 100, 100, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrOnly = afwImage.ExposureF(afwGeom.ExtentI( 100, 100)) # test with ExtentI(100, 100) too afwImage.Filter.reset() afwImage.FilterProperty.reset() filterPolicy = pexPolicy.Policy() filterPolicy.add("lambdaEff", 470.0) afwImage.Filter.define(afwImage.FilterProperty("g", filterPolicy))
def testConstructorErrors(self): """Test constructor errors """ def duplicateAmpName(dw): """Set two amplifiers to the same name""" dw.ampInfo[1].setName(dw.ampInfo[0].getName()) with self.assertRaises(lsst.pex.exceptions.Exception): DetectorWrapper(modFunc=duplicateAmpName) def addBadCameraSys(dw): """Add an invalid camera system""" dw.transMap[cameraGeom.CameraSys("foo", "wrong detector")] = \ afwGeom.makeIdentityTransform() with self.assertRaises(lsst.pex.exceptions.Exception): DetectorWrapper(modFunc=addBadCameraSys) # These break in the pybind layer for crosstalk in ( [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], # 1D and not numpy np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]), # 1D, wrong numpy type np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], dtype=np.float32), # 1D ): self.assertRaises(TypeError, DetectorWrapper, crosstalk=crosstalk) # These break in the Detector ctor: wrong shape self.assertRaises(lsst.pex.exceptions.InvalidParameterError, DetectorWrapper, crosstalk=np.array([[1.0, 2.0], [3.0, 4.0]])) self.assertRaises(lsst.pex.exceptions.InvalidParameterError, DetectorWrapper, crosstalk=np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]))
def testGainAndReadnoise(self): isrTask = IsrTask() detector = DetectorWrapper().detector raw = afwImage.ExposureF(detector.getBBox()) level = 10 readNoise = 1.5 raw.image.set(level) amp = detector[0] for gain in [-1, 0, 0.1, 1, np.NaN]: # Because amplifiers are immutable, we can't change the gain or # read noise in-place. Instead, we clone, and update the clone. testAmp = Amplifier.Builder() testAmp.assign(amp) testAmp.setReadNoise(readNoise) testAmp.setGain(gain) testAmp.finish() isrTask.updateVariance(raw, testAmp) if gain <= 0: # behave the same way as amp.setGain gain = 1 if math.isnan(gain): gain = 1 self.assertEqual(raw.variance[0, 0, afwImage.LOCAL], level / gain + readNoise**2)
def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwGeom.makeSkyWcs(maskedImageMD, False) self.md = maskedImageMD self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.extras = {"misc": DummyPsf(3.5)} self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) # test with ExtentI(100, 100) too self.exposureCrOnly = afwImage.ExposureF(lsst.geom.ExtentI(100, 100)) afwImage.Filter.reset() afwImage.FilterProperty.reset() defineFilter("g", 470.0)
def testDetectorRebuild(self): """Test Detector.rebuild() method """ # # Make a copy without any modifications # detector = DetectorWrapper().detector ndetector = detector.rebuild().finish() self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) self.assertEqual(detector.getPhysicalType(), ndetector.getPhysicalType()) for amp, namp in zip(detector, ndetector): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) # # Now make a copy with a hacked-up set of amps # builder = detector.rebuild() for i, amp in enumerate(builder, 1): amp.setRawXYOffset(i * lsst.geom.ExtentI(1, 1)) ndetector = builder.finish() self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) for i, (amp, namp) in enumerate(zip(detector, ndetector), 1): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertNotEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) self.assertEqual(namp.getRawXYOffset()[0], i)
def testSetPolygonIntersect(self): # Create a detector detector = DetectorWrapper().detector numPolygonPoints = 50 # Create an exposure with bounding box defined by detector exposure = afwImage.ExposureF(detector.getBBox()) exposure.setDetector(detector) pixelSizeMm = exposure.getDetector().getPixelSize()[0] pixX0 = exposure.getX0() pixY0 = exposure.getY0() pixX1 = pixX0 + exposure.getWidth() - 1 pixY1 = pixY0 + exposure.getHeight() - 1 fpCenter = exposure.getDetector().getCenter(FOCAL_PLANE) fpCenterX = fpCenter[0] fpCenterY = fpCenter[1] pixCenter = exposure.getDetector().getCenter(PIXELS) # Create an instance of IsrTask task = IsrTask() # Make a polygon that encompases entire ccd (radius of 2*max of width/height) fpRadius = 2.0*max(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints) # Set the polygon that is the intersection of fpPolygon and ccd task.setValidPolygonIntersect(exposure, fpPolygon) # Since the ccd is fully contained in the fpPolygon, the intersection should be the ccdPolygon itself ccdPolygonPix = afwGeom.Polygon(exposure.getDetector().getCorners(PIXELS)) self.assertEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # Make a polygon that is entirely within, but smaller than, the ccd # (radius of 0.2*min of width/height) fpRadius = 0.2*min(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints) # Set the polygon that is the intersection of fpPolygon and ccd task.setValidPolygonIntersect(exposure, fpPolygon) # all vertices of polygon should be contained within the ccd for x in exposure.getInfo().getValidPolygon(): self.assertTrue(ccdPolygonPix.contains(lsst.geom.Point2D(x))) # intersection is smaller than the ccd self.assertNotEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # make a simple square polygon that partly intersects the ccd, centered at ccd center fpPolygonSize = max(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeSquarePolygon(fpCenterX, fpCenterY, fpPolygonSize) task.setValidPolygonIntersect(exposure, fpPolygon) # Check that the polygon contains the central pixel (offset by one to actually be "contained") pixCenterPlusOne = lsst.geom.Point2D(pixCenter[0] + 1, pixCenter[1] + 1) self.assertTrue(exposure.getInfo().getValidPolygon().contains(lsst.geom.Point2D(pixCenterPlusOne))) # Check that the polygon contains the upper right ccd edge self.assertTrue(exposure.getInfo().getValidPolygon().contains(lsst.geom.Point2D(pixX1, pixY1)))
def testSetPolygonIntersect(self): # Create a detector detector = DetectorWrapper().detector numPolygonPoints = 50 # Create an exposure with bounding box defined by detector exposure = afwImage.ExposureF(detector.getBBox()) exposure.setDetector(detector) pixelSizeMm = exposure.getDetector().getPixelSize()[0] pixX0 = exposure.getX0() pixY0 = exposure.getY0() pixX1 = pixX0 + exposure.getWidth() - 1 pixY1 = pixY0 + exposure.getHeight() - 1 fpCenter = exposure.getDetector().getCenter(FOCAL_PLANE) fpCenterX = fpCenter[0] fpCenterY = fpCenter[1] pixCenter = exposure.getDetector().getCenter(PIXELS) # Create an instance of IsrTask task = IsrTask() # Make a polygon that encompases entire ccd (radius of 2*max of width/height) fpRadius = 2.0*max(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints) # Set the polygon that is the intersection of fpPolygon and ccd task.setValidPolygonIntersect(exposure, fpPolygon) # Since the ccd is fully contained in the fpPolygon, the intersection should be the ccdPolygon itself ccdPolygonPix = afwGeom.Polygon(exposure.getDetector().getCorners(PIXELS)) self.assertEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # Make a polygon that is entirely within, but smaller than, the ccd # (radius of 0.2*min of width/height) fpRadius = 0.2*min(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints) # Set the polygon that is the intersection of fpPolygon and ccd task.setValidPolygonIntersect(exposure, fpPolygon) # all vertices of polygon should be contained within the ccd for x in exposure.getInfo().getValidPolygon(): self.assertTrue(ccdPolygonPix.contains(afwGeom.Point2D(x))) # intersection is smaller than the ccd self.assertNotEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # make a simple square polygon that partly intersects the ccd, centered at ccd center fpPolygonSize = max(exposure.getWidth()*pixelSizeMm, exposure.getHeight()*pixelSizeMm) fpPolygon = makeSquarePolygon(fpCenterX, fpCenterY, fpPolygonSize) task.setValidPolygonIntersect(exposure, fpPolygon) # Check that the polygon contains the central pixel (offset by one to actually be "contained") pixCenterPlusOne = afwGeom.Point2D(pixCenter[0] + 1, pixCenter[1] + 1) self.assertTrue(exposure.getInfo().getValidPolygon().contains(afwGeom.Point2D(pixCenterPlusOne))) # Check that the polygon contains the upper right ccd edge self.assertTrue(exposure.getInfo().getValidPolygon().contains(afwGeom.Point2D(pixX1, pixY1)))
def testCopyDetector(self): """Test copyDetector() method """ # # Make a copy without any modifications # detector = DetectorWrapper().detector ndetector = cameraGeom.copyDetector(detector) self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) self.assertEqual(detector.getPhysicalType(), ndetector.getPhysicalType()) for amp, namp in zip(detector, ndetector): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) # # Now make a copy with a hacked-up set of amps # ampInfoCatalog = detector.getAmpInfoCatalog().copy(deep=True) for i, amp in enumerate(ampInfoCatalog, 1): amp.setRawXYOffset(i * lsst.geom.ExtentI(1, 1)) ndetector = cameraGeom.copyDetector(detector, ampInfoCatalog=ampInfoCatalog) self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) for i, (amp, namp) in enumerate(zip(detector, ndetector), 1): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertNotEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) self.assertEqual(namp.getRawXYOffset()[0], i)
def testConstructorErrors(self): """Test constructor errors """ def duplicateAmpName(dw): """Set two amplifiers to the same name""" dw.ampInfo[1].setName(dw.ampInfo[0].getName()) with self.assertRaises(lsst.pex.exceptions.Exception): DetectorWrapper(modFunc=duplicateAmpName) def addBadCameraSys(dw): """Add an invalid camera system""" dw.transMap[cameraGeom.CameraSys("foo", "wrong detector")] = \ afwGeom.IdentityXYTransform() with self.assertRaises(lsst.pex.exceptions.Exception): DetectorWrapper(modFunc=addBadCameraSys)
def setUp(self): nSources = 10 # CFHT Filters from the camera mapper. afwImageUtils.resetFilters() afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301") afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401") afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601") afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701") afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801") self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(1024, 1153)) dataset = measTests.TestDataset(self.bbox) for srcIdx in range(nSources): dataset.addSource(100000.0, geom.Point2D(100, 100)) self.inputCatalogNoFlags, _ = make_input_source_catalog(dataset, False) self.inputCatalog, self.exposure = \ make_input_source_catalog(dataset, True) detector = DetectorWrapper(id=23, bbox=self.exposure.getBBox()).detector visit = afwImage.VisitInfo(exposureId=4321, exposureTime=200., date=dafBase.DateTime(nsecs=1400000000 * 10**9)) self.exposure.setDetector(detector) self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter(afwImage.Filter('g.MP9401')) scale = 2 scaleErr = 1 self.photoCalib = afwImage.PhotoCalib(scale, scaleErr) self.exposure.setPhotoCalib(self.photoCalib)
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 testTransform(self): """Test the transform method """ dw = DetectorWrapper() pixOffset = dw.orientation.getReferencePoint() for xyMM in ((25.6, -31.07), (0, 0), (-1.234e5, 3.123e4)): fpPoint = afwGeom.Point2D(*xyMM) fpCamPoint = cameraGeom.CameraPoint(fpPoint, cameraGeom.FOCAL_PLANE) pixCamPoint = dw.detector.transform(fpCamPoint, cameraGeom.PIXELS) pixPoint = pixCamPoint.getPoint() for i in range(2): self.assertAlmostEquals( fpPoint[i] / dw.pixelSize[i] + pixOffset[i], pixPoint[i]) fpCamPoint2 = dw.detector.transform(pixCamPoint, cameraGeom.FOCAL_PLANE) fpPoint2 = fpCamPoint2.getPoint() for i in range(2): self.assertAlmostEquals(fpPoint[i], fpPoint2[i]) # test pix to pix pixCamPoint2 = dw.detector.transform(pixCamPoint, cameraGeom.PIXELS) for i in range(2): self.assertAlmostEquals(pixCamPoint.getPoint()[i], pixCamPoint2.getPoint()[i]) # make sure you cannot transform to a different detector pixCamPoint = dw.detector.makeCameraPoint(afwGeom.Point2D(1, 1), cameraGeom.PIXELS) otherCamSys = cameraGeom.CameraSys(cameraGeom.PIXELS, "other detector") with self.assertRaises(lsst.pex.exceptions.Exception): dw.detector.transform(pixCamPoint, otherCamSys)
def setUp(self): super().setUp() afwImage.Filter.reset() afwImage.FilterProperty.reset() defineFilter("g", 470.0) self.wcs = afwGeom.makeSkyWcs( lsst.geom.Point2D(0.0, 0.0), lsst.geom.SpherePoint(2.0, 34.0, lsst.geom.degrees), np.identity(2), ) self.photoCalib = afwImage.PhotoCalib(1.5) self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.summaryStats = afwImage.ExposureSummaryStats(ra=100.0) self.polygon = afwGeom.Polygon( lsst.geom.Box2D(lsst.geom.Point2D(0.0, 0.0), lsst.geom.Point2D(25.0, 20.0))) self.coaddInputs = afwImage.CoaddInputs() self.apCorrMap = afwImage.ApCorrMap() self.transmissionCurve = afwImage.TransmissionCurve.makeIdentity() self.exposureInfo = afwImage.ExposureInfo() gFilter = afwImage.Filter("g") gFilterLabel = afwImage.FilterLabel(band="g") self.exposureInfo.setFilter(gFilter) self.exposureInfo.setFilterLabel(gFilterLabel)
def testConstructorErrors(self): """Test constructor errors """ def duplicateAmpName(dw): """Set two amplifiers to the same name""" dw.ampInfo[1].setName(dw.ampInfo[0].getName()) with self.assertRaises(lsst.pex.exceptions.Exception): DetectorWrapper(modFunc=duplicateAmpName) # These break in the pybind layer for crosstalk in ( [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], # 1D and not numpy np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]), # 1D, wrong numpy type np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], dtype=np.float32), # 1D ): self.assertRaises(TypeError, DetectorWrapper, crosstalk=crosstalk) # These break in the Detector ctor: wrong shape self.assertRaises(lsst.pex.exceptions.InvalidParameterError, DetectorWrapper, crosstalk=np.array([[1.0, 2.0], [3.0, 4.0]])) self.assertRaises(lsst.pex.exceptions.InvalidParameterError, DetectorWrapper, crosstalk=np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]))
def testTransform(self): """Test the transform method """ dw = DetectorWrapper() pixOffset = dw.orientation.getReferencePoint() for xyMM in ((25.6, -31.07), (0, 0), (-1.234e5, 3.123e4)): fpPoint = afwGeom.Point2D(*xyMM) pixPoint = dw.detector.transform(fpPoint, cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS) for i in range(2): self.assertAlmostEqual( fpPoint[i] / dw.pixelSize[i] + pixOffset[i], pixPoint[i]) fpPoint2 = dw.detector.transform(pixPoint, cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE) self.assertPairsAlmostEqual(fpPoint, fpPoint2) # test pix to pix pixPoint2 = dw.detector.transform(pixPoint, cameraGeom.PIXELS, cameraGeom.PIXELS) self.assertPairsAlmostEqual(pixPoint, pixPoint2) # make sure you cannot transform to or from a different detector otherCamSys = cameraGeom.CameraSys(cameraGeom.PIXELS, "other detector") for goodSys in (cameraGeom.PIXELS, cameraGeom.FOCAL_PLANE): with self.assertRaises(lsst.pex.exceptions.Exception): dw.detector.transform(pixPoint, goodSys, otherCamSys) with self.assertRaises(lsst.pex.exceptions.Exception): dw.detector.transform(pixPoint, otherCamSys, goodSys)
def test_makeWcs_fail_if_detector_is_bad(self): """If Detector is broken, raise an exception. """ # This detector doesn't know about FIELD_ANGLE, so can't be used to # make a SkyWcs. detector = DetectorWrapper().detector with self.assertRaises(InitialSkyWcsError): self.formatter.makeWcs(self.visitInfo, detector)
def testCopyDetector(self): """Test copyDetector() method """ # # Make a copy without any modifications # detector = DetectorWrapper().detector ndetector = cameraGeom.copyDetector(detector) self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) self.assertEqual(detector.getPhysicalType(), ndetector.getPhysicalType()) for amp, namp in zip(detector, ndetector): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) # # Now make a copy with a hacked-up set of amps # ampInfoCatalog = detector.getAmpInfoCatalog().copy(deep=True) for i, amp in enumerate(ampInfoCatalog, 1): amp.setRawXYOffset(i*lsst.geom.ExtentI(1, 1)) ndetector = cameraGeom.copyDetector( detector, ampInfoCatalog=ampInfoCatalog) self.assertEqual(detector.getName(), ndetector.getName()) self.assertEqual(detector.getBBox(), ndetector.getBBox()) for i, (amp, namp) in enumerate(zip(detector, ndetector), 1): self.assertEqual(amp.getBBox(), namp.getBBox()) self.assertNotEqual(amp.getRawXYOffset(), namp.getRawXYOffset()) self.assertEqual(namp.getRawXYOffset()[0], i)
def testPersistence(self): """Test round-tripping a Detector through FITS I/O. """ dw = DetectorWrapper() detectorIn = dw.detector with lsst.utils.tests.getTempFilePath("*.fits") as filename: detectorIn.writeFits(filename) detectorOut = cameraGeom.Detector.readFits(filename) self.assertDetectorsEqual(detectorIn, detectorOut)
def testTransformAccess(self): """Test hasTransform and getTransform """ detector = DetectorWrapper().detector for camSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS, cameraGeom.TAN_PIXELS): # camSys may be a CameraSys or a CameraSysPrefix fullCamSys = detector.makeCameraSys(camSys) self.assertTrue(detector.hasTransform(camSys)) self.assertTrue(detector.hasTransform(fullCamSys)) detector.getTransform(camSys) detector.getTransform(fullCamSys) for badCamSys in ( cameraGeom.CameraSys("badName"), cameraGeom.CameraSys("pixels", "badDetectorName") ): self.assertFalse(detector.hasTransform(badCamSys)) self.assertRaises(lsst.pex.exceptions.Exception, detector.getTransform, badCamSys)
def __init__(self, shape=geom.Extent2I(201, 301), offset=geom.Point2I(-123, -45), backgroundLevel=314.592, seed=42, nSrc=37, fluxRange=2., noiseLevel=5, sourceSigma=200., minPsfSize=1.5, maxPsfSize=3., pixelScale=0.2 * arcseconds, ra=209. * degrees, dec=-20.25 * degrees, ccd=37, patch=42, patchGen2="2,3", tract=0): self.ra = ra self.dec = dec self.pixelScale = pixelScale self.patch = patch self.patchGen2 = patchGen2 self.tract = tract self.filterLabel = afwImage.FilterLabel(band="gTest", physical="gTest") self.rngData = np.random.default_rng(seed) self.rngMods = np.random.default_rng(seed + 1) self.bbox = geom.Box2I(offset, shape) if not self.bbox.contains(0, 0): raise ValueError( f"The bounding box must contain the coordinate (0, 0). {repr(self.bbox)}" ) self.wcs = self.makeDummyWcs() # Set up properties of the simulations nSigmaForKernel = 5 self.kernelSize = (int(maxPsfSize * nSigmaForKernel + 0.5) // 2) * 2 + 1 # make sure it is odd bufferSize = self.kernelSize // 2 x0, y0 = self.bbox.getBegin() xSize, ySize = self.bbox.getDimensions() # Set the pixel coordinates and fluxes of the simulated sources. self.xLoc = self.rngData.random(nSrc) * ( xSize - 2 * bufferSize) + bufferSize + x0 self.yLoc = self.rngData.random(nSrc) * ( ySize - 2 * bufferSize) + bufferSize + y0 self.flux = (self.rngData.random(nSrc) * (fluxRange - 1.) + 1.) * sourceSigma * noiseLevel self.backgroundLevel = backgroundLevel self.noiseLevel = noiseLevel self.minPsfSize = minPsfSize self.maxPsfSize = maxPsfSize self.detector = DetectorWrapper(name=f"detector {ccd}", id=ccd).detector
def testGetCenter(self): """Test the getCenter method """ dw = DetectorWrapper() ctrPixPoint = lsst.geom.Box2D(dw.detector.getBBox()).getCenter() for cameraSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS): ctrPoint = dw.detector.getCenter(cameraSys) transform = dw.detector.getTransform(cameraGeom.PIXELS, cameraSys) predCtrPoint = transform.applyForward(ctrPixPoint) self.assertPairsAlmostEqual(predCtrPoint, ctrPoint)
def testIteration(self): """Test iteration over amplifiers and __getitem__ """ dw = DetectorWrapper() ampList = [amp for amp in dw.detector] self.assertEquals(len(ampList), len(dw.ampInfo)) for i, amp in enumerate(ampList): self.assertEquals(amp.getName(), dw.detector[i].getName()) self.assertEquals(amp.getName(), dw.ampInfo[i].getName()) self.assertEquals(amp.getName(), dw.detector[amp.getName()].getName())
def setUp(self): np.random.seed(1234) self.cutoutSize = 35 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) exposure, catalog = self.dataset.realize( 10.0, self.dataset.makeMinimalSchema(), randomSeed=0) self.exposure = exposure detector = DetectorWrapper(id=23, bbox=exposure.getBBox()).detector self.exposure.setDetector(detector) visit = afwImage.VisitInfo(exposureId=1234, exposureTime=200., date=dafBase.DateTime( "2014-05-13T17:00:00.000000000", dafBase.DateTime.Timescale.TAI)) self.exposure.getInfo().setVisitInfo(visit) self.filter_names = ["g"] afwImageUtils.resetFilters() afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401") self.exposure.setFilter(afwImage.Filter('g')) diaObjects = makeDiaObjects(2, self.exposure) diaSourceHistory = makeDiaSources(10, diaObjects["diaObjectId"], self.exposure) diaForcedSources = makeDiaForcedSources(10, diaObjects["diaObjectId"], self.exposure) self.diaObjects, diaSourceHistory, self.diaForcedSources = _roundTripThroughApdb( diaObjects, diaSourceHistory, diaForcedSources, self.exposure.getInfo().getVisitInfo().getDate().toPython()) self.diaObjects.replace(to_replace=[None], value=np.nan, inplace=True) diaSourceHistory.replace(to_replace=[None], value=np.nan, inplace=True) self.diaForcedSources.replace(to_replace=[None], value=np.nan, inplace=True) diaSourceHistory["programId"] = 0 self.diaSources = diaSourceHistory.loc[[(0, "g", 8), (1, "g", 9)], :] self.diaSources["bboxSize"] = self.cutoutSize self.diaSourceHistory = diaSourceHistory.drop(labels=[(0, "g", 8), (1, "g", 9)]) self.cutoutWcs = wcs.WCS(naxis=2) self.cutoutWcs.wcs.crpix = [self.center[0], self.center[1]] self.cutoutWcs.wcs.crval = [ self.exposure.getWcs().getSkyOrigin().getRa().asDegrees(), self.exposure.getWcs().getSkyOrigin().getDec().asDegrees() ] self.cutoutWcs.wcs.cd = self.exposure.getWcs().getCdMatrix() self.cutoutWcs.wcs.ctype = ["RA---TAN", "DEC--TAN"]
def setUp(self): # Define point2D object which are distributed about a detector self.positions = [lsst.afw.geom.Point2D(*x) for x in ((50.1, 49.8), (12, 15.6), (13.4, 100.0))] # Define a box which will be used to as boundaries to construct an detector object self.bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-20, -30), lsst.afw.geom.Extent2I(140, 160)) self.dataset = lsst.meas.base.tests.TestDataset(self.bbox) # Add in sources to synthetic dataset at defined positions with an arbitrary value for pos in self.positions: self.dataset.addSource(100000.0, pos) self.dw = DetectorWrapper()
def setUp(self): self.camera = CameraWrapper().camera self.detector = DetectorWrapper().detector self.crpix = lsst.geom.Point2D(50, 100) self.crval = lsst.geom.SpherePoint(36, 71, lsst.geom.degrees) scale = 1.0 * lsst.geom.arcseconds self.cdMatrix = afwGeom.makeCdMatrix(scale=scale) self.wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-10, 10), lsst.geom.Extent2I(1000, 1022)) self.exposure = ExposureF(self.bbox) # set the few items of ExposureInfo needed by IsrTask.run # when only adding a distortion model exposureInfo = ExposureInfo(photoCalib=PhotoCalib(1.0), detector=self.detector, visitInfo=VisitInfo(exposureTime=1.0), wcs=self.wcs) self.exposure.setInfo(exposureInfo)
def testMakeCameraSys(self): """Test the makeCameraSys method """ dw = DetectorWrapper() for sysName in ("csys1", "csys2"): for detectorName in ("", dw.name, "a different detector"): inCamSys = cameraGeom.CameraSys(sysName, detectorName) outCamSys = dw.detector.makeCameraSys(inCamSys) self.assertEquals(inCamSys, outCamSys) inCamSysPrefix = cameraGeom.CameraSysPrefix(sysName) outCamSys2 = dw.detector.makeCameraSys(inCamSysPrefix) self.assertEquals(outCamSys2, cameraGeom.CameraSys(sysName, dw.name))
def setUp(self): # CFHT Filters from the camera mapper. afwImageUtils.resetFilters() afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301") afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401") afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601") afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701") afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801") self.metadata = dafBase.PropertySet() self.metadata.set("SIMPLE", "T") self.metadata.set("BITPIX", -32) self.metadata.set("NAXIS", 2) self.metadata.set("NAXIS1", 1024) self.metadata.set("NAXIS2", 1153) self.metadata.set("RADECSYS", 'FK5') self.metadata.set("EQUINOX", 2000.) self.metadata.setDouble("CRVAL1", 215.604025685476) self.metadata.setDouble("CRVAL2", 53.1595451514076) self.metadata.setDouble("CRPIX1", 1109.99981456774) self.metadata.setDouble("CRPIX2", 560.018167811613) self.metadata.set("CTYPE1", 'RA---SIN') self.metadata.set("CTYPE2", 'DEC--SIN') self.metadata.setDouble("CD1_1", 5.10808596133527E-05) self.metadata.setDouble("CD1_2", 1.85579539217196E-07) self.metadata.setDouble("CD2_2", -5.10281493481982E-05) self.metadata.setDouble("CD2_1", -8.27440751733828E-07) self.wcs = afwGeom.makeSkyWcs(self.metadata) self.exposure = afwImage.makeExposure( afwImage.makeMaskedImageFromArrays(np.ones((1024, 1153))), self.wcs) detector = DetectorWrapper(id=23, bbox=self.exposure.getBBox()).detector visit = afwImage.VisitInfo(exposureId=4321, exposureTime=200., date=dafBase.DateTime(nsecs=1400000000 * 10**9)) self.exposure.setDetector(detector) self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter(afwImage.Filter('g')) scale = 2 scaleErr = 1 self.photoCalib = afwImage.PhotoCalib(scale, scaleErr) self.exposure.setPhotoCalib(self.photoCalib) self.inputCatalogNoFlags = make_input_source_catalog(10, False) self.inputCatalog = make_input_source_catalog(10, True)
def testGetCorners(self): """Test the getCorners method """ dw = DetectorWrapper() for cameraSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS): # positions of corners in specified camera system cornerList = dw.detector.getCorners(cameraSys) for posPixels, posCameraSys in zip( lsst.geom.Box2D(dw.bbox).getCorners(), cornerList): pixelsToCameraSys = dw.detector.getTransform( cameraGeom.PIXELS, cameraSys) predPosCameraSys = pixelsToCameraSys.applyForward(posPixels) self.assertPairsAlmostEqual(predPosCameraSys, posCameraSys) if cameraSys == cameraGeom.PIXELS: self.assertPairsAlmostEqual(posPixels, predPosCameraSys)
def testGainAndReadnoise(self): import lsst.afw.image as afwImage from lsst.afw.cameraGeom.testUtils import DetectorWrapper from lsst.ip.isr import IsrTask isrTask = IsrTask() detector = DetectorWrapper().detector raw = afwImage.ExposureF(detector.getBBox()) level = 10 readNoise = 1 raw.image.set(level) amp = detector[0] amp.setReadNoise(readNoise) for gain in [-1, 0, 0.1, 1]: amp.setGain(gain) isrTask.updateVariance(raw, amp) if gain <= 0: gain = 1 self.assertEqual(raw.variance[0, 0, afwImage.LOCAL], level/gain + readNoise**2)
def testGetCenter(self): """Test the getCenter method """ dw = DetectorWrapper() ctrPixPoint = afwGeom.Box2D(dw.detector.getBBox()).getCenter() ctrPixCameraPoint = dw.detector.makeCameraPoint(ctrPixPoint, cameraGeom.PIXELS) for cameraSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS): ctrCameraPoint = dw.detector.getCenter(cameraSys) self.assertEquals(ctrCameraPoint.getCameraSys().getSysName(), cameraSys.getSysName()) ctrPoint = ctrCameraPoint.getPoint() predCtrCameraPoint = dw.detector.transform(ctrPixCameraPoint, cameraSys) predCtrPoint = predCtrCameraPoint.getPoint() for i in range(2): self.assertAlmostEquals(ctrPoint[i], predCtrPoint[i]) if cameraSys == cameraGeom.PIXELS: self.assertAlmostEquals(ctrPixPoint[i], ctrPoint[i])
def get_psf_exp( exp, coadd_cen_skypos, var, ): """ create a psf exposure to be coadded, rendered at the position in the exposure corresponding to the center of the coadd Parameters ---------- exp: afw_image.ExposureF The exposure coadd_cen_skypos: SpherePoint The sky position of the center of the coadd within its bbox var: float The variance to set in the psf variance map Returns ------- psf ExposureF """ wcs = exp.getWcs() pos = wcs.skyToPixel(coadd_cen_skypos) psf_obj = exp.getPsf() psf_image = psf_obj.computeImage(pos).array psf_dim = psf_image.shape[0] psf_bbox = get_psf_bbox(pos=pos, dim=psf_dim) # wcs same as SE exposure psf_exp = afw_image.ExposureF(psf_bbox, wcs) psf_exp.image.array[:, :] = psf_image psf_exp.variance.array[:, :] = var psf_exp.mask.array[:, :] = 0 psf_exp.setFilterLabel(exp.getFilterLabel()) detector = DetectorWrapper().detector psf_exp.setDetector(detector) return psf_exp
def testGetCorners(self): """Test the getCorners method """ dw = DetectorWrapper() for cameraSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS): cornerList = dw.detector.getCorners(cameraSys) for fromPoint, toPoint in itertools.izip(afwGeom.Box2D(dw.bbox).getCorners(), cornerList): predToCameraPoint = dw.detector.transform( dw.detector.makeCameraPoint(fromPoint, cameraGeom.PIXELS), cameraSys, ) predToPoint = predToCameraPoint.getPoint() self.assertEquals(predToCameraPoint.getCameraSys().getSysName(), cameraSys.getSysName()) for i in range(2): self.assertAlmostEquals(predToPoint[i], toPoint[i]) if cameraSys == cameraGeom.PIXELS: self.assertAlmostEquals(fromPoint[i], toPoint[i])
def setUp(self): self.camera = CameraWrapper().camera self.detector = DetectorWrapper().detector self.crpix = afwGeom.Point2D(50, 100) self.crval = afwGeom.SpherePoint(36, 71, afwGeom.degrees) scale = 1.0*afwGeom.arcseconds self.cdMatrix = afwGeom.makeCdMatrix(scale=scale) self.wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) self.bbox = afwGeom.Box2I(afwGeom.Point2I(-10, 10), afwGeom.Extent2I(1000, 1022)) self.exposure = ExposureF(self.bbox) # set the few items of ExposureInfo needed by IsrTask.run # when only adding a distortion model exposureInfo = ExposureInfo(photoCalib=PhotoCalib(1.0), detector=self.detector, visitInfo=VisitInfo(exposureTime=1.0), wcs=self.wcs) self.exposure.setInfo(exposureInfo)
def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = afwImage.readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwImage.makeWcs(maskedImageMD) self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrOnly = afwImage.ExposureF(afwGeom.ExtentI(100, 100)) # test with ExtentI(100, 100) too afwImage.Filter.reset() afwImage.FilterProperty.reset() filterPolicy = pexPolicy.Policy() filterPolicy.add("lambdaEff", 470.0) afwImage.Filter.define(afwImage.FilterProperty("g", filterPolicy))
def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwGeom.makeSkyWcs(maskedImageMD, False) self.md = maskedImageMD self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) # test with ExtentI(100, 100) too self.exposureCrOnly = afwImage.ExposureF(lsst.geom.ExtentI(100, 100)) afwImage.Filter.reset() afwImage.FilterProperty.reset() defineFilter("g", 470.0)
class ExposureTestCase(unittest.TestCase): """ A test case for the Exposure Class """ def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = afwImage.readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwImage.makeWcs(maskedImageMD) self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrOnly = afwImage.ExposureF(afwGeom.ExtentI(100, 100)) # test with ExtentI(100, 100) too afwImage.Filter.reset() afwImage.FilterProperty.reset() filterPolicy = pexPolicy.Policy() filterPolicy.add("lambdaEff", 470.0) afwImage.Filter.define(afwImage.FilterProperty("g", filterPolicy)) def tearDown(self): del self.smallExposure del self.wcs del self.psf del self.detector del self.exposureBlank del self.exposureMiOnly del self.exposureMiWcs del self.exposureCrWcs del self.exposureCrOnly def testGetMaskedImage(self): """ Test to ensure a MaskedImage can be obtained from each Exposure. An Exposure is required to have a MaskedImage, therefore each of the Exposures should return a MaskedImage. MaskedImage class should throw appropriate lsst::pex::exceptions::NotFound if the MaskedImage can not be obtained. """ maskedImageBlank = self.exposureBlank.getMaskedImage() blankWidth = maskedImageBlank.getWidth() blankHeight = maskedImageBlank.getHeight() if blankWidth != blankHeight != 0: self.fail("%s = %s != 0" % (blankWidth, blankHeight)) maskedImageMiOnly = self.exposureMiOnly.getMaskedImage() miOnlyWidth = maskedImageMiOnly.getWidth() miOnlyHeight = maskedImageMiOnly.getHeight() self.assertAlmostEqual(miOnlyWidth, self.width) self.assertAlmostEqual(miOnlyHeight, self.height) # NOTE: Unittests for Exposures created from a MaskedImage and # a WCS object are incomplete. No way to test the validity of # the WCS being copied/created. maskedImageMiWcs = self.exposureMiWcs.getMaskedImage() miWcsWidth = maskedImageMiWcs.getWidth() miWcsHeight = maskedImageMiWcs.getHeight() self.assertAlmostEqual(miWcsWidth, self.width) self.assertAlmostEqual(miWcsHeight, self.height) maskedImageCrWcs = self.exposureCrWcs.getMaskedImage() crWcsWidth = maskedImageCrWcs.getWidth() crWcsHeight = maskedImageCrWcs.getHeight() if crWcsWidth != crWcsHeight != 0: self.fail("%s != %s != 0" % (crWcsWidth, crWcsHeight)) maskedImageCrOnly = self.exposureCrOnly.getMaskedImage() crOnlyWidth = maskedImageCrOnly.getWidth() crOnlyHeight = maskedImageCrOnly.getHeight() if crOnlyWidth != crOnlyHeight != 0: self.fail("%s != %s != 0" % (crOnlyWidth, crOnlyHeight)) # Check Exposure.getWidth() returns the MaskedImage's width self.assertEqual(crOnlyWidth, self.exposureCrOnly.getWidth()) self.assertEqual(crOnlyHeight, self.exposureCrOnly.getHeight()) def testGetWcs(self): """ Test if a WCS can be obtained from each Exposure created with a WCS. Test that appropriate exceptions are thrown if a WCS is requested from an Exposure that was not created with a WCS. Python turns the pex::exceptions in the Exposure and MaskedImage classes into IndexErrors. The exposureBlank, exposureMiOnly, and exposureCrOnly Exposures should throw a lsst::pex::exceptions::NotFound. """ self.assertTrue(not self.exposureBlank.getWcs()) self.assertTrue(not self.exposureMiOnly.getWcs()) # These two should pass self.exposureMiWcs.getWcs() self.exposureCrWcs.getWcs() self.assertTrue(not self.exposureCrOnly.getWcs()) def testSetMembers(self): """ Test that the MaskedImage and the WCS of an Exposure can be set. """ exposure = afwImage.ExposureF() maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure.setMaskedImage(maskedImage) exposure.setWcs(self.wcs) exposure.setDetector(self.detector) exposure.setFilter(afwImage.Filter("g")) self.assertEquals(exposure.getDetector().getName(), self.detector.getName()) self.assertEquals(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEquals(exposure.getFilter().getName(), "g") try: exposure.getWcs() except pexExcept.Exception as e: print "caught expected exception (getWcs): %s" % e pass # # Test the Calib member. The Calib tests are in color.py, here we just check that it's in Exposure # calib = exposure.getCalib() dt = 10 calib.setExptime(dt) self.assertEqual(exposure.getCalib().getExptime(), dt) # # now check that we can set Calib # calib = afwImage.Calib() dt = 666 calib.setExptime(dt) exposure.setCalib(calib) self.assertEqual(exposure.getCalib().getExptime(), dt) # # Psfs next # self.assertFalse(exposure.hasPsf()) exposure.setPsf(self.psf) self.assertTrue(exposure.hasPsf()) exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf # Test that we can set the MaskedImage and WCS of an Exposure # that already has both self.exposureMiWcs.setMaskedImage(maskedImage) exposure.setWcs(self.wcs) def testHasWcs(self): """ Test if an Exposure has a WCS or not. """ self.assertFalse(self.exposureBlank.hasWcs()) self.assertFalse(self.exposureMiOnly.hasWcs()) self.assertTrue(self.exposureMiWcs.hasWcs()) self.assertTrue(self.exposureCrWcs.hasWcs()) self.assertFalse(self.exposureCrOnly.hasWcs()) def testGetSubExposure(self): """ Test that a subExposure of the original Exposure can be obtained. The MaskedImage class should throw a lsst::pex::exceptions::InvalidParameter if the requested subRegion is not fully contained within the original MaskedImage. """ # # This subExposure is valid # subBBox = afwGeom.Box2I(afwGeom.Point2I(40, 50), afwGeom.Extent2I(10, 10)) subExposure = self.exposureCrWcs.Factory(self.exposureCrWcs, subBBox, afwImage.LOCAL) self.checkWcs(self.exposureCrWcs, subExposure) # this subRegion is not valid and should trigger an exception # from the MaskedImage class and should trigger an exception # from the WCS class for the MaskedImage 871034p_1_MI. subRegion3 = afwGeom.Box2I(afwGeom.Point2I(100, 100), afwGeom.Extent2I(10, 10)) def getSubRegion(): self.exposureCrWcs.Factory(self.exposureCrWcs, subRegion3, afwImage.LOCAL) self.assertRaises(pexExcept.LengthError, getSubRegion) # this subRegion is not valid and should trigger an exception # from the MaskedImage class only for the MaskedImage small_MI. # small_MI (cols, rows) = (256, 256) subRegion4 = afwGeom.Box2I(afwGeom.Point2I(250, 250), afwGeom.Extent2I(10, 10)) def getSubRegion(): self.exposureCrWcs.Factory(self.exposureCrWcs, subRegion4, afwImage.LOCAL) self.assertRaises(pexExcept.LengthError, getSubRegion) #check the sub- and parent- exposures are using the same Wcs transformation subBBox = afwGeom.Box2I(afwGeom.Point2I(40, 50), afwGeom.Extent2I(10, 10)) subExposure = self.exposureCrWcs.Factory(self.exposureCrWcs, subBBox, afwImage.LOCAL) parentPos = self.exposureCrWcs.getWcs().pixelToSky(0,0) parentPos = parentPos.getPosition() subExpPos = subExposure.getWcs().pixelToSky(0,0).getPosition() for i in range(2): self.assertAlmostEqual(parentPos[i], subExpPos[i], 9, "Wcs in sub image has changed") def testReadWriteFits(self): """Test readFits and writeFits. """ # This should pass without an exception mainExposure = afwImage.ExposureF(inFilePathSmall) mainExposure.setDetector(self.detector) subBBox = afwGeom.Box2I(afwGeom.Point2I(10, 10), afwGeom.Extent2I(40, 50)) subExposure = mainExposure.Factory(mainExposure, subBBox, afwImage.LOCAL) self.checkWcs(mainExposure, subExposure) det = subExposure.getDetector() self.assertTrue(det) subExposure = afwImage.ExposureF(inFilePathSmall, subBBox, afwImage.LOCAL) self.checkWcs(mainExposure, subExposure) # This should throw an exception def getExposure(): afwImage.ExposureF(inFilePathSmallImage) self.assertRaises(lsst.afw.fits.FitsError, getExposure) mainExposure.setPsf(self.psf) # Make sure we can write without an exception mainExposure.getCalib().setExptime(10) mainExposure.getCalib().setMidTime(dafBase.DateTime()) midMjd = mainExposure.getCalib().getMidTime().get() fluxMag0, fluxMag0Err = 1e12, 1e10 mainExposure.getCalib().setFluxMag0(fluxMag0, fluxMag0Err) with utilsTests.getTempFilePath(".fits") as tmpFile: mainExposure.writeFits(tmpFile) readExposure = type(mainExposure)(tmpFile) # # Check the round-tripping # self.assertEqual(mainExposure.getFilter().getName(), readExposure.getFilter().getName()) self.assertEqual(mainExposure.getCalib().getExptime(), readExposure.getCalib().getExptime()) self.assertEqual(midMjd, readExposure.getCalib().getMidTime().get()) self.assertEqual((fluxMag0, fluxMag0Err), readExposure.getCalib().getFluxMag0()) psf = readExposure.getPsf() self.assert_(psf is not None) dummyPsf = DummyPsf.swigConvert(psf) self.assert_(dummyPsf is not None) self.assertEqual(dummyPsf.getValue(), self.psf.getValue()) def checkWcs(self, parentExposure, subExposure): """Compare WCS at corner points of a sub-exposure and its parent exposure By using the function indexToPosition, we should be able to convert the indices (of the four corners (of the sub-exposure)) to positions and use the wcs to get the same sky coordinates for each. """ subMI = subExposure.getMaskedImage() subDim = subMI.getDimensions() # Note: pixel positions must be computed relative to XY0 when working with WCS mainWcs = parentExposure.getWcs() subWcs = subExposure.getWcs() for xSubInd in (0, subDim.getX()-1): for ySubInd in (0, subDim.getY()-1): mainWcs.pixelToSky( afwImage.indexToPosition(xSubInd), afwImage.indexToPosition(ySubInd), ) subWcs.pixelToSky( afwImage.indexToPosition(xSubInd), afwImage.indexToPosition(ySubInd), ) def cmpExposure(self, e1, e2): self.assertEqual(e1.getDetector().getName(), e2.getDetector().getName()) self.assertEqual(e1.getDetector().getSerial(), e2.getDetector().getSerial()) self.assertEqual(e1.getFilter().getName(), e2.getFilter().getName()) xy = afwGeom.Point2D(0, 0) self.assertEqual(e1.getWcs().pixelToSky(xy)[0], e2.getWcs().pixelToSky(xy)[0]) self.assertEqual(e1.getCalib().getExptime(), e2.getCalib().getExptime()) # check PSF identity if not e1.getPsf(): self.assertFalse(e2.getPsf()) else: psf1 = DummyPsf.swigConvert(e1.getPsf()) psf2 = DummyPsf.swigConvert(e2.getPsf()) self.assertEqual(psf1.getValue(), psf2.getValue()) def testCopyExposure(self): """Copy an Exposure (maybe changing type)""" exposureU = afwImage.ExposureU(inFilePathSmall) exposureU.setWcs(self.wcs) exposureU.setDetector(self.detector) exposureU.setFilter(afwImage.Filter("g")) exposureU.getCalib().setExptime(666) exposureU.setPsf(DummyPsf(4.0)) exposureF = exposureU.convertF() self.cmpExposure(exposureF, exposureU) nexp = exposureF.Factory(exposureF, False) self.cmpExposure(exposureF, nexp) # Ensure that the copy was deep. # (actually this test is invalid since getDetector() returns a CONST_PTR) # cen0 = exposureU.getDetector().getCenterPixel() # x0,y0 = cen0 # det = exposureF.getDetector() # det.setCenterPixel(afwGeom.Point2D(999.0, 437.8)) # self.assertEqual(exposureU.getDetector().getCenterPixel()[0], x0) # self.assertEqual(exposureU.getDetector().getCenterPixel()[1], y0) def testDeepCopyData(self): """Make sure a deep copy of an Exposure has its own data (ticket #2625) """ exp = afwImage.ExposureF(6, 7) mi = exp.getMaskedImage() mi.getImage().set(100) mi.getMask().set(5) mi.getVariance().set(200) expCopy = exp.clone() miCopy = expCopy.getMaskedImage() miCopy.getImage().set(-50) miCopy.getMask().set(2) miCopy.getVariance().set(175) self.assertTrue(numpy.allclose(miCopy.getImage().getArray(), -50)) self.assertTrue(numpy.all(miCopy.getMask().getArray() == 2)) self.assertTrue(numpy.allclose(miCopy.getVariance().getArray(), 175)) self.assertTrue(numpy.allclose(mi.getImage().getArray(), 100)) self.assertTrue(numpy.all(mi.getMask().getArray() == 5)) self.assertTrue(numpy.allclose(mi.getVariance().getArray(), 200)) def testDeepCopySubData(self): """Make sure a deep copy of a subregion of an Exposure has its own data (ticket #2625) """ exp = afwImage.ExposureF(6, 7) mi = exp.getMaskedImage() mi.getImage().set(100) mi.getMask().set(5) mi.getVariance().set(200) bbox = afwGeom.Box2I(afwGeom.Point2I(1,0), afwGeom.Extent2I(5, 4)) expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) miCopy = expCopy.getMaskedImage() miCopy.getImage().set(-50) miCopy.getMask().set(2) miCopy.getVariance().set(175) self.assertTrue(numpy.allclose(miCopy.getImage().getArray(), -50)) self.assertTrue(numpy.all(miCopy.getMask().getArray() == 2)) self.assertTrue(numpy.allclose(miCopy.getVariance().getArray(), 175)) self.assertTrue(numpy.allclose(mi.getImage().getArray(), 100)) self.assertTrue(numpy.all(mi.getMask().getArray() == 5)) self.assertTrue(numpy.allclose(mi.getVariance().getArray(), 200)) def testDeepCopyMetadata(self): """Make sure a deep copy of an Exposure has a deep copy of metadata (ticket #2568) """ exp = afwImage.ExposureF(10, 10) expMeta = exp.getMetadata() expMeta.set("foo", 5) expCopy = exp.clone() expCopyMeta = expCopy.getMetadata() expCopyMeta.set("foo", 6) self.assertEqual(expCopyMeta.get("foo"), 6) self.assertEqual(expMeta.get("foo"), 5) # this will fail if the bug is present def testDeepCopySubMetadata(self): """Make sure a deep copy of a subregion of an Exposure has a deep copy of metadata (ticket #2568) """ exp = afwImage.ExposureF(10, 10) expMeta = exp.getMetadata() expMeta.set("foo", 5) bbox = afwGeom.Box2I(afwGeom.Point2I(1,0), afwGeom.Extent2I(5, 5)) expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) expCopyMeta = expCopy.getMetadata() expCopyMeta.set("foo", 6) self.assertEqual(expCopyMeta.get("foo"), 6) self.assertEqual(expMeta.get("foo"), 5) # this will fail if the bug is present def testMakeExposureLeaks(self): """Test for memory leaks in makeExposure (the test is in utilsTests.MemoryTestCase)""" afwImage.makeMaskedImage(afwImage.ImageU(afwGeom.Extent2I(10, 20))) afwImage.makeExposure(afwImage.makeMaskedImage(afwImage.ImageU(afwGeom.Extent2I(10, 20)))) def testImageSlices(self): """Test image slicing, which generate sub-images using Box2I under the covers""" exp = afwImage.ExposureF(10, 20) mi = exp.getMaskedImage() mi[9, 19] = 10 # N.b. Exposures don't support setting/getting the pixels so can't replicate e.g. Image's slice tests sexp = exp[1:4, 6:10] self.assertEqual(sexp.getDimensions(), afwGeom.ExtentI(3, 4)) sexp = exp[..., -3:] self.assertEqual(sexp.getDimensions(), afwGeom.ExtentI(exp.getWidth(), 3)) self.assertEqual(sexp.getMaskedImage().get(sexp.getWidth() - 1, sexp.getHeight() - 1), exp.getMaskedImage().get( exp.getWidth() - 1, exp.getHeight() - 1)) def testConversionToScalar(self): """Test that even 1-pixel Exposures can't be converted to scalars""" im = afwImage.ExposureF(10, 20) self.assertRaises(TypeError, float, im) # only single pixel images may be converted self.assertRaises(TypeError, float, im[0,0]) # actually, can't convert (img, msk, var) to scalar def testReadMetadata(self): with utilsTests.getTempFilePath(".fits") as tmpFile: self.exposureCrWcs.getMetadata().set("FRAZZLE", True) # This will write the main metadata (inc. FRAZZLE) to the primary HDU, and the # WCS to subsequent HDUs, along with INHERIT=T. self.exposureCrWcs.writeFits(tmpFile) # This should read the first non-empty HDU (i.e. it skips the primary), but # goes back and reads it if it finds INHERIT=T. That should let us read # frazzle and the Wcs from the PropertySet returned by readMetadata. md = afwImage.readMetadata(tmpFile) wcs = afwImage.makeWcs(md, True) self.assertEqual(wcs.getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(wcs.getSkyOrigin(), self.wcs.getSkyOrigin()) self.assert_(numpy.all(wcs.getCDMatrix() == self.wcs.getCDMatrix())) frazzle = md.get("FRAZZLE") self.assert_(frazzle is True) def testArchiveKeys(self): with utilsTests.getTempFilePath(".fits") as tmpFile: exposure1 = afwImage.ExposureF(100, 100, self.wcs) exposure1.setPsf(self.psf) exposure1.writeFits(tmpFile) exposure2 = afwImage.ExposureF(tmpFile) self.assertFalse(exposure2.getMetadata().exists("AR_ID")) self.assertFalse(exposure2.getMetadata().exists("PSF_ID")) self.assertFalse(exposure2.getMetadata().exists("WCS_ID")) def testTicket2861(self): with utilsTests.getTempFilePath(".fits") as tmpFile: exposure1 = afwImage.ExposureF(100, 100, self.wcs) exposure1.setPsf(self.psf) schema = afwTable.ExposureTable.makeMinimalSchema() coaddInputs = afwImage.CoaddInputs(schema, schema) exposure1.getInfo().setCoaddInputs(coaddInputs) exposure2 = afwImage.ExposureF(exposure1, True) self.assertIsNotNone(exposure2.getInfo().getCoaddInputs()) exposure2.writeFits(tmpFile) exposure3 = afwImage.ExposureF(tmpFile) self.assertIsNotNone(exposure3.getInfo().getCoaddInputs())
def testTransformAccess(self): """Test hasTransform and getTransform """ detector = DetectorWrapper().detector for fromSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS, cameraGeom.TAN_PIXELS): fullFromSys = detector.makeCameraSys(fromSys) for toSys in (cameraGeom.FOCAL_PLANE, cameraGeom.PIXELS, cameraGeom.TAN_PIXELS): fullToSys = detector.makeCameraSys(toSys) self.assertTrue(detector.hasTransform(fromSys)) self.assertTrue(detector.hasTransform(fullFromSys)) self.assertTrue(detector.hasTransform(toSys)) self.assertTrue(detector.hasTransform(fullToSys)) detector.getTransform(fromSys, toSys) detector.getTransform(fromSys, fullToSys) detector.getTransform(fullFromSys, toSys) detector.getTransform(fullFromSys, fullToSys) for badCamSys in ( cameraGeom.CameraSys("badName"), cameraGeom.CameraSys("pixels", "badDetectorName") ): self.assertFalse(detector.hasTransform(badCamSys)) self.assertTrue(detector.hasTransform(cameraGeom.PIXELS)) with self.assertRaises(lsst.pex.exceptions.Exception): detector.getTransform(cameraGeom.PIXELS, badCamSys)
class ExposureTestCase(lsst.utils.tests.TestCase): """ A test case for the Exposure Class """ def setUp(self): maskedImage = afwImage.MaskedImageF(inFilePathSmall) maskedImageMD = readMetadata(inFilePathSmall) self.smallExposure = afwImage.ExposureF(inFilePathSmall) self.width = maskedImage.getWidth() self.height = maskedImage.getHeight() self.wcs = afwGeom.makeSkyWcs(maskedImageMD, False) self.md = maskedImageMD self.psf = DummyPsf(2.0) self.detector = DetectorWrapper().detector self.exposureBlank = afwImage.ExposureF() self.exposureMiOnly = afwImage.makeExposure(maskedImage) self.exposureMiWcs = afwImage.makeExposure(maskedImage, self.wcs) # n.b. the (100, 100, ...) form self.exposureCrWcs = afwImage.ExposureF(100, 100, self.wcs) # test with ExtentI(100, 100) too self.exposureCrOnly = afwImage.ExposureF(lsst.geom.ExtentI(100, 100)) afwImage.Filter.reset() afwImage.FilterProperty.reset() defineFilter("g", 470.0) def tearDown(self): del self.smallExposure del self.wcs del self.psf del self.detector del self.exposureBlank del self.exposureMiOnly del self.exposureMiWcs del self.exposureCrWcs del self.exposureCrOnly def testGetMaskedImage(self): """ Test to ensure a MaskedImage can be obtained from each Exposure. An Exposure is required to have a MaskedImage, therefore each of the Exposures should return a MaskedImage. MaskedImage class should throw appropriate lsst::pex::exceptions::NotFound if the MaskedImage can not be obtained. """ maskedImageBlank = self.exposureBlank.getMaskedImage() blankWidth = maskedImageBlank.getWidth() blankHeight = maskedImageBlank.getHeight() if blankWidth != blankHeight != 0: self.fail("%s = %s != 0" % (blankWidth, blankHeight)) maskedImageMiOnly = self.exposureMiOnly.getMaskedImage() miOnlyWidth = maskedImageMiOnly.getWidth() miOnlyHeight = maskedImageMiOnly.getHeight() self.assertAlmostEqual(miOnlyWidth, self.width) self.assertAlmostEqual(miOnlyHeight, self.height) # NOTE: Unittests for Exposures created from a MaskedImage and # a WCS object are incomplete. No way to test the validity of # the WCS being copied/created. maskedImageMiWcs = self.exposureMiWcs.getMaskedImage() miWcsWidth = maskedImageMiWcs.getWidth() miWcsHeight = maskedImageMiWcs.getHeight() self.assertAlmostEqual(miWcsWidth, self.width) self.assertAlmostEqual(miWcsHeight, self.height) maskedImageCrWcs = self.exposureCrWcs.getMaskedImage() crWcsWidth = maskedImageCrWcs.getWidth() crWcsHeight = maskedImageCrWcs.getHeight() if crWcsWidth != crWcsHeight != 0: self.fail("%s != %s != 0" % (crWcsWidth, crWcsHeight)) maskedImageCrOnly = self.exposureCrOnly.getMaskedImage() crOnlyWidth = maskedImageCrOnly.getWidth() crOnlyHeight = maskedImageCrOnly.getHeight() if crOnlyWidth != crOnlyHeight != 0: self.fail("%s != %s != 0" % (crOnlyWidth, crOnlyHeight)) # Check Exposure.getWidth() returns the MaskedImage's width self.assertEqual(crOnlyWidth, self.exposureCrOnly.getWidth()) self.assertEqual(crOnlyHeight, self.exposureCrOnly.getHeight()) def testProperties(self): self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, self.exposureMiOnly.getMaskedImage()) mi2 = afwImage.MaskedImageF(self.exposureMiOnly.getDimensions()) mi2.image.array[:] = 5.0 mi2.variance.array[:] = 3.0 mi2.mask.array[:] = 0x1 self.exposureMiOnly.maskedImage = mi2 self.assertMaskedImagesEqual(self.exposureMiOnly.maskedImage, mi2) self.assertImagesEqual(self.exposureMiOnly.image, self.exposureMiOnly.maskedImage.image) image3 = afwImage.ImageF(self.exposureMiOnly.getDimensions()) image3.array[:] = 3.0 self.exposureMiOnly.image = image3 self.assertImagesEqual(self.exposureMiOnly.image, image3) mask3 = afwImage.MaskX(self.exposureMiOnly.getDimensions()) mask3.array[:] = 0x2 self.exposureMiOnly.mask = mask3 self.assertMasksEqual(self.exposureMiOnly.mask, mask3) var3 = afwImage.ImageF(self.exposureMiOnly.getDimensions()) var3.array[:] = 2.0 self.exposureMiOnly.variance = var3 self.assertImagesEqual(self.exposureMiOnly.variance, var3) def testGetWcs(self): """ Test if a WCS can be obtained from each Exposure created with a WCS. Test that appropriate exceptions are thrown if a WCS is requested from an Exposure that was not created with a WCS. Python turns the pex::exceptions in the Exposure and MaskedImage classes into IndexErrors. The exposureBlank, exposureMiOnly, and exposureCrOnly Exposures should throw a lsst::pex::exceptions::NotFound. """ self.assertFalse(self.exposureBlank.getWcs()) self.assertFalse(self.exposureMiOnly.getWcs()) # These two should pass self.exposureMiWcs.getWcs() self.exposureCrWcs.getWcs() self.assertFalse(self.exposureCrOnly.getWcs()) def testExposureInfoConstructor(self): """Test the Exposure(maskedImage, exposureInfo) constructor""" exposureInfo = afwImage.ExposureInfo() exposureInfo.setWcs(self.wcs) exposureInfo.setDetector(self.detector) gFilter = afwImage.Filter("g") exposureInfo.setFilter(gFilter) maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure = afwImage.ExposureF(maskedImage, exposureInfo) self.assertTrue(exposure.hasWcs()) self.assertEqual(exposure.getWcs().getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(exposure.getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getFilter(), gFilter) self.assertTrue(exposure.getInfo().hasWcs()) self.assertEqual(exposure.getInfo().getWcs().getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(exposure.getInfo().getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getInfo().getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getInfo().getFilter(), gFilter) def testNullWcs(self): """Test that an Exposure constructed with second argument None is usable When the exposureInfo constructor was first added, trying to get a WCS or other info caused a segfault because the ExposureInfo did not exist. """ maskedImage = self.exposureMiOnly.getMaskedImage() exposure = afwImage.ExposureF(maskedImage, None) self.assertFalse(exposure.hasWcs()) self.assertFalse(exposure.hasPsf()) def testExposureInfoSetNone(self): exposureInfo = afwImage.ExposureInfo() exposureInfo.setDetector(None) exposureInfo.setValidPolygon(None) exposureInfo.setPsf(None) exposureInfo.setWcs(None) exposureInfo.setPhotoCalib(None) exposureInfo.setCoaddInputs(None) exposureInfo.setVisitInfo(None) exposureInfo.setApCorrMap(None) def testSetExposureInfo(self): exposureInfo = afwImage.ExposureInfo() exposureInfo.setWcs(self.wcs) exposureInfo.setDetector(self.detector) gFilter = afwImage.Filter("g") exposureInfo.setFilter(gFilter) maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure = afwImage.ExposureF(maskedImage) self.assertFalse(exposure.hasWcs()) exposure.setInfo(exposureInfo) self.assertTrue(exposure.hasWcs()) self.assertEqual(exposure.getWcs().getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertEqual(exposure.getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getFilter(), gFilter) def testVisitInfoFitsPersistence(self): """Test saving an exposure to FITS and reading it back in preserves (some) VisitInfo fields""" exposureId = 5 exposureTime = 12.3 boresightRotAngle = 45.6 * lsst.geom.degrees weather = Weather(1.1, 2.2, 0.3) visitInfo = afwImage.VisitInfo( exposureId=exposureId, exposureTime=exposureTime, boresightRotAngle=boresightRotAngle, weather=weather, ) photoCalib = afwImage.PhotoCalib(3.4, 5.6) exposureInfo = afwImage.ExposureInfo() exposureInfo.setVisitInfo(visitInfo) exposureInfo.setPhotoCalib(photoCalib) exposureInfo.setDetector(self.detector) gFilter = afwImage.Filter("g") exposureInfo.setFilter(gFilter) maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure = afwImage.ExposureF(maskedImage, exposureInfo) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: exposure.writeFits(tmpFile) rtExposure = afwImage.ExposureF(tmpFile) rtVisitInfo = rtExposure.getInfo().getVisitInfo() self.assertEqual(rtVisitInfo.getWeather(), weather) self.assertEqual(rtExposure.getPhotoCalib(), photoCalib) self.assertEqual(rtExposure.getFilter(), gFilter) def testSetMembers(self): """ Test that the MaskedImage and the WCS of an Exposure can be set. """ exposure = afwImage.ExposureF() maskedImage = afwImage.MaskedImageF(inFilePathSmall) exposure.setMaskedImage(maskedImage) exposure.setWcs(self.wcs) exposure.setDetector(self.detector) exposure.setFilter(afwImage.Filter("g")) self.assertEqual(exposure.getDetector().getName(), self.detector.getName()) self.assertEqual(exposure.getDetector().getSerial(), self.detector.getSerial()) self.assertEqual(exposure.getFilter().getName(), "g") self.assertEqual(exposure.getWcs(), self.wcs) # The PhotoCalib tests are in test_photoCalib.py; # here we just check that it's gettable and settable. self.assertIsNone(exposure.getPhotoCalib()) photoCalib = afwImage.PhotoCalib(511.1, 44.4) exposure.setPhotoCalib(photoCalib) self.assertEqual(exposure.getPhotoCalib(), photoCalib) # Psfs next self.assertFalse(exposure.hasPsf()) exposure.setPsf(self.psf) self.assertTrue(exposure.hasPsf()) exposure.setPsf(DummyPsf(1.0)) # we can reset the Psf # Test that we can set the MaskedImage and WCS of an Exposure # that already has both self.exposureMiWcs.setMaskedImage(maskedImage) exposure.setWcs(self.wcs) def testHasWcs(self): """ Test if an Exposure has a WCS or not. """ self.assertFalse(self.exposureBlank.hasWcs()) self.assertFalse(self.exposureMiOnly.hasWcs()) self.assertTrue(self.exposureMiWcs.hasWcs()) self.assertTrue(self.exposureCrWcs.hasWcs()) self.assertFalse(self.exposureCrOnly.hasWcs()) def testGetSubExposure(self): """ Test that a subExposure of the original Exposure can be obtained. The MaskedImage class should throw a lsst::pex::exceptions::InvalidParameter if the requested subRegion is not fully contained within the original MaskedImage. """ # # This subExposure is valid # subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50), lsst.geom.Extent2I(10, 10)) subExposure = self.exposureCrWcs.Factory( self.exposureCrWcs, subBBox, afwImage.LOCAL) self.checkWcs(self.exposureCrWcs, subExposure) # this subRegion is not valid and should trigger an exception # from the MaskedImage class and should trigger an exception # from the WCS class for the MaskedImage 871034p_1_MI. subRegion3 = lsst.geom.Box2I(lsst.geom.Point2I(100, 100), lsst.geom.Extent2I(10, 10)) def getSubRegion(): self.exposureCrWcs.Factory( self.exposureCrWcs, subRegion3, afwImage.LOCAL) self.assertRaises(pexExcept.LengthError, getSubRegion) # this subRegion is not valid and should trigger an exception # from the MaskedImage class only for the MaskedImage small_MI. # small_MI (cols, rows) = (256, 256) subRegion4 = lsst.geom.Box2I(lsst.geom.Point2I(250, 250), lsst.geom.Extent2I(10, 10)) def getSubRegion(): self.exposureCrWcs.Factory( self.exposureCrWcs, subRegion4, afwImage.LOCAL) self.assertRaises(pexExcept.LengthError, getSubRegion) # check the sub- and parent- exposures are using the same Wcs # transformation subBBox = lsst.geom.Box2I(lsst.geom.Point2I(40, 50), lsst.geom.Extent2I(10, 10)) subExposure = self.exposureCrWcs.Factory( self.exposureCrWcs, subBBox, afwImage.LOCAL) parentSkyPos = self.exposureCrWcs.getWcs().pixelToSky(0, 0) subExpSkyPos = subExposure.getWcs().pixelToSky(0, 0) self.assertSpherePointsAlmostEqual(parentSkyPos, subExpSkyPos, msg="Wcs in sub image has changed") def testReadWriteFits(self): """Test readFits and writeFits. """ # This should pass without an exception mainExposure = afwImage.ExposureF(inFilePathSmall) mainExposure.setDetector(self.detector) subBBox = lsst.geom.Box2I(lsst.geom.Point2I(10, 10), lsst.geom.Extent2I(40, 50)) subExposure = mainExposure.Factory( mainExposure, subBBox, afwImage.LOCAL) self.checkWcs(mainExposure, subExposure) det = subExposure.getDetector() self.assertTrue(det) subExposure = afwImage.ExposureF( inFilePathSmall, subBBox, afwImage.LOCAL) self.checkWcs(mainExposure, subExposure) # This should throw an exception def getExposure(): afwImage.ExposureF(inFilePathSmallImage) self.assertRaises(FitsError, getExposure) mainExposure.setPsf(self.psf) # Make sure we can write without an exception photoCalib = afwImage.PhotoCalib(1e-10, 1e-12) mainExposure.setPhotoCalib(photoCalib) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: mainExposure.writeFits(tmpFile) readExposure = type(mainExposure)(tmpFile) # # Check the round-tripping # self.assertEqual(mainExposure.getFilter().getName(), readExposure.getFilter().getName()) self.assertEqual(photoCalib, readExposure.getPhotoCalib()) psf = readExposure.getPsf() self.assertIsNotNone(psf) self.assertEqual(psf.getValue(), self.psf.getValue()) def checkWcs(self, parentExposure, subExposure): """Compare WCS at corner points of a sub-exposure and its parent exposure By using the function indexToPosition, we should be able to convert the indices (of the four corners (of the sub-exposure)) to positions and use the wcs to get the same sky coordinates for each. """ subMI = subExposure.getMaskedImage() subDim = subMI.getDimensions() # Note: pixel positions must be computed relative to XY0 when working # with WCS mainWcs = parentExposure.getWcs() subWcs = subExposure.getWcs() for xSubInd in (0, subDim.getX()-1): for ySubInd in (0, subDim.getY()-1): self.assertSpherePointsAlmostEqual( mainWcs.pixelToSky( afwImage.indexToPosition(xSubInd), afwImage.indexToPosition(ySubInd), ), subWcs.pixelToSky( afwImage.indexToPosition(xSubInd), afwImage.indexToPosition(ySubInd), )) def cmpExposure(self, e1, e2): self.assertEqual(e1.getDetector().getName(), e2.getDetector().getName()) self.assertEqual(e1.getDetector().getSerial(), e2.getDetector().getSerial()) self.assertEqual(e1.getFilter().getName(), e2.getFilter().getName()) xy = lsst.geom.Point2D(0, 0) self.assertEqual(e1.getWcs().pixelToSky(xy)[0], e2.getWcs().pixelToSky(xy)[0]) self.assertEqual(e1.getPhotoCalib(), e2.getPhotoCalib()) # check PSF identity if not e1.getPsf(): self.assertFalse(e2.getPsf()) else: self.assertEqual(e1.getPsf().getValue(), e2.getPsf().getValue()) def testCopyExposure(self): """Copy an Exposure (maybe changing type)""" exposureU = afwImage.ExposureU(inFilePathSmall, allowUnsafe=True) exposureU.setWcs(self.wcs) exposureU.setDetector(self.detector) exposureU.setFilter(afwImage.Filter("g")) exposureU.setPsf(DummyPsf(4.0)) exposureF = exposureU.convertF() self.cmpExposure(exposureF, exposureU) nexp = exposureF.Factory(exposureF, False) self.cmpExposure(exposureF, nexp) # Ensure that the copy was deep. # (actually this test is invalid since getDetector() returns a shared_ptr) # cen0 = exposureU.getDetector().getCenterPixel() # x0,y0 = cen0 # det = exposureF.getDetector() # det.setCenterPixel(lsst.geom.Point2D(999.0, 437.8)) # self.assertEqual(exposureU.getDetector().getCenterPixel()[0], x0) # self.assertEqual(exposureU.getDetector().getCenterPixel()[1], y0) def testDeepCopyData(self): """Make sure a deep copy of an Exposure has its own data (ticket #2625) """ exp = afwImage.ExposureF(6, 7) mi = exp.getMaskedImage() mi.getImage().set(100) mi.getMask().set(5) mi.getVariance().set(200) expCopy = exp.clone() miCopy = expCopy.getMaskedImage() miCopy.getImage().set(-50) miCopy.getMask().set(2) miCopy.getVariance().set(175) self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50) self.assertTrue(np.all(miCopy.getMask().getArray() == 2)) self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175) self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100) self.assertTrue(np.all(mi.getMask().getArray() == 5)) self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200) def testDeepCopySubData(self): """Make sure a deep copy of a subregion of an Exposure has its own data (ticket #2625) """ exp = afwImage.ExposureF(6, 7) mi = exp.getMaskedImage() mi.getImage().set(100) mi.getMask().set(5) mi.getVariance().set(200) bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 4)) expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) miCopy = expCopy.getMaskedImage() miCopy.getImage().set(-50) miCopy.getMask().set(2) miCopy.getVariance().set(175) self.assertFloatsAlmostEqual(miCopy.getImage().getArray(), -50) self.assertTrue(np.all(miCopy.getMask().getArray() == 2)) self.assertFloatsAlmostEqual(miCopy.getVariance().getArray(), 175) self.assertFloatsAlmostEqual(mi.getImage().getArray(), 100) self.assertTrue(np.all(mi.getMask().getArray() == 5)) self.assertFloatsAlmostEqual(mi.getVariance().getArray(), 200) def testDeepCopyMetadata(self): """Make sure a deep copy of an Exposure has a deep copy of metadata (ticket #2568) """ exp = afwImage.ExposureF(10, 10) expMeta = exp.getMetadata() expMeta.set("foo", 5) expCopy = exp.clone() expCopyMeta = expCopy.getMetadata() expCopyMeta.set("foo", 6) self.assertEqual(expCopyMeta.getScalar("foo"), 6) # this will fail if the bug is present self.assertEqual(expMeta.getScalar("foo"), 5) def testDeepCopySubMetadata(self): """Make sure a deep copy of a subregion of an Exposure has a deep copy of metadata (ticket #2568) """ exp = afwImage.ExposureF(10, 10) expMeta = exp.getMetadata() expMeta.set("foo", 5) bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 0), lsst.geom.Extent2I(5, 5)) expCopy = exp.Factory(exp, bbox, afwImage.PARENT, True) expCopyMeta = expCopy.getMetadata() expCopyMeta.set("foo", 6) self.assertEqual(expCopyMeta.getScalar("foo"), 6) # this will fail if the bug is present self.assertEqual(expMeta.getScalar("foo"), 5) def testMakeExposureLeaks(self): """Test for memory leaks in makeExposure (the test is in lsst.utils.tests.MemoryTestCase)""" afwImage.makeMaskedImage(afwImage.ImageU(lsst.geom.Extent2I(10, 20))) afwImage.makeExposure(afwImage.makeMaskedImage( afwImage.ImageU(lsst.geom.Extent2I(10, 20)))) def testImageSlices(self): """Test image slicing, which generate sub-images using Box2I under the covers""" exp = afwImage.ExposureF(10, 20) mi = exp.getMaskedImage() mi.image[9, 19] = 10 # N.b. Exposures don't support setting/getting the pixels so can't # replicate e.g. Image's slice tests sexp = exp[1:4, 6:10] self.assertEqual(sexp.getDimensions(), lsst.geom.ExtentI(3, 4)) sexp = exp[:, -3:, afwImage.LOCAL] self.assertEqual(sexp.getDimensions(), lsst.geom.ExtentI(exp.getWidth(), 3)) self.assertEqual(sexp.maskedImage[-1, -1, afwImage.LOCAL], exp.maskedImage[-1, -1, afwImage.LOCAL]) def testConversionToScalar(self): """Test that even 1-pixel Exposures can't be converted to scalars""" im = afwImage.ExposureF(10, 20) # only single pixel images may be converted self.assertRaises(TypeError, float, im) # actually, can't convert (img, msk, var) to scalar self.assertRaises(TypeError, float, im[0, 0]) def testReadMetadata(self): with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: self.exposureCrWcs.getMetadata().set("FRAZZLE", True) # This will write the main metadata (inc. FRAZZLE) to the primary HDU, and the # WCS to subsequent HDUs, along with INHERIT=T. self.exposureCrWcs.writeFits(tmpFile) # This should read the first non-empty HDU (i.e. it skips the primary), but # goes back and reads it if it finds INHERIT=T. That should let us read # frazzle and the Wcs from the PropertySet returned by # testReadMetadata. md = readMetadata(tmpFile) wcs = afwGeom.makeSkyWcs(md, False) self.assertPairsAlmostEqual(wcs.getPixelOrigin(), self.wcs.getPixelOrigin()) self.assertSpherePointsAlmostEqual(wcs.getSkyOrigin(), self.wcs.getSkyOrigin()) assert_allclose(wcs.getCdMatrix(), self.wcs.getCdMatrix(), atol=1e-10) frazzle = md.getScalar("FRAZZLE") self.assertTrue(frazzle) def testArchiveKeys(self): with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: exposure1 = afwImage.ExposureF(100, 100, self.wcs) exposure1.setPsf(self.psf) exposure1.writeFits(tmpFile) exposure2 = afwImage.ExposureF(tmpFile) self.assertFalse(exposure2.getMetadata().exists("AR_ID")) self.assertFalse(exposure2.getMetadata().exists("PSF_ID")) self.assertFalse(exposure2.getMetadata().exists("WCS_ID")) def testTicket2861(self): with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: exposure1 = afwImage.ExposureF(100, 100, self.wcs) exposure1.setPsf(self.psf) schema = afwTable.ExposureTable.makeMinimalSchema() coaddInputs = afwImage.CoaddInputs(schema, schema) exposure1.getInfo().setCoaddInputs(coaddInputs) exposure2 = afwImage.ExposureF(exposure1, True) self.assertIsNotNone(exposure2.getInfo().getCoaddInputs()) exposure2.writeFits(tmpFile) exposure3 = afwImage.ExposureF(tmpFile) self.assertIsNotNone(exposure3.getInfo().getCoaddInputs()) def testGetCutout(self): wcs = self.smallExposure.getWcs() dimensions = [lsst.geom.Extent2I(100, 50), lsst.geom.Extent2I(15, 15), lsst.geom.Extent2I(0, 10), lsst.geom.Extent2I(25, 30), lsst.geom.Extent2I(15, -5), 2*self.smallExposure.getDimensions()] locations = [("center", self._getExposureCenter(self.smallExposure)), ("edge", wcs.pixelToSky(lsst.geom.Point2D(0, 0))), ("rounding test", wcs.pixelToSky(lsst.geom.Point2D(0.2, 0.7))), ("just inside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 + 1e-4, -0.5 + 1e-4))), ("just outside", wcs.pixelToSky(lsst.geom.Point2D(-0.5 - 1e-4, -0.5 - 1e-4))), ("outside", wcs.pixelToSky(lsst.geom.Point2D(-1000, -1000)))] for cutoutSize in dimensions: for label, cutoutCenter in locations: msg = 'Cutout size = %s, location = %s' % (cutoutSize, label) if "outside" not in label and all(cutoutSize.gt(0)): cutout = self.smallExposure.getCutout(cutoutCenter, cutoutSize) centerInPixels = wcs.skyToPixel(cutoutCenter) precision = (1 + 1e-4)*np.sqrt(0.5)*wcs.getPixelScale(centerInPixels) self._checkCutoutProperties(cutout, cutoutSize, cutoutCenter, precision, msg) self._checkCutoutPixels( cutout, self._getValidCorners(self.smallExposure.getBBox(), cutout.getBBox()), msg) # Need a valid WCS with self.assertRaises(pexExcept.LogicError, msg=msg): self.exposureMiOnly.getCutout(cutoutCenter, cutoutSize) else: with self.assertRaises(pexExcept.InvalidParameterError, msg=msg): self.smallExposure.getCutout(cutoutCenter, cutoutSize) def _checkCutoutProperties(self, cutout, size, center, precision, msg): """Test whether a cutout has the desired size and position. Parameters ---------- cutout : `lsst.afw.image.Exposure` The cutout to test. size : `lsst.geom.Extent2I` The expected dimensions of ``cutout``. center : `lsst.geom.SpherePoint` The expected center of ``cutout``. precision : `lsst.geom.Angle` The precision to which ``center`` must match. msg : `str` An error message suffix describing test parameters. """ newCenter = self._getExposureCenter(cutout) self.assertIsNotNone(cutout, msg=msg) self.assertSpherePointsAlmostEqual(newCenter, center, maxSep=precision, msg=msg) self.assertEqual(cutout.getWidth(), size[0], msg=msg) self.assertEqual(cutout.getHeight(), size[1], msg=msg) def _checkCutoutPixels(self, cutout, validCorners, msg): """Test whether a cutout has valid/empty pixels where expected. Parameters ---------- cutout : `lsst.afw.image.Exposure` The cutout to test. validCorners : iterable of `lsst.geom.Point2I` The corners of ``cutout`` that should be drawn from the original image. msg : `str` An error message suffix describing test parameters. """ mask = cutout.getMaskedImage().getMask() edgeMask = mask.getPlaneBitMask("NO_DATA") for corner in cutout.getBBox().getCorners(): maskBitsSet = mask[corner] & edgeMask if corner in validCorners: self.assertEqual(maskBitsSet, 0, msg=msg) else: self.assertEqual(maskBitsSet, edgeMask, msg=msg) def _getExposureCenter(self, exposure): """Return the sky coordinates of an Exposure's center. Parameters ---------- exposure : `lsst.afw.image.Exposure` The image whose center is desired. Returns ------- center : `lsst.geom.SpherePoint` The position at the center of ``exposure``. """ return exposure.getWcs().pixelToSky(lsst.geom.Box2D(exposure.getBBox()).getCenter()) def _getValidCorners(self, imageBox, cutoutBox): """Return the corners of a cutout that are constrained by the original image. Parameters ---------- imageBox: `lsst.geom.Extent2I` The bounding box of the original image. cutoutBox : `lsst.geom.Box2I` The bounding box of the cutout. Returns ------- corners : iterable of `lsst.geom.Point2I` The corners that are drawn from the original image. """ return [corner for corner in cutoutBox.getCorners() if corner in imageBox]
class ApplyLookupTableTestCase(lsst.utils.tests.TestCase): """Test IsrTask.addDistortionModel """ def setUp(self): self.camera = CameraWrapper().camera self.detector = DetectorWrapper().detector self.crpix = afwGeom.Point2D(50, 100) self.crval = afwGeom.SpherePoint(36, 71, afwGeom.degrees) scale = 1.0*afwGeom.arcseconds self.cdMatrix = afwGeom.makeCdMatrix(scale=scale) self.wcs = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix) self.bbox = afwGeom.Box2I(afwGeom.Point2I(-10, 10), afwGeom.Extent2I(1000, 1022)) self.exposure = ExposureF(self.bbox) # set the few items of ExposureInfo needed by IsrTask.run # when only adding a distortion model exposureInfo = ExposureInfo(photoCalib=PhotoCalib(1.0), detector=self.detector, visitInfo=VisitInfo(exposureTime=1.0), wcs=self.wcs) self.exposure.setInfo(exposureInfo) def tearDown(self): self.detector = None self.exposure = None def testAddDistortionMethod(self): """Call IsrTask.addDistortionModel directly""" isrFunctions.addDistortionModel(self.exposure, self.camera) self.assertFalse(wcsAlmostEqualOverBBox(self.wcs, self.exposure.getWcs(), self.bbox)) desiredWcs = self.makeDesiredDistortedWcs() self.assertWcsAlmostEqualOverBBox(desiredWcs, self.exposure.getWcs(), self.bbox) def makeMinimalIsrConfig(self): """Return an IsrConfig with all boolean flags disabled""" isrConfig = IsrTask.ConfigClass() for name in isrConfig: if name.startswith("do"): setattr(isrConfig, name, False) return isrConfig def makeDesiredDistortedWcs(self): """Make the expected distorted WCS""" pixelToFocalPlane = self.detector.getTransform(PIXELS, FOCAL_PLANE) focalPlaneToFieldAngle = self.camera.getTransformMap().getTransform(FOCAL_PLANE, FIELD_ANGLE) return makeDistortedTanWcs(self.wcs, pixelToFocalPlane, focalPlaneToFieldAngle) def testRunWithAddDistortionModel(self): """Test IsrTask.run with config.doAddDistortionModel true""" isrConfig = self.makeMinimalIsrConfig() isrConfig.doAddDistortionModel = True isrTask = IsrTask(config=isrConfig) with self.assertRaises(RuntimeError): # the camera argument is required isrTask.run(ccdExposure=self.exposure) exposure = isrTask.run(ccdExposure=self.exposure, camera=self.camera).exposure desiredWcs = self.makeDesiredDistortedWcs() self.assertWcsAlmostEqualOverBBox(desiredWcs, exposure.getWcs(), self.bbox) def testRunWithoutAddDistortionModel(self): """Test IsrTask.run with config.doAddDistortionModel false""" isrConfig = self.makeMinimalIsrConfig() isrTask = IsrTask(config=isrConfig) # the camera argument is not needed exposure = isrTask.run(ccdExposure=self.exposure).exposure self.assertEqual(self.wcs, exposure.getWcs()) # and the camera argument is ignored if provided exposure2 = isrTask.run(ccdExposure=self.exposure, camera=self.camera).exposure self.assertEqual(self.wcs, exposure2.getWcs())