Пример #1
0
 def setUp(self):
     self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                               afwGeom.Point2I(20, 20))
     x = [0, 0, 10, 10]
     y = [0, 10, 10, 0]
     self.polygon = Polygon(
         [afwGeom.Point2D(xc, yc) for xc, yc in zip(x, y)])
Пример #2
0
    def testSymDifference(self):
        """Test Polygon.symDifference"""
        poly1 = self.square(2.0, -1.0, -1.0)
        poly2 = self.square(2.0, +1.0, +1.0)

        poly3 = Polygon([
            afwGeom.Point2D(x, y)
            for x, y in ((-3.0, -3.0), (-3.0, +1.0), (-1.0, +1.0),
                         (-1.0, -1.0), (+1.0, -1.0), (1.0, -3.0))
        ])
        poly4 = Polygon([
            afwGeom.Point2D(x, y)
            for x, y in ((-1.0, +1.0), (-1.0, +3.0), (+3.0, +3.0),
                         (+3.0, -1.0), (+1.0, -1.0), (1.0, +1.0))
        ])

        diff1 = poly1.symDifference(poly2)
        diff2 = poly2.symDifference(poly1)

        self.assertEqual(len(diff1), 2)
        self.assertEqual(len(diff2), 2)
        self.assertTrue((diff1[0] == diff2[0] and diff1[1] == diff2[1])
                        or (diff1[1] == diff2[0] and diff1[0] == diff2[1]))
        self.assertTrue((diff1[0] == poly3 and diff1[1] == poly4)
                        or (diff1[1] == poly3 and diff1[0] == poly4))
Пример #3
0
def getCoaddSecondMoments(coaddpsf, point, useValidPolygon=False):
    count = coaddpsf.getComponentCount()
    coaddWcs = coaddpsf.getCoaddWcs()
    weight_sum = 0.0
    m1_sum = 0.0
    m2_sum = 0.0
    for i in range(count):
        wcs = coaddpsf.getWcs(i)
        psf = coaddpsf.getPsf(i)
        bbox = afwGeom.Box2D(coaddpsf.getBBox(i))
        if useValidPolygon:
            validPolygon = coaddpsf.getValidPolygon(i)
        else:
            validPolygon = Polygon(bbox)

        point_rel = wcs.skyToPixel(coaddWcs.pixelToSky(afwGeom.Point2D(point)))
        if bbox.contains(point_rel) and validPolygon.contains(point_rel):
            weight = coaddpsf.getWeight(i)
            m0,xbar,ybar,mxx,myy,x0,y0 = getPsfMoments(psf, point) #, extent)
            m1_sum += mxx*weight
            m2_sum += myy*weight
            weight_sum += weight
    if weight_sum == 0.0:
        return 0,0
    else:
        return m1_sum/weight_sum, m2_sum/weight_sum
Пример #4
0
def getCoaddSecondMoments(coaddpsf, point, useValidPolygon=False):
    count = coaddpsf.getComponentCount()
    coaddWcs = coaddpsf.getCoaddWcs()
    weight_sum = 0.0
    m1_sum = 0.0
    m2_sum = 0.0
    for i in range(count):
        wcs = coaddpsf.getWcs(i)
        psf = coaddpsf.getPsf(i)
        bbox = afwGeom.Box2D(coaddpsf.getBBox(i))
        if useValidPolygon:
            validPolygon = coaddpsf.getValidPolygon(i)
        else:
            validPolygon = Polygon(bbox)

        point_rel = wcs.skyToPixel(coaddWcs.pixelToSky(afwGeom.Point2D(point)))
        if bbox.contains(point_rel) and validPolygon.contains(point_rel):
            weight = coaddpsf.getWeight(i)
            m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments(psf,
                                                             point)  #, extent)
            m1_sum += mxx * weight
            m2_sum += myy * weight
            weight_sum += weight
    if weight_sum == 0.0:
        return 0, 0
    else:
        return m1_sum / weight_sum, m2_sum / weight_sum
Пример #5
0
 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)
Пример #6
0
class ValidPolygonTestCase(utilsTests.TestCase):
    def setUp(self):
        self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                  afwGeom.Point2I(20, 20))
        x = [0, 0, 10, 10]
        y = [0, 10, 10, 0]
        self.polygon = Polygon(
            [afwGeom.Point2D(xc, yc) for xc, yc in zip(x, y)])

    def testPersistence(self):
        """Test that we can round-trip an ValidPolygon through FITS persistence."""
        filename = "testValidPolygon.fits"
        self.polygon.writeFits(filename)
        polygon2 = Polygon.readFits(filename)
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposurePersistence(self):
        """Test that the ValidPolygon is saved with an Exposure"""
        filename = "testValidPolygon.fits"
        exposure1 = afwImage.ExposureF(self.bbox)
        exposure1.getInfo().setValidPolygon(self.polygon)
        exposure1.writeFits(filename)
        exposure2 = afwImage.ExposureF(filename)
        polygon2 = exposure2.getInfo().getValidPolygon()
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposureRecordPersistence(self):
        """Test that the ValidPolygon is saved with an ExposureRecord"""
        filename = "testValidPolygon.fits"
        cat1 = afwTable.ExposureCatalog(
            afwTable.ExposureTable.makeMinimalSchema())
        record1 = cat1.addNew()
        record1.setValidPolygon(self.polygon)
        cat1.writeFits(filename)
        cat2 = afwTable.ExposureCatalog.readFits(filename)
        record2 = cat2[0]
        polygon2 = record2.getValidPolygon()
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposureCatalogBackwardsCompatibility(self):
        """Test that we can read an ExposureCatalog written with an old version of the code."""
        filename = os.path.join(os.environ["AFW_DIR"], "tests", "data",
                                "version-0-ExposureCatalog.fits")
        cat = afwTable.ExposureCatalog.readFits(filename)
        record = cat[0]
        self.assertIsNone(record.getValidPolygon())

        filename2 = os.path.join(os.environ["AFW_DIR"], "tests", "data",
                                 "version-1-ExposureCatalog.fits")
        cat2 = afwTable.ExposureCatalog.readFits(filename2)
        record2 = cat2[0]
        self.assertIsNone(record2.getValidPolygon())
    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).getPoint()
        fpCenterX = fpCenter[0]
        fpCenterY = fpCenter[1]
        pixCenter = exposure.getDetector().getCenter(PIXELS).getPoint()

        # 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 = 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)))
Пример #8
0
class ValidPolygonTestCase(utilsTests.TestCase):

    def setUp(self):
        self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(20, 20))
        x=[0,0,10,10]
        y=[0,10,10,0]
        self.polygon=Polygon([afwGeom.Point2D(xc,yc) for xc,yc in zip(x,y)])

    def testPersistence(self):
        """Test that we can round-trip an ValidPolygon through FITS persistence."""
        filename = "testValidPolygon.fits"
        self.polygon.writeFits(filename)
        polygon2 = Polygon.readFits(filename)
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposurePersistence(self):
        """Test that the ValidPolygon is saved with an Exposure"""
        filename = "testValidPolygon.fits"
        exposure1 = afwImage.ExposureF(self.bbox)
        exposure1.getInfo().setValidPolygon(self.polygon)
        exposure1.writeFits(filename)
        exposure2 = afwImage.ExposureF(filename)
        polygon2 = exposure2.getInfo().getValidPolygon()
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposureRecordPersistence(self):
        """Test that the ValidPolygon is saved with an ExposureRecord"""
        filename = "testValidPolygon.fits"
        cat1 = afwTable.ExposureCatalog(afwTable.ExposureTable.makeMinimalSchema())
        record1 = cat1.addNew()
        record1.setValidPolygon(self.polygon)
        cat1.writeFits(filename)
        cat2 = afwTable.ExposureCatalog.readFits(filename)
        record2 = cat2[0]
        polygon2 = record2.getValidPolygon()
        self.assertEqual(self.polygon, polygon2)
        os.remove(filename)

    def testExposureCatalogBackwardsCompatibility(self):
        """Test that we can read an ExposureCatalog written with an old version of the code."""
        filename = os.path.join(os.environ["AFW_DIR"], "tests", "data", "version-0-ExposureCatalog.fits")
        cat = afwTable.ExposureCatalog.readFits(filename)
        record = cat[0]
        self.assertIsNone(record.getValidPolygon())

        filename2 = os.path.join(os.environ["AFW_DIR"], "tests", "data", "version-1-ExposureCatalog.fits")
        cat2 = afwTable.ExposureCatalog.readFits(filename2)
        record2 = cat2[0]
        self.assertIsNone(record2.getValidPolygon())
 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)
Пример #10
0
 def testPersistence(self):
     """Test that we can round-trip an ValidPolygon through FITS persistence."""
     filename = "testValidPolygon.fits"
     self.polygon.writeFits(filename)
     polygon2 = Polygon.readFits(filename)
     self.assertEqual(self.polygon, polygon2)
     os.remove(filename)
def makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints):
    theta = np.linspace(0, 2 * np.pi, num=numPolygonPoints, endpoint=False)
    xx = fpRadius * np.cos(theta) + fpCenterX
    yy = fpRadius * np.sin(theta) + fpCenterY
    points = np.array([xx, yy]).transpose()
    polygon = Polygon([afwGeom.Point2D(x, y) for x, y in reversed(points)])
    return polygon
Пример #12
0
 def testPersistence(self):
     """Test that we can round-trip an ValidPolygon through FITS persistence."""
     filename = "testValidPolygon.fits"
     self.polygon.writeFits(filename)
     polygon2 = Polygon.readFits(filename)
     self.assertEqual(self.polygon, polygon2)
     os.remove(filename)
Пример #13
0
    def testUnion(self):
        """Test Polygon.union"""
        poly1 = self.square(2.0, -1.0, -1.0)
        poly2 = self.square(2.0, +1.0, +1.0)
        poly3 = Polygon([
            afwGeom.Point2D(x, y)
            for x, y in ((-3.0, -3.0), (-3.0, +1.0), (-1.0, +1.0),
                         (-1.0, +3.0), (+3.0, +3.0), (+3.0, -1.0),
                         (+1.0, -1.0), (+1.0, -3.0))
        ])
        poly4 = self.square(1.0, +5.0, +5.0)

        # unionSingle: assumes there's a single union (intersecting polygons)
        self.assertEqual(poly1.unionSingle(poly2), poly3)
        self.assertEqual(poly2.unionSingle(poly1), poly3)
        self.assertRaisesLsstCpp(SinglePolygonException, poly1.unionSingle,
                                 poly4)
        self.assertRaisesLsstCpp(SinglePolygonException, poly4.unionSingle,
                                 poly1)

        # union: no assumptions
        polyList1 = poly1.union(poly2)
        polyList2 = poly2.union(poly1)
        self.assertEqual(polyList1, polyList2)
        self.assertEqual(len(polyList1), 1)
        self.assertEqual(polyList1[0], poly3)
        polyList3 = poly1.union(poly4)
        polyList4 = poly4.union(poly1)
        self.assertEqual(len(polyList3), 2)
        self.assertEqual(len(polyList3), len(polyList4))
        self.assertTrue(
            (polyList3[0] == polyList4[0] and polyList3[1] == polyList4[1])
            or (polyList3[0] == polyList4[1] and polyList3[1] == polyList4[0]))
        self.assertTrue((polyList3[0] == poly1 and polyList3[1] == poly4)
                        or (polyList3[0] == poly4 and polyList3[1] == poly1))
Пример #14
0
    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 = afwGeom.PointD(1000 - 10.0 * i, 1000.0 - 10.0 * i)
            wcs = afwImage.makeWcs(self.crval, crpix, self.cd11, self.cd12,
                                   self.cd21, self.cd22)
            record.setWcs(wcs)
            record['weight'] = 1.0 * (i + 1)
            record['id'] = i
            record.setBBox(
                afwGeom.Box2I(afwGeom.Point2I(0, 0),
                              afwGeom.Extent2I(1000, 1000)))
            validPolygon = Polygon(
                afwGeom.Box2D(afwGeom.Point2D(0, 0),
                              afwGeom.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 [
                afwGeom.Point2D(50, 50),
                afwGeom.Point2D(500, 500),
                afwGeom.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)
Пример #15
0
 def testFromBox(self):
     size = 1.0
     poly1 = self.square(size=size)
     box = afwGeom.Box2D(afwGeom.Point2D(-1.0, -1.0),
                         afwGeom.Point2D(1.0, 1.0))
     poly2 = Polygon(box)
     self.assertEqual(poly1, poly2)
Пример #16
0
    def testValidPolygonPsf(self):
        """Test that we can use the validPolygon on exposures in the coadd psf"""
        print "ValidPolygonTest"
        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Each of the 9 has its peculiar Psf, Wcs, weight, bounding box, and valid region.
        for i in range(1, 10, 1):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)
            record.setPsf(psf)
            crpix = afwGeom.PointD(1000 - 10.0 * i, 1000.0 - 10.0 * i)
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

            record.setWcs(wcs)
            record['weight'] = 1.0 * (i + 1)
            record['id'] = i
            bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(1000, 1000))
            record.setBBox(bbox)
            validPolygon_bbox = afwGeom.Box2D(
                afwGeom.Point2D(0, 0), afwGeom.Extent2D(i * 100, i * 100))
            validPolygon = Polygon(validPolygon_bbox)
            record.setValidPolygon(validPolygon)
            mycatalog.append(record)

        # Create the coaddpsf and check at three different points to ensure that the validPolygon is working
        mypsf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(50, 50), True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(50, 50))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))

        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(500, 500),
                                                 True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(500, 500))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))

        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(850, 850),
                                                 True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(850, 850))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))
Пример #17
0
 def testReadWrite(self):
     """Test that polygons can be read and written to fits files"""
     for num in range(3, 30):
         poly = self.polygon(num)
         with lsst.utils.tests.getTempFilePath(".fits") as filename:
             poly.writeFits(filename)
             poly2 = Polygon.readFits(filename)
         self.assertEqual(poly, poly2)
    def setValidPolygonIntersect(self, ccdExposure, fpPolygon):
        """!Set the valid polygon as the intersection of fpPolygon and the ccd corners

        \param[in,out]  exposure    exposure to process
        \param[in]      fpPolygon   Polygon in focal plane coordinates
        """
        # Get ccd corners in focal plane coordinates
        ccd = ccdExposure.getDetector()
        fpCorners = ccd.getCorners(FOCAL_PLANE)
        ccdPolygon = Polygon(fpCorners)

        # Get intersection of ccd corners with fpPolygon
        intersect = ccdPolygon.intersectionSingle(fpPolygon)

        # Transform back to pixel positions and build new polygon
        ccdPoints = [ccd.transform(ccd.makeCameraPoint(x, FOCAL_PLANE), PIXELS).getPoint() for x in intersect]
        validPolygon = Polygon(ccdPoints)
        ccdExposure.getInfo().setValidPolygon(validPolygon)
Пример #19
0
 def testReadWrite(self):
     """Test that polygons can be read and written to fits files"""
     for num in range(3, 30):
         poly = self.polygon(num)
         filename='polygon.fits'
         poly.writeFits(filename)
         poly2=Polygon.readFits(filename)
         self.assertEqual(poly, poly2)
         os.remove(filename)
Пример #20
0
    def setValidPolygonIntersect(self, ccdExposure, fpPolygon):
        """!Set the valid polygon as the intersection of fpPolygon and the ccd corners

        \param[in,out]  exposure    exposure to process
        \param[in]      fpPolygon   Polygon in focal plane coordinates
        """
        # Get ccd corners in focal plane coordinates
        ccd = ccdExposure.getDetector()
        fpCorners = ccd.getCorners(FOCAL_PLANE)
        ccdPolygon = Polygon(fpCorners)

        # Get intersection of ccd corners with fpPolygon
        intersect = ccdPolygon.intersectionSingle(fpPolygon)

        # Transform back to pixel positions and build new polygon
        ccdPoints = [ccd.transform(ccd.makeCameraPoint(x, FOCAL_PLANE), PIXELS).getPoint() for x in intersect]
        validPolygon = Polygon(ccdPoints)
        ccdExposure.getInfo().setValidPolygon(validPolygon)
Пример #21
0
 def testReadWrite(self):
     """Test that polygons can be read and written to fits files"""
     for num in range(3, 30):
         poly = self.polygon(num)
         filename = 'polygon.fits'
         poly.writeFits(filename)
         poly2 = Polygon.readFits(filename)
         self.assertEqual(poly, poly2)
         os.remove(filename)
Пример #22
0
    def square(self, size=1.0, x0=0, y0=0):
        """Generate a square

        @param size: Half-length of the sides
        @param x0,y0: Offset of center
        """
        return Polygon([
            afwGeom.Point2D(size * x + x0, size * y + y0)
            for x, y in ((-1, -1), (-1, 1), (1, 1), (1, -1))
        ])
Пример #23
0
 def testConvexHull(self):
     """Test Polygon.convexHull"""
     poly1 = self.square(2.0, -1.0, -1.0)
     poly2 = self.square(2.0, +1.0, +1.0)
     poly = poly1.unionSingle(poly2)
     expected = Polygon([
         afwGeom.Point2D(x, y)
         for x, y in ((-3.0, -3.0), (-3.0, +1.0), (-1.0, +3.0),
                      (+3.0, +3.0), (+3.0, -1.0), (+1.0, -3.0))
     ])
     self.assertEqual(poly.convexHull(), expected)
Пример #24
0
    def polygon(self, num, radius=1.0, x0=None, y0=None):
        """Generate a polygon

        @param num: Number of points
        @param radius: Radius of polygon
        @param x0,y0: Offset of center
        @return polygon
        """
        if x0 is None:
            x0 = self.x0
        if y0 is None:
            y0 = self.y0
        points = circle(radius, num, x0=x0, y0=y0)
        return Polygon([afwGeom.Point2D(x, y) for x, y in reversed(points)])
Пример #25
0
 def __init__(self, *args, **kwargs):
     super(SubaruIsrTask, self).__init__(*args, **kwargs)
     self.makeSubtask("crosstalk")
     if self.config.doWriteVignettePolygon:
         theta = numpy.linspace(0,
                                2 * numpy.pi,
                                num=self.config.numPolygonPoints,
                                endpoint=False)
         x = self.config.vignette.radius * numpy.cos(
             theta) + self.config.vignette.xCenter
         y = self.config.vignette.radius * numpy.sin(
             theta) + self.config.vignette.yCenter
         points = numpy.array([x, y]).transpose()
         self.vignettePolygon = Polygon(
             [afwGeom.Point2D(x, y) for x, y in reversed(points)])
Пример #26
0
    def testTransform(self):
        """Test constructor for Polygon involving transforms"""
        box = afwGeom.Box2D(afwGeom.Point2D(0.0, 0.0),
                            afwGeom.Point2D(123.4, 567.8))
        poly1 = Polygon(box)
        scale = (0.2 * afwGeom.arcseconds).asDegrees()
        wcs = afwImage.makeWcs(
            afwCoord.Coord(0.0 * afwGeom.degrees, 0.0 * afwGeom.degrees),
            afwGeom.Point2D(0.0, 0.0), scale, 0.0, 0.0, scale)
        transform = afwImage.XYTransformFromWcsPair(wcs, wcs)
        poly2 = Polygon(box, transform)

        # We lose some very small precision in the XYTransformFromWcsPair
        # so we can't compare the polygons directly.
        self.assertEqual(poly1.getNumEdges(), poly2.getNumEdges())
        for p1, p2 in zip(poly1.getVertices(), poly2.getVertices()):
            self.assertAlmostEqual(p1.getX(), p2.getX())
            self.assertAlmostEqual(p1.getY(), p2.getY())

        transform = afwGeom.AffineTransform.makeScaling(1.0)
        poly3 = Polygon(box, transform)
        self.assertEqual(poly1, poly3)
    def constructElements(self, validBox):
        """Construct the elements of a CoaddBoundedField."""
        np.random.seed(50)
        validPolygon = Polygon(lsst.afw.geom.Box2D(validBox)) if validBox else None
        elements = []
        validBoxes = []

        for i in range(10):
            elements.append(
                lsst.meas.algorithms.CoaddBoundedField.Element(
                    self.makeRandomField(self.elementBBox),
                    self.makeRandomWcs(self.crval),
                    validPolygon,
                    np.random.uniform(low=0.5, high=1.5)
                )
            )
            validBoxes.append(validBox)
        return elements, validBoxes
Пример #28
0
    def makeExposure(self, universalId):
        """Make a tiny exposure with exposure info set, but no pixels

        In particular, exposure info is set as a record in a table, so it can be recorded in a coadd
        """
        inputRecorder = self.coaddInputRecorder.makeCoaddTempExpRecorder(
            universalId, self.numExp)
        bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(100, 100),
                                   lsst.afw.geom.Extent2I(10, 10))

        detectorName = "detector {}".format(universalId)
        detector = lsst.afw.cameraGeom.testUtils.DetectorWrapper(
            name=detectorName, id=universalId).detector

        exp = lsst.afw.image.ExposureF(bbox)
        exp.setDetector(detector)

        expInfo = exp.getInfo()
        wcs = lsst.afw.image.makeWcs(
            IcrsCoord(10 * lsst.afw.geom.degrees, 45 * lsst.afw.geom.degrees),
            lsst.afw.geom.Point2D(5, 5),
            5.1e-5,
            0,
            0,
            -5.1e-5,  # CD: 11, 12, 21, 22
        )
        expInfo.setWcs(wcs)
        expInfo.setPsf(GaussianPsf(5, 5, 2.5))
        calib = lsst.afw.image.Calib()
        calib.setFluxMag0(1.1e12, 2.2e10)
        expInfo.setCalib(calib)
        expInfo.setApCorrMap(self.makeApCorrMap())
        expInfo.setValidPolygon(Polygon(
            lsst.afw.geom.Box2D(bbox).getCorners()))
        if self.version > 1:
            expInfo.setVisitInfo(self.makeVisitInfo())

        inputRecorder.addCalExp(calExp=exp, ccdId=universalId, nGoodPix=100)
        inputRecorder.finish(coaddTempExp=exp, nGoodPix=100)

        return exp
Пример #29
0
    def setUp(self):
        crval = lsst.afw.coord.IcrsCoord(45.0 * lsst.afw.geom.degrees,
                                         45.0 * lsst.afw.geom.degrees)
        elementBBox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-50, -50),
                                          lsst.afw.geom.Point2I(50, 50))
        validBox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-25, -25),
                                       lsst.afw.geom.Point2I(25, 25))
        self.elements = lsst.meas.algorithms.CoaddBoundedField.ElementVector()
        self.validBoxes = []

        for i in range(10):
            self.elements.append(
                lsst.meas.algorithms.CoaddBoundedField.Element(
                    self.makeRandomField(elementBBox),
                    self.makeRandomWcs(crval),
                    Polygon(lsst.afw.geom.Box2D(validBox)),
                    numpy.random.uniform(low=0.5, high=1.5)))
            self.validBoxes.append(validBox)
        self.coaddWcs = self.makeRandomWcs(crval, maxOffset=0.0)
        self.bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(-75, -75),
                                        lsst.afw.geom.Point2I(75, 75))
Пример #30
0
    def testTransform(self):
        """Test constructor for Polygon involving transforms"""
        box = afwGeom.Box2D(afwGeom.Point2D(0.0, 0.0), afwGeom.Point2D(123.4, 567.8))
        poly1 = Polygon(box)
        scale = (0.2*afwGeom.arcseconds).asDegrees()
        wcs = afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees),
                               afwGeom.Point2D(0.0, 0.0), scale, 0.0, 0.0, scale)
        transform = afwImage.XYTransformFromWcsPair(wcs, wcs)
        poly2 = Polygon(box, transform)

        # We lose some very small precision in the XYTransformFromWcsPair
        # so we can't compare the polygons directly.
        self.assertEqual(poly1.getNumEdges(), poly2.getNumEdges())
        for p1, p2 in zip(poly1.getVertices(), poly2.getVertices()):
            self.assertAlmostEqual(p1.getX(), p2.getX())
            self.assertAlmostEqual(p1.getY(), p2.getY())

        transform = afwGeom.AffineTransform.makeScaling(1.0)
        poly3 = Polygon(box, transform)
        self.assertEqual(poly1, poly3)
def makeSquarePolygon(fpX0, fpY0, fpSize):
    xx = [fpX0, fpX0, fpX0 + fpSize - 1, fpX0 + fpSize - 1, fpX0]
    yy = [fpY0, fpY0 + fpSize - 1, fpY0 + fpSize - 1, fpY0, fpY0]
    points = np.array([xx, yy]).transpose()
    polygon = Polygon([afwGeom.Point2D(x, y) for x, y in points])
    return polygon
Пример #32
0
    def testCountInputs(self):
        num = 3  # Number of images
        size = 10  # Size of images (pixels)
        shift = 4  # Shift to apply between images (pixels)
        value = 100.0  # Value to give objects
        offset = 12345  # x0,y0

        cdMatrix = (1.0e-5, 0.0, 0.0, 1.0e-5)
        crval = afwCoord.Coord(0.0 * afwGeom.degrees, 0.0 * afwGeom.degrees)

        positions = [
            afwGeom.Point2D(size // 2 + shift * (i - num // 2) + offset,
                            size // 2 + shift * (i - num // 2) + offset)
            for i in range(num)
        ]
        wcsList = [
            afwImage.makeWcs(crval, pos - afwGeom.Extent2D(offset, offset),
                             *cdMatrix) for pos in positions
        ]
        imageBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(size, size))
        wcsRef = afwImage.makeWcs(crval, afwGeom.Point2D(offset, offset),
                                  *cdMatrix)

        exp = afwImage.ExposureF(size, size)
        exp.setXY0(afwGeom.Point2I(offset, offset))
        exp.setWcs(wcsRef)
        exp.setPsf(measAlg.DoubleGaussianPsf(5, 5, 1.0))
        exp.getInfo().setCoaddInputs(
            afwImage.CoaddInputs(afwTable.ExposureTable.makeMinimalSchema(),
                                 afwTable.ExposureTable.makeMinimalSchema()))
        ccds = exp.getInfo().getCoaddInputs().ccds
        for wcs in wcsList:
            record = ccds.addNew()
            record.setWcs(wcs)
            record.setBBox(imageBox)
            record.setValidPolygon(Polygon(afwGeom.Box2D(imageBox)))

        exp.getMaskedImage().getImage().set(0)
        exp.getMaskedImage().getMask().set(0)
        exp.getMaskedImage().getVariance().set(1.0)
        for pp in positions:
            x, y = map(int, pp)
            exp.getMaskedImage().getImage().set0(x, y, value)
            exp.getMaskedImage().getMask().set(x - offset, y - offset, value)

        measureSourcesConfig = measAlg.SourceMeasurementConfig()
        measureSourcesConfig.algorithms.names = [
            "centroid.naive", "countInputs"
        ]
        measureSourcesConfig.slots.centroid = "centroid.naive"
        measureSourcesConfig.slots.psfFlux = None
        measureSourcesConfig.slots.apFlux = None
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.instFlux = None
        measureSourcesConfig.slots.calibFlux = None
        measureSourcesConfig.slots.shape = None
        measureSourcesConfig.validate()
        schema = afwTable.SourceTable.makeMinimalSchema()
        ms = measureSourcesConfig.makeMeasureSources(schema)
        catalog = afwTable.SourceCatalog(schema)
        measureSourcesConfig.slots.setupTable(catalog.getTable())

        for pp in positions:
            foot = afwDetection.Footprint(afwGeom.Point2I(pp), 1.0)
            peak = foot.getPeaks().addNew()
            peak.setIx(int(pp[0]))
            peak.setIy(int(pp[1]))
            peak.setFx(pp[0])
            peak.setFy(pp[1])
            peak.setPeakValue(value)

            source = catalog.addNew()
            source.setFootprint(foot)

            ms.applyWithPeak(source, exp)

            number = sum(
                afwGeom.Box2D(imageBox).contains(
                    wcs.skyToPixel(wcsRef.pixelToSky(pp))) for wcs in wcsList)
            self.assertEqual(source.get("countInputs"), number)
Пример #33
0
    def testInputCounts(self, showPlot=False):
        # Generate a simulated coadd of four overlapping-but-offset CCDs.
        # Populate it with three sources.
        # Demonstrate that we can correctly recover the number of images which
        # contribute to each source.

        size = 20  # Size of images (pixels)
        value = 100.0  # Source flux

        ccdPositions = [
            afwGeom.Point2D(8, 0),
            afwGeom.Point2D(10, 10),
            afwGeom.Point2D(-8, -8),
            afwGeom.Point2D(-8, 8)
        ]

        # Represent sources by a tuple of position and expected number of
        # contributing CCDs (based on the size/positions given above).
        Source = namedtuple("Source", ["pos", "count"])
        sources = [
            Source(pos=afwGeom.Point2D(6, 6), count=2),
            Source(pos=afwGeom.Point2D(10, 10), count=3),
            Source(pos=afwGeom.Point2D(14, 14), count=1)
        ]

        # These lines are used in the creation of WCS information
        cdMatrix = (1.0e-5, 0.0, 0.0, 1.0e-5)
        crval = afwCoord.Coord(0.0 * afwGeom.degrees, 0.0 * afwGeom.degrees)

        # Construct the info needed to set the exposure object
        imageBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(size, size))
        wcsRef = afwImage.makeWcs(crval, afwGeom.Point2D(0, 0), *cdMatrix)

        # Create the exposure object, and set it up to be the output of a coadd
        exp = afwImage.ExposureF(size, size)
        exp.setWcs(wcsRef)
        exp.getInfo().setCoaddInputs(
            afwImage.CoaddInputs(afwTable.ExposureTable.makeMinimalSchema(),
                                 afwTable.ExposureTable.makeMinimalSchema()))

        # Set the fake CCDs that "went into" making this coadd, using the
        # differing wcs objects created above.
        ccds = exp.getInfo().getCoaddInputs().ccds
        for pos in ccdPositions:
            record = ccds.addNew()
            record.setWcs(afwImage.makeWcs(crval, pos, *cdMatrix))
            record.setBBox(imageBox)
            record.setValidPolygon(Polygon(afwGeom.Box2D(imageBox)))

        # Configure a SingleFrameMeasurementTask to run InputCounts.
        measureSourcesConfig = measBase.SingleFrameMeasurementConfig()
        measureSourcesConfig.plugins.names = [
            "base_PeakCentroid", "base_InputCount"
        ]
        measureSourcesConfig.slots.centroid = "base_PeakCentroid"
        measureSourcesConfig.slots.psfFlux = None
        measureSourcesConfig.slots.apFlux = None
        measureSourcesConfig.slots.modelFlux = None
        measureSourcesConfig.slots.instFlux = None
        measureSourcesConfig.slots.calibFlux = None
        measureSourcesConfig.slots.shape = None
        measureSourcesConfig.validate()
        schema = afwTable.SourceTable.makeMinimalSchema()
        task = measBase.SingleFrameMeasurementTask(schema,
                                                   config=measureSourcesConfig)
        catalog = afwTable.SourceCatalog(schema)

        # Add simulated sources to the measurement catalog.
        for src in sources:
            spans = afwGeom.SpanSet.fromShape(1)
            spans = spans.shiftedBy(int(src.pos.getX()), int(src.pos.getY()))
            foot = afwDetection.Footprint(spans)
            peak = foot.getPeaks().addNew()
            peak.setFx(src.pos[0])
            peak.setFy(src.pos[1])
            peak.setPeakValue(value)
            catalog.addNew().setFootprint(foot)

        task.run(catalog, exp)

        for src, rec in zip(sources, catalog):
            self.assertEqual(rec.get("base_InputCount_value"), src.count)

        if display:
            ccdVennDiagram(exp)
Пример #34
0
 def setUp(self):
     self.bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(20, 20))
     x=[0,0,10,10]
     y=[0,10,10,0]
     self.polygon=Polygon([afwGeom.Point2D(xc,yc) for xc,yc in zip(x,y)])
Пример #35
0
 def makePolygon():
     # We "hide" the import of Polygon here as it has side effects due to
     # pybind11 "order of import" issues. See the brief discussion at
     # DM-10289.
     from lsst.afw.geom.polygon import Polygon
     return Polygon([Point2D(1,2), Point2D(2,1)])
Пример #36
0
 def testPersistence(self):
     """Test that we can round-trip an ValidPolygon through FITS persistence."""
     with lsst.utils.tests.getTempFilePath(".fits") as filename:
         self.polygon.writeFits(filename)
         polygon2 = Polygon.readFits(filename)
         self.assertEqual(self.polygon, polygon2)
Пример #37
0
    def test(self):
        """Check that we can create and use a coadd ApCorrMap"""
        coaddBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(100, 100))
        scale = 5.0e-5  # deg/pix; for CD matrix
        coord = afwCoord.Coord(0.0 * afwGeom.degrees, 0.0 * afwGeom.degrees)
        center = afwGeom.Point2D(
            afwGeom.Extent2D(coaddBox.getDimensions()) * 0.5)
        coaddWcs = afwImage.makeWcs(coord, afwGeom.Point2D(0, 0), scale, 0.0,
                                    0.0, scale)
        schema = afwTable.ExposureTable.makeMinimalSchema()
        weightKey = schema.addField("customweightname",
                                    type="D",
                                    doc="Coadd weight")
        catalog = afwTable.ExposureCatalog(schema)

        # Non-overlapping
        num = 5
        inputBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(10, 10))
        validBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(7, 7))
        pointList = []
        pointListValid = []

        for i in range(num):
            value = numpy.array([[1]],
                                dtype=float)  # Constant with value = i+1
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value * (i + 1))
            apCorrMap.set("only", bf)

            point = afwGeom.Point2D(0, 0) - afwGeom.Extent2D(
                coaddBox.getDimensions()) * (i + 0.5) / num
            wcs = afwImage.makeWcs(coord, point, scale, 0.0, 0.0, scale)
            center = afwGeom.Box2D(inputBox).getCenter()
            pointList.append(coaddWcs.skyToPixel(wcs.pixelToSky(center)))

            # This point will only be valid for the second overlapping record
            pointValid = center + afwGeom.Extent2D(4, 4)
            pointListValid.append(
                coaddWcs.skyToPixel(wcs.pixelToSky(pointValid)))

            # A record with the valid polygon defining a limited region
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 1)
            record['id'] = i
            record.setValidPolygon(Polygon(afwGeom.Box2D(validBox)))
            catalog.append(record)

            # An overlapping record with the whole region as valid
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value * (i + 2))
            apCorrMap.set("only", bf)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 2)
            record['id'] = i + num
            record.setValidPolygon(Polygon(afwGeom.Box2D(inputBox)))
            catalog.append(record)

        apCorrMap = measAlg.makeCoaddApCorrMap(catalog, coaddBox, coaddWcs,
                                               "customweightname")
        # This will test a point where both records contribute
        self.assertApCorrMap(apCorrMap, pointList)
        # Only the second record will be valid for this point
        self.assertApCorrMapValid(apCorrMap, pointListValid)

        filename = "tests/coaddApCorrMap.fits"
        exposure = afwImage.ExposureF(1, 1)
        exposure.getInfo().setApCorrMap(apCorrMap)
        exposure.writeFits(filename)
        exposure = afwImage.ExposureF(filename)
        self.assertApCorrMap(exposure.getInfo().getApCorrMap(), pointList)
        self.assertApCorrMapValid(exposure.getInfo().getApCorrMap(),
                                  pointListValid)
        os.unlink(filename)