def testMutators(self): box = geom.Box2D(geom.Point2D(-2, -3), geom.Point2D(2, 1), True) box.grow(1) self.assertEqual( box, geom.Box2D(geom.Point2D(-3, -4), geom.Point2D(3, 2), True)) box.grow(geom.Extent2D(2, 3)) self.assertEqual( box, geom.Box2D(geom.Point2D(-5, -7), geom.Point2D(5, 5), True)) box.shift(geom.Extent2D(3, 2)) self.assertEqual( box, geom.Box2D(geom.Point2D(-2, -5), geom.Point2D(8, 7), True)) box.include(geom.Point2D(-4, 2)) self.assertEqual( box, geom.Box2D(geom.Point2D(-4, -5), geom.Point2D(8, 7), True)) self.assertTrue(box.contains(geom.Point2D(-4, 2))) box.include(geom.Point2D(0, -6)) self.assertEqual( box, geom.Box2D(geom.Point2D(-4, -6), geom.Point2D(8, 7), True)) box.include(geom.Box2D(geom.Point2D(0, 0), geom.Point2D(10, 11), True)) self.assertEqual( box, geom.Box2D(geom.Point2D(-4, -6), geom.Point2D(10, 11), True)) box.clip(geom.Box2D(geom.Point2D(0, 0), geom.Point2D(11, 12), True)) self.assertEqual( box, geom.Box2D(geom.Point2D(0, 0), geom.Point2D(10, 11), True)) box.clip(geom.Box2D(geom.Point2D(-1, -2), geom.Point2D(5, 4), True)) self.assertEqual( box, geom.Box2D(geom.Point2D(0, 0), geom.Point2D(5, 4), True))
def fromCamera(cls, config, camera): """Construct from a camera object Parameters ---------- config : `FocalPlaneBackgroundConfig` Configuration for measuring backgrounds. camera : `lsst.afw.cameraGeom.Camera` Camera for which to measure backgrounds. """ cameraBox = geom.Box2D() for ccd in camera: for point in ccd.getCorners(afwCameraGeom.FOCAL_PLANE): cameraBox.include(point) width, height = cameraBox.getDimensions() # Offset so that we run from zero offset = geom.Extent2D(cameraBox.getMin()) * -1 # Add an extra pixel buffer on either side dims = geom.Extent2I( int(numpy.ceil(width / config.xSize)) + 2, int(numpy.ceil(height / config.ySize)) + 2) # Transform takes us from focal plane coordinates --> sample coordinates transform = ( geom.AffineTransform.makeTranslation(geom.Extent2D(1, 1)) * geom.AffineTransform.makeScaling(1.0 / config.xSize, 1.0 / config.ySize) * geom.AffineTransform.makeTranslation(offset)) return cls(config, dims, afwGeom.makeTransform(transform))
def testFindTract(self): """Test the SkyMap.findTract method """ for numTracts in (2, 4): config = EquatSkyMap.ConfigClass() config.numTracts = numTracts skyMap = EquatSkyMap(config) decRange = skyMap.config.decRange decList = ( (decRange[0] * 0.999) + (decRange[1] * 0.901), (decRange[0] * 0.500) + (decRange[1] * 0.500), (decRange[0] * 0.091) + (decRange[1] * 0.999), ) for tractInfo0 in skyMap: tractId0 = tractInfo0.getId() ctrCoord0 = tractInfo0.getCtrCoord() for tractInfo1 in self.getNeighborTracts(skyMap, tractId0): tractId1 = tractInfo1.getId() ctrCoord1 = tractInfo1.getCtrCoord() for deltaFrac in (-0.001, 0.001): v0 = ctrCoord0.getVector() * (0.5 + deltaFrac) v1 = ctrCoord1.getVector() * (0.5 - deltaFrac) testVec = v0 + v1 testRa = geom.SpherePoint(testVec).getRa() if deltaFrac > 0.0: expectedTractId = tractId0 else: expectedTractId = tractId1 for testDecDeg in decList: testDec = geom.Angle(testDecDeg, geom.degrees) testCoord = geom.SpherePoint(testRa, testDec) nearestTractInfo = skyMap.findTract(testCoord) nearestTractId = nearestTractInfo.getId() self.assertEqual(nearestTractId, expectedTractId) patchInfo = nearestTractInfo.findPatch(testCoord) pixelInd = geom.Point2I(nearestTractInfo.getWcs().skyToPixel(testCoord)) self.assertTrue(patchInfo.getInnerBBox().contains(pixelInd)) # find a point outside the tract and make sure it fails tractInfo = tractInfo0 wcs = tractInfo.getWcs() bbox = geom.Box2D(tractInfo.getBBox()) outerPixPosList = [ bbox.getMin() - geom.Extent2D(1, 1), geom.Point2D(bbox.getMaxX(), bbox.getMinY()) - geom.Extent2D(1, 1), bbox.getMax() + geom.Extent2D(1, 1), geom.Point2D(bbox.getMinX(), bbox.getMaxY()) + geom.Extent2D(1, 1), ] for outerPixPos in outerPixPosList: testCoord = wcs.pixelToSky(outerPixPos) self.assertRaises(LookupError, tractInfo.findPatch, testCoord)
def testConstructors(self): # test extent from extent 2-d e1 = geom.Extent2I(1, 2) e2 = geom.Extent2I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent2D(1.2, 3.4) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent2I(1, 2) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from extent 3-d e1 = geom.Extent3I(1, 2, 3) e2 = geom.Extent3I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent3D(1.2, 3.4, 5.6) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Extent3I(1, 2, 3) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from point 2-d e1 = geom.Point2I(1, 2) e2 = geom.Extent2I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point2D(1.2, 3.4) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point2I(1, 2) e2 = geom.Extent2D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) # test extent from point 3-d e1 = geom.Point3I(1, 2, 3) e2 = geom.Extent3I(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point3D(1.2, 3.4, 5.6) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2)) e1 = geom.Point3I(1, 2, 3) e2 = geom.Extent3D(e1) self.assertAlmostEqual(tuple(e1), tuple(e2))
def _getCenterOfMass(exp, nominalCentroid, boxSize): """Get the centre of mass around a point in the image. Parameters ---------- exp : `lsst.afw.image.Exposure` The exposure in question. nominalCentroid : `tuple` of `float` Nominal location of the centroid in pixel coordinates. boxSize : `int` The size of the box around the nominalCentroid in which to measure the centre of mass. Returns ------- com : `tuple` of `float` The locaiton of the centre of mass of the brightest source in pixel coordinates. """ centroidPoint = geom.Point2I(nominalCentroid) extent = geom.Extent2I(1, 1) bbox = geom.Box2I(centroidPoint, extent) bbox = bbox.dilatedBy(int(boxSize // 2)) bbox = bbox.clippedTo(exp.getBBox()) data = exp[bbox].image.array xy0 = exp[bbox].getXY0() peak = ndImage.center_of_mass(data) peak = (peak[1], peak[0]) # numpy coords returned com = geom.Point2D(xy0) com.shift(geom.Extent2D(*peak)) return (com[0], com[1])
def _finalOrientation(self, bbox, wcs): """Determine the final orientation We offset everything so the lower-left corner is at 0,0 and compute the final Wcs. Parameters ---------- bbox : `lsst.geom.Box2I` Current bounding box. wcs : `lsst.afw.geom.SkyWcs Current Wcs. Returns ------- finalBBox : `lsst.geom.Box2I` Revised bounding box. wcs : `lsst.afw.geom.SkyWcs` Revised Wcs. """ finalBBox = geom.Box2I(geom.Point2I(0, 0), bbox.getDimensions()) # shift the WCS by the same amount as the bbox; extra code is required # because simply subtracting makes an Extent2I pixPosOffset = geom.Extent2D(finalBBox.getMinX() - bbox.getMinX(), finalBBox.getMinY() - bbox.getMinY()) wcs = wcs.copyAtShiftedPixelOrigin(pixPosOffset) return finalBBox, wcs
def testMakeCenteredBox(self): dimensionsI = [ geom.Extent2I(100, 50), geom.Extent2I(15, 15), geom.Extent2I(0, 10), geom.Extent2I(25, 30), geom.Extent2I(15, -5) ] dimensionsD = [geom.Extent2D(d) for d in dimensionsI] \ + [geom.Extent2D(1.5, 2.1), geom.Extent2D(4, 3.7), geom.Extent2D(-0.1, -0.1), geom.Extent2D(5.5, 5.5), geom.Extent2D(-np.nan, 5.5), geom.Extent2D(4, np.inf)] locations = [ geom.Point2D(0, 0), geom.Point2D(0.2, 0.7), geom.Point2D(1, 1.5), geom.Point2D(-0.5 + 1e-4, -0.5 + 1e-4), geom.Point2D(-0.5 - 1e-4, -0.5 - 1e-4), geom.Point2D(-np.nan, 0), geom.Point2D(1.0, np.inf), ] for center in locations: for size in dimensionsI: self._checkBoxConstruction(geom.Box2I, size, center, np.sqrt(0.5)) for size in dimensionsD: self._checkBoxConstruction(geom.Box2D, size, center, 1e-10)
def runMeasurement(self, algorithmName, imageid, x, y, v): """Run the measurement algorithm on an image""" # load the test image imgFile = os.path.join(self.dataDir, "image.%d.fits" % imageid) img = afwImage.ImageF(imgFile) img -= self.bkgd nx, ny = img.getWidth(), img.getHeight() msk = afwImage.Mask(geom.Extent2I(nx, ny), 0x0) var = afwImage.ImageF(geom.Extent2I(nx, ny), v) mimg = afwImage.MaskedImageF(img, msk, var) msk.getArray()[:] = np.where(np.fabs(img.getArray()) < 1.0e-8, msk.getPlaneBitMask("BAD"), 0) # Put it in a bigger image, in case it matters big = afwImage.MaskedImageF(self.offset + mimg.getDimensions()) big.getImage().set(0) big.getMask().set(0) big.getVariance().set(v) subBig = afwImage.MaskedImageF(big, geom.Box2I(big.getXY0() + self.offset, mimg.getDimensions())) subBig <<= mimg mimg = big mimg.setXY0(self.xy0) exposure = afwImage.makeExposure(mimg) cdMatrix = np.array([1.0/(2.53*3600.0), 0.0, 0.0, 1.0/(2.53*3600.0)]) cdMatrix.shape = (2, 2) exposure.setWcs(afwGeom.makeSkyWcs(crpix=geom.Point2D(1.0, 1.0), crval=geom.SpherePoint(0, 0, geom.degrees), cdMatrix=cdMatrix)) # load the corresponding test psf psfFile = os.path.join(self.dataDir, "psf.%d.fits" % imageid) psfImg = afwImage.ImageD(psfFile) psfImg -= self.bkgd kernel = afwMath.FixedKernel(psfImg) kernelPsf = algorithms.KernelPsf(kernel) exposure.setPsf(kernelPsf) # perform the shape measurement msConfig = base.SingleFrameMeasurementConfig() alg = base.SingleFramePlugin.registry[algorithmName].PluginClass.AlgClass control = base.SingleFramePlugin.registry[algorithmName].PluginClass.ConfigClass().makeControl() msConfig.algorithms.names = [algorithmName] # Note: It is essential to remove the floating point part of the position for the # Algorithm._apply. Otherwise, when the PSF is realised it will have been warped # to account for the sub-pixel offset and we won't get *exactly* this PSF. plugin, table = makePluginAndCat(alg, algorithmName, control, centroid="centroid") center = geom.Point2D(int(x), int(y)) + geom.Extent2D(self.offset + geom.Extent2I(self.xy0)) source = table.makeRecord() source.set("centroid_x", center.getX()) source.set("centroid_y", center.getY()) source.setFootprint(afwDetection.Footprint(afwGeom.SpanSet(exposure.getBBox(afwImage.PARENT)))) plugin.measure(source, exposure) return source
def computeImageScaler(self, exposure, dataRef): """Compute image scaling object for a given exposure. @param[in] exposure: exposure for which scaling is desired. Only wcs and bbox are used. @param[in] dataRef: dataRef of exposure dataRef.dataId used to retrieve all applicable fluxMag0's from a database. @return a SpatialImageScaler """ wcs = exposure.getWcs() fluxMagInfoList = self.selectFluxMag0.run( dataRef.dataId).fluxMagInfoList xList = [] yList = [] scaleList = [] for fluxMagInfo in fluxMagInfoList: # find center of field in tract coordinates if not fluxMagInfo.coordList: raise RuntimeError("no x,y data for fluxMagInfo") ctr = geom.Extent2D() for coord in fluxMagInfo.coordList: # accumulate x, y ctr += geom.Extent2D(wcs.skyToPixel(coord)) # and find average x, y as the center of the chip ctr = geom.Point2D(ctr / len(fluxMagInfo.coordList)) xList.append(ctr.getX()) yList.append(ctr.getY()) scaleList.append( self.scaleFromFluxMag0(fluxMagInfo.fluxMag0).scale) self.log.info("Found %d flux scales for interpolation: %s", len(scaleList), [f"{s:%0.4f}" for s in scaleList]) return SpatialImageScaler( interpStyle=self.config.interpStyle, xList=xList, yList=yList, scaleList=scaleList, )
def toCcdBackground(self, detector, bbox): """Produce a background model for a CCD The superpixel background model is warped back to the CCD frame, for application to the individual CCD. Parameters ---------- detector : `lsst.afw.cameraGeom.Detector` CCD for which to produce background model. bbox : `lsst.geom.Box2I` Bounding box of CCD exposure. Returns ------- bg : `lsst.afw.math.BackgroundList` Background model for CCD. """ transform = detector.getTransformMap().getTransform( detector.makeCameraSys(afwCameraGeom.PIXELS), detector.makeCameraSys(afwCameraGeom.FOCAL_PLANE)) binTransform = ( geom.AffineTransform.makeScaling(self.config.binning) * geom.AffineTransform.makeTranslation(geom.Extent2D(0.5, 0.5))) # Binned image on CCD --> unbinned image on CCD --> focal plane --> binned focal plane toSample = afwGeom.makeTransform(binTransform).then(transform).then( self.transform) focalPlane = self.getStatsImage() fpNorm = afwImage.ImageF(focalPlane.getBBox()) fpNorm.set(1.0) image = afwImage.ImageF(bbox.getDimensions() // self.config.binning) norm = afwImage.ImageF(image.getBBox()) ctrl = afwMath.WarpingControl("bilinear") afwMath.warpImage(image, focalPlane, toSample.inverted(), ctrl) afwMath.warpImage(norm, fpNorm, toSample.inverted(), ctrl) image /= norm mask = afwImage.Mask(image.getBBox()) isBad = numpy.isnan(image.getArray()) mask.getArray()[isBad] = mask.getPlaneBitMask("BAD") image.getArray()[isBad] = image.getArray()[~isBad].mean() return afwMath.BackgroundList( (afwMath.BackgroundMI(bbox, afwImage.makeMaskedImage(image, mask)), afwMath.stringToInterpStyle(self.config.interpolation), afwMath.stringToUndersampleStyle("REDUCE_INTERP_ORDER"), afwMath.ApproximateControl.UNKNOWN, 0, 0, False))
def createImage( dataId={"name": "foobar"}, # Data identifier center=CENTER, # ICRS sky position of center (lsst.afw.geom.SpherePoint) rotateAxis=ROTATEAXIS, # Rotation axis (lsst.afw.geom.SpherePoint) rotateAngle=0 * geom.degrees, # Rotation angle/distance to move (Angle) dims=DIMS, # Image dimensions (Extent2I) scale=SCALE # Pixel scale (Angle) ): crpix = geom.Point2D(geom.Extent2D(dims) * 0.5) center = center.rotated(rotateAxis, rotateAngle) cdMatrix = afwGeom.makeCdMatrix(scale=scale) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=center, cdMatrix=cdMatrix) return SelectStruct( DummyDataRef(dataId), wcs, geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(dims[0], dims[1])))
def testWcsPostIsr(self): """Test the wcs of postISRCCD products The postISRCCD wcs should be the same as the raw wcs after adding camera distortion and adjustment of overscan/prescan trimming. Test DM-4859. """ if not self.config.isr.doWrite or not self.config.isr.assembleCcd.doTrim: return expRaw = self.butler.get("raw", self.dataId, immediate=True) expPost = self.butler.get("postISRCCD", self.dataId, immediate=True) self.assertIsInstance(expPost, afwImage.ExposureF) wcsRaw = expRaw.getWcs() wcsPost = expPost.getWcs() # Shift WCS for trimming the prescan and overscan region # ccdnum 1 is S29, with overscan in the bottom wcsRaw = wcsRaw.copyAtShiftedPixelOrigin(geom.Extent2D(-56, -50)) self.assertWcsAlmostEqualOverBBox(wcsRaw, wcsPost, expPost.getBBox())
def testConstruction(self): for n in range(10): xmin, xmax, ymin, ymax = np.random.uniform(low=-5, high=5, size=4) if xmin > xmax: xmin, xmax = xmax, xmin if ymin > ymax: ymin, ymax = ymax, ymin pmin = geom.Point2D(xmin, ymin) pmax = geom.Point2D(xmax, ymax) # min/max constructor box = geom.Box2D(pmin, pmax) self.assertEqual(box.getMin(), pmin) self.assertEqual(box.getMax(), pmax) box = geom.Box2D(pmax, pmin) self.assertEqual(box.getMin(), pmin) self.assertEqual(box.getMax(), pmax) box = geom.Box2D(pmin, pmax, False) self.assertEqual(box.getMin(), pmin) self.assertEqual(box.getMax(), pmax) box = geom.Box2D(pmax, pmin, False) self.assertTrue(box.isEmpty()) self.assertEqual(box, geom.Box2D(box)) # min/dim constructor dim = pmax - pmin if any(dim.eq(0)): box = geom.Box2D(pmin, dim) self.assertTrue(box.isEmpty()) box = geom.Box2D(pmin, dim, False) self.assertTrue(box.isEmpty()) else: box = geom.Box2D(pmin, dim) self.assertEqual(box.getMin(), pmin) self.assertEqual(box.getDimensions(), dim) box = geom.Box2D(pmin, dim, False) self.assertEqual(box.getMin(), pmin) self.assertEqual(box.getDimensions(), dim) dim = -dim box = geom.Box2D(pmin, dim) self.assertEqual(box.getMin(), pmin + dim) self.assertFloatsAlmostEqual( box.getDimensions(), geom.Extent2D(abs(dim.getX()), abs(dim.getY())))
def createPatch( tractId=1, patchId=(2, 3), # Tract and patch identifier, for dataId dims=DIMS, # Patch dimensions (Extent2I) xy0=geom.Point2I(1234, 5678), # Patch xy0 (Point2I) center=CENTER, # ICRS sky position of center (lsst.afw.geom.SpherePoint) scale=SCALE # Pixel scale (Angle) ): crpix = geom.Point2D(xy0) + geom.Extent2D(dims) * 0.5 cdMatrix = afwGeom.makeCdMatrix(scale=scale) wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=center, cdMatrix=cdMatrix) patch = DummyPatch(xy0, dims) tract = DummyTract(patchId, patch, wcs) skymap = DummySkyMap(tractId, tract) dataRef = DummyDataRef( { 'tract': tractId, 'patch': ",".join(map(str, patchId)) }, deepCoadd_skyMap=skymap) return dataRef
def testFlipD(self): parentExtent = geom.Extent2D(15.1, 20.6) x00, y00, x11, y11 = (8.3, 11.4, 13.2, 16.9) lrx00, lry00, lrx11, lry11 = (1.9, 11.4, 6.8, 16.9) tbx00, tby00, tbx11, tby11 = (8.3, 3.7, 13.2, 9.2) box0 = geom.Box2D(geom.Point2D(x00, y00), geom.Point2D(x11, y11)) box1 = geom.Box2D(geom.Point2D(x00, y00), geom.Point2D(x11, y11)) box0.flipLR(parentExtent[0]) box1.flipTB(parentExtent[1]) # test flip RL self.assertAlmostEqual(box0.getMinX(), lrx00, places=6) self.assertAlmostEqual(box0.getMinY(), lry00, places=6) self.assertAlmostEqual(box0.getMaxX(), lrx11, places=6) self.assertAlmostEqual(box0.getMaxY(), lry11, places=6) # test flip TB self.assertAlmostEqual(box1.getMinX(), tbx00, places=6) self.assertAlmostEqual(box1.getMinY(), tby00, places=6) self.assertAlmostEqual(box1.getMaxX(), tbx11, places=6) self.assertAlmostEqual(box1.getMaxY(), tby11, places=6)
def _solve(self, sourceCat, wcs, bbox, pixelScale, radecCenter, searchRadius, parity, filterName=None): """ @param[in] parity True for flipped parity, False for normal parity, None to leave parity unchanged """ solver = self.refObjLoader._getSolver() imageSize = bbox.getDimensions() x0, y0 = bbox.getMin() # select sources with valid x, y, flux xybb = geom.Box2D() goodsources = afwTable.SourceCatalog(sourceCat.table) badkeys = [goodsources.getSchema().find(name).key for name in self.config.badFlags] for s in sourceCat: if np.isfinite(s.getX()) and np.isfinite(s.getY()) and np.isfinite(s.getPsfInstFlux()) \ and self._isGoodSource(s, badkeys): goodsources.append(s) xybb.include(geom.Point2D(s.getX() - x0, s.getY() - y0)) self.log.info("Number of selected sources for astrometry : %d" % (len(goodsources))) if len(goodsources) < len(sourceCat): self.log.debug('Keeping %i of %i sources with finite X,Y positions and PSF flux', len(goodsources), len(sourceCat)) self.log.debug('Feeding sources in range x=[%.1f, %.1f], y=[%.1f, %.1f] ' + '(after subtracting x0,y0 = %.1f,%.1f) to Astrometry.net', xybb.getMinX(), xybb.getMaxX(), xybb.getMinY(), xybb.getMaxY(), x0, y0) # setStars sorts them by PSF flux. solver.setStars(goodsources, x0, y0) solver.setMaxStars(self.config.maxStars) solver.setImageSize(*imageSize) solver.setMatchThreshold(self.config.matchThreshold) raDecRadius = None if radecCenter is not None: raDecRadius = (radecCenter.getLongitude().asDegrees(), radecCenter.getLatitude().asDegrees(), searchRadius.asDegrees()) solver.setRaDecRadius(*raDecRadius) self.log.debug('Searching for match around RA,Dec = (%g, %g) with radius %g deg' % raDecRadius) if pixelScale is not None: dscale = self.config.pixelScaleUncertainty scale = pixelScale.asArcseconds() lo = scale / dscale hi = scale * dscale solver.setPixelScaleRange(lo, hi) self.log.debug( 'Searching for matches with pixel scale = %g +- %g %% -> range [%g, %g] arcsec/pix', scale, 100.*(dscale-1.), lo, hi) if parity is not None: solver.setParity(parity) self.log.debug('Searching for match with parity = %s', str(parity)) # Find and load index files within RA,Dec range and scale range. if radecCenter is not None: multiInds = self.refObjLoader._getMIndexesWithinRange(radecCenter, searchRadius) else: multiInds = self.refObjLoader.multiInds qlo, qhi = solver.getQuadSizeRangeArcsec() toload_multiInds = set() toload_inds = [] for mi in multiInds: for i in range(len(mi)): ind = mi[i] if not ind.overlapsScaleRange(qlo, qhi): continue toload_multiInds.add(mi) toload_inds.append(ind) import lsstDebug if lsstDebug.Info(__name__).display: # Use separate context for display, since astrometry.net can segfault if we don't... with LoadMultiIndexes(toload_multiInds): displayAstrometry(refCat=self.refObjLoader.loadPixelBox(bbox, wcs, filterName).refCat, frame=lsstDebug.Info(__name__).frame, pause=lsstDebug.Info(__name__).pause) with LoadMultiIndexes(toload_multiInds): solver.addIndices(toload_inds) self.memusage('Index files loaded: ') cpulimit = self.config.maxCpuTime solver.run(cpulimit) self.memusage('Solving finished: ') self.memusage('Index files unloaded: ') if solver.didSolve(): self.log.debug('Solved!') wcs = solver.getWcs() if x0 != 0 or y0 != 0: wcs = wcs.copyAtShiftedPixelOrigin(geom.Extent2D(x0, y0)) else: self.log.warn('Did not get an astrometric solution from Astrometry.net') wcs = None # Gather debugging info... # -are there any reference stars in the proposed search area? # log the number found and discard the results if radecCenter is not None: self.refObjLoader.loadSkyCircle(radecCenter, searchRadius, filterName) qa = solver.getSolveStats() self.log.debug('qa: %s', qa.toString()) return wcs, qa
def testRounding(self): e1 = geom.Extent2D(1.2, -3.4) self.assertEqual(e1.floor(), geom.Extent2I(1, -4)) self.assertEqual(e1.ceil(), geom.Extent2I(2, -3)) self.assertEqual(e1.truncate(), geom.Extent2I(1, -3))
def testIntersect(self): self.check( createPatch(), createImage(rotateAngle=0.5 * geom.Extent2D(DIMS).computeNorm() * SCALE), True)
def pixelSize(self): """Return the pixel size as an Extent2D from the separate values. """ return geom.Extent2D(self.pixelSize_x, self.pixelSize_y)
def check(self, psfFwhm=0.5, flux=1000.0, forced=False): """Check that we can measure convolved fluxes We create an image with a Gaussian PSF and a single point source. Measurements of the point source should match expectations for a Gaussian of the known sigma and known aperture radius. Parameters ---------- psfFwhm : `float` PSF FWHM (arcsec) flux : `float` Source flux (ADU) forced : `bool` Forced measurement? """ bbox = geom.Box2I(geom.Point2I(12345, 6789), geom.Extent2I(200, 300)) # We'll only achieve the target accuracy if the pixel scale is rather smaller than Gaussians # involved. Otherwise it's important to consider the convolution with the pixel grid, and we're # not doing that here. scale = 0.1 * geom.arcseconds TaskClass = measBase.ForcedMeasurementTask if forced else measBase.SingleFrameMeasurementTask exposure, center = makeExposure(bbox, scale, psfFwhm, flux) measConfig = TaskClass.ConfigClass() algName = "ext_convolved_ConvolvedFlux" measConfig.plugins.names.add(algName) if not forced: measConfig.plugins.names.add("ext_photometryKron_KronFlux") else: measConfig.copyColumns = { "id": "objectId", "parent": "parentObjectId" } values = [ii / scale.asArcseconds() for ii in (0.6, 0.8, 1.0, 1.2)] algConfig = measConfig.plugins[algName] algConfig.seeing = values algConfig.aperture.radii = values algConfig.aperture.maxSincRadius = max( values) + 1 # Get as exact as we can if forced: offset = geom.Extent2D(-12.3, 45.6) kronRadiusName = "my_Kron_Radius" kronRadius = 12.345 refWcs = exposure.getWcs().copyAtShiftedPixelOrigin(offset) measConfig.plugins[algName].kronRadiusName = kronRadiusName refSchema = afwTable.SourceTable.makeMinimalSchema() centroidKey = afwTable.Point2DKey.addFields(refSchema, "my_centroid", doc="centroid", unit="pixel") shapeKey = afwTable.QuadrupoleKey.addFields( refSchema, "my_shape", "shape") refSchema.getAliasMap().set("slot_Centroid", "my_centroid") refSchema.getAliasMap().set("slot_Shape", "my_shape") refSchema.addField("my_centroid_flag", type="Flag", doc="centroid flag") refSchema.addField("my_shape_flag", type="Flag", doc="shape flag") refSchema.addField(kronRadiusName, type=float, doc="my custom kron radius", units="pixel") refCat = afwTable.SourceCatalog(refSchema) refSource = refCat.addNew() refSource.set(centroidKey, center + offset) refSource.set( shapeKey, afwEll.Quadrupole(afwEll.Axes(kronRadius, kronRadius, 0))) refSource.set(kronRadiusName, kronRadius) refSource.setCoord(refWcs.pixelToSky(refSource.get(centroidKey))) taskInitArgs = (refSchema, ) taskRunArgs = (refCat, refWcs) else: taskInitArgs = (afwTable.SourceTable.makeMinimalSchema(), ) taskRunArgs = () # Activate undeblended measurement with the same configuration measConfig.undeblended.names.add(algName) measConfig.undeblended[algName] = measConfig.plugins[algName] algMetadata = dafBase.PropertyList() task = TaskClass(*taskInitArgs, config=measConfig, algMetadata=algMetadata) schema = task.schema measCat = afwTable.SourceCatalog(schema) source = measCat.addNew() source.getTable().setMetadata(algMetadata) ss = afwDetection.FootprintSet(exposure.getMaskedImage(), afwDetection.Threshold(0.1)) fp = ss.getFootprints()[0] source.setFootprint(fp) task.run(measCat, exposure, *taskRunArgs) disp = afwDisplay.Display(frame) disp.mtv(exposure) disp.dot("x", *center, origin=afwImage.PARENT, title="psfFwhm=%f" % (psfFwhm, )) self.checkSchema(schema, algConfig.getAllApertureResultNames()) self.checkSchema(schema, algConfig.getAllKronResultNames()) self.checkSchema(schema, algConfig.getAllResultNames()) if not forced: kronRadius = source.get("ext_photometryKron_KronFlux_radius") self.assertFalse(source.get(algName + "_flag")) # algorithm succeeded originalSeeing = psfFwhm / scale.asArcseconds() for ii, targetSeeing in enumerate(algConfig.seeing): deconvolve = targetSeeing < originalSeeing seeing = originalSeeing if deconvolve else targetSeeing def expected(radius, sigma=seeing / SIGMA_TO_FWHM): """Return expected flux for 2D Gaussian with nominated sigma""" return flux * (1.0 - math.exp(-0.5 * (radius / sigma)**2)) for prefix in ("", "undeblended_"): self.assertEqual( source.get(prefix + algName + "_%d_deconv" % ii), deconvolve) # Kron succeeded and match expectation if not forced: kronName = algConfig.getKronResultName(targetSeeing) kronApRadius = algConfig.kronRadiusForFlux * kronRadius self.assertFloatsAlmostEqual(source.get(prefix + kronName + "_instFlux"), expected(kronApRadius), rtol=1.0e-3) self.assertGreater( source.get(prefix + kronName + "_instFluxErr"), 0) self.assertFalse(source.get(prefix + kronName + "_flag")) # Aperture measurements succeeded and match expectation for jj, radius in enumerate( measConfig.algorithms[algName].aperture.radii): name = algConfig.getApertureResultName( targetSeeing, radius) self.assertFloatsAlmostEqual(source.get(prefix + name + "_instFlux"), expected(radius), rtol=1.0e-3) self.assertFalse(source.get(prefix + name + "_flag")) self.assertGreater( source.get(prefix + name + "_instFluxErr"), 0)