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))
def setUp(self): # Test geometry: # # -100,99 99,99 # +--------------------+ # |AAAAAAAAAACCCCCDDDDD| A == only in epoch A # |AAAAAAAAAACCCCCDDDDD| B == only in epoch B # |AAAAAAAAAACCCCCDDDDD| C == in both epoch A and epoch B # |AAAAAAAAAACCCCCDDDDD| D == in epoch A; in B's bbox but outside its ValidPolygon # |AAAAAAAAAACCCCCDDDDD| # | BBBBBBBBBB| All WCSs have the same CRVAL and CD. # | BBBBBBBBBB| # | BBBBBBBBBB| Coadd has CRPIX=(0, 0) # | BBBBBBBBBB| Epoch A has CRPIX=(0, -50) # | BBBBBBBBBB| Epoch B has CRPIX=(-50, 0) # +--------------------+ # -100,-100 99,-100 # self.rng = np.random.RandomState(50) crval = SpherePoint(45.0, 45.0, degrees) cdMatrix = makeCdMatrix(scale=5E-5 * degrees, flipX=True) self.wcsCoadd = makeSkyWcs(crpix=Point2D(0.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.wcsA = makeSkyWcs(crpix=Point2D(0.0, -50.0), crval=crval, cdMatrix=cdMatrix) self.wcsB = makeSkyWcs(crpix=Point2D(-50.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.bboxCoadd = Box2I(Point2I(-100, -100), Point2I(99, 99)) self.bboxA = Box2I(Point2I(-100, -50), Point2I(99, 49)) self.bboxB = Box2I(Point2I(-50, -100), Point2I(49, 99)) self.polygonA = None polygonD = Polygon(Box2D(Box2I(Point2I(0, 0), Point2I(49, 99)))) self.polygonB, = polygonD.symDifference(Polygon(Box2D(self.bboxB))) self.curveA = makeRandomTransmissionCurve(self.rng) self.curveB = makeRandomTransmissionCurve(self.rng) self.weightA = 0.6 self.weightB = 0.2 schema = ExposureTable.makeMinimalSchema() weightKey = schema.addField("weight", type=float, doc="relative weight of image in Coadd") catalog = ExposureCatalog(schema) recordA = catalog.addNew() recordA[weightKey] = self.weightA recordA.setWcs(self.wcsA) recordA.setValidPolygon(self.polygonA) recordA.setBBox(self.bboxA) recordA.setTransmissionCurve(self.curveA) recordB = catalog.addNew() recordB[weightKey] = self.weightB recordB.setWcs(self.wcsB) recordB.setValidPolygon(self.polygonB) recordB.setBBox(self.bboxB) recordB.setTransmissionCurve(self.curveB) self.curveCoadd = makeCoaddTransmissionCurve(self.wcsCoadd, catalog)
def 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
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)
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
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)
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))
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 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))
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)
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)) ])
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)
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)))
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 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)])
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)])
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
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
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))
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)
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)
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)])
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
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)