def testMakeAlertDict(self): """Test stripping data from the various data products and into a dictionary "alert". """ packageAlerts = PackageAlertsTask() alertId = 1234 for srcIdx, diaSource in self.diaSources.iterrows(): sphPoint = geom.SpherePoint(diaSource["ra"], diaSource["decl"], geom.degrees) cutout = self.exposure.getCutout( sphPoint, geom.Extent2I(self.cutoutSize, self.cutoutSize)) ccdCutout = packageAlerts.createCcdDataCutout( cutout, sphPoint, geom.Extent2I(self.cutoutSize, self.cutoutSize), cutout.getPhotoCalib(), 1234) cutoutBytes = packageAlerts.streamCcdDataToBytes(ccdCutout) objSources = self.diaSourceHistory.loc[srcIdx[0]] objForcedSources = self.diaForcedSources.loc[srcIdx[0]] alert = packageAlerts.makeAlertDict(alertId, diaSource, self.diaObjects.loc[srcIdx[0]], objSources, objForcedSources, ccdCutout, ccdCutout) self.assertEqual(len(alert), 9) self.assertEqual(alert["alertId"], alertId) self.assertEqual(alert["diaSource"], diaSource.to_dict()) self.assertEqual(alert["cutoutDifference"], cutoutBytes) self.assertEqual(alert["cutoutTemplate"], cutoutBytes)
def testGaussianWithNoise(self): # Convolve a real image with a gaussian and try and recover # it. Add noise and perform the same test. gsize = self.ps["kernelSize"] gaussFunction = afwMath.GaussianFunction2D(2, 3) gaussKernel = afwMath.AnalyticKernel(gsize, gsize, gaussFunction) kImageIn = afwImage.ImageD(geom.Extent2I(gsize, gsize)) kSumIn = gaussKernel.computeImage(kImageIn, False) imX, imY = self.templateExposure2.getMaskedImage().getDimensions() smi = afwImage.MaskedImageF(geom.Extent2I(imX, imY)) afwMath.convolve(smi, self.templateExposure2.getMaskedImage(), gaussKernel, False) bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL)) tmi2 = afwImage.MaskedImageF(self.templateExposure2.getMaskedImage(), bbox, origin=afwImage.LOCAL) smi2 = afwImage.MaskedImageF(smi, bbox, origin=afwImage.LOCAL) kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.ps) kList = ipDiffim.makeKernelBasisList(self.subconfig) kc.build(kList) self.assertEqual(kc.isInitialized(), True) kImageOut = kc.getImage() soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT) self.assertAlmostEqual(soln.getKsum(), kSumIn) # 8.7499380640430563e-06 != 0.0 within 7 places self.assertAlmostEqual(soln.getBackground(), 0.0, 4) for j in range(kImageOut.getHeight()): for i in range(kImageOut.getWidth()): # in the outskirts of the kernel, the ratio can get screwed because of low S/N # e.g. 7.45817359824e-09 vs. 1.18062529402e-08 # in the guts of the kernel it should look closer if kImageIn[i, j, afwImage.LOCAL] > 1e-4: # sigh, too bad this sort of thing fails.. # 0.99941584433815966 != 1.0 within 3 places self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL]/kImageIn[i, j, afwImage.LOCAL], 1.0, 2) # now repeat with noise added; decrease precision of comparison self.addNoise(smi2) kc = ipDiffim.KernelCandidateF(self.x02, self.y02, tmi2, smi2, self.ps) kList = ipDiffim.makeKernelBasisList(self.subconfig) kc.build(kList) self.assertEqual(kc.isInitialized(), True) kImageOut = kc.getImage() soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT) self.assertAlmostEqual(soln.getKsum(), kSumIn, 3) if not self.ps.get("fitForBackground"): self.assertEqual(soln.getBackground(), 0.0) for j in range(kImageOut.getHeight()): for i in range(kImageOut.getWidth()): if kImageIn[i, j, afwImage.LOCAL] > 1e-2: self.assertAlmostEqual(kImageOut[i, j, afwImage.LOCAL], kImageIn[i, j, afwImage.LOCAL], 2)
def testMutators(self): box = geom.Box2I(geom.Point2I(-2, -3), geom.Point2I(2, 1), True) box.grow(1) self.assertEqual( box, geom.Box2I(geom.Point2I(-3, -4), geom.Point2I(3, 2), True)) box.grow(geom.Extent2I(2, 3)) self.assertEqual( box, geom.Box2I(geom.Point2I(-5, -7), geom.Point2I(5, 5), True)) box.shift(geom.Extent2I(3, 2)) self.assertEqual( box, geom.Box2I(geom.Point2I(-2, -5), geom.Point2I(8, 7), True)) box.include(geom.Point2I(-4, 2)) self.assertEqual( box, geom.Box2I(geom.Point2I(-4, -5), geom.Point2I(8, 7), True)) box.include(geom.Point2I(0, -6)) self.assertEqual( box, geom.Box2I(geom.Point2I(-4, -6), geom.Point2I(8, 7), True)) box.include(geom.Box2I(geom.Point2I(0, 0), geom.Point2I(10, 11), True)) self.assertEqual( box, geom.Box2I(geom.Point2I(-4, -6), geom.Point2I(10, 11), True)) box.clip(geom.Box2I(geom.Point2I(0, 0), geom.Point2I(11, 12), True)) self.assertEqual( box, geom.Box2I(geom.Point2I(0, 0), geom.Point2I(10, 11), True)) box.clip(geom.Box2I(geom.Point2I(-1, -2), geom.Point2I(5, 4), True)) self.assertEqual( box, geom.Box2I(geom.Point2I(0, 0), geom.Point2I(5, 4), True))
def getAmplifier(image, amp, ampReference=None, offset=2): """Extract an image of the amplifier from the CCD, along with an offset version The amplifier image will be flipped (if required) to match the orientation of a nominated reference amplifier. An additional image, with the nominated offset applied, is also produced. Parameters ---------- image : Image of CCD amp : Index of amplifier ampReference : Index of reference amplifier offset : Offset to apply Returns ------- amp_image : amplifier image, offset amplifier image """ height = image.getHeight() ampBox = geom.Box2I(geom.Point2I(amp * 512, 0), geom.Extent2I(512, height)) ampImage = image.Factory(image, ampBox, afwImage.LOCAL) if ampReference is not None and amp % 2 != ampReference % 2: ampImage = afwMath.flipImage(ampImage, True, False) offBox = geom.Box2I(geom.Point2I(offset if amp == ampReference else 0, 0), geom.Extent2I(510, height)) offsetImage = ampImage.Factory(ampImage, offBox, afwImage.LOCAL) return ampImage, offsetImage
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 testAssertions(self): """Test that addToCoadd requires coadd and weightMap to have the same dimensions and xy0""" maskedImage = afwImage.MaskedImageF(geom.Extent2I(10, 10)) coadd = afwImage.MaskedImageF(geom.Extent2I(11, 11)) coadd.setXY0(5, 6) for dw, dh in (1, 0), (0, 1), (-1, 0), (0, -1): weightMapBBox = geom.Box2I( coadd.getXY0(), coadd.getDimensions() + geom.Extent2I(dw, dh)) weightMap = afwImage.ImageF(weightMapBBox) weightMap.setXY0(coadd.getXY0()) try: coaddUtils.addToCoadd(coadd, weightMap, maskedImage, 0x0, 0.1) self.fail("should have raised exception") except pexExcept.Exception: pass for dx0, dy0 in (1, 0), (0, 1), (-1, 0), (0, -1): weightMapBBox = geom.Box2I( coadd.getXY0() + geom.Extent2I(dx0, dy0), coadd.getDimensions()) weightMap = afwImage.ImageF(weightMapBBox) try: coaddUtils.addToCoadd(coadd, weightMap, maskedImage, 0x0, 0.1) self.fail("should have raised exception") except pexExcept.Exception: pass
def addAmp(ampCatalog, i, eparams): """ Add an amplifier to an AmpInfoCatalog @param ampCatalog: An instance of an AmpInfoCatalog object to fill with amp properties @param i which amplifier? (i == 0 ? left : right) @param eparams: Electronic parameters. This is a list of tuples with (i, params), where params is a dictionary of electronic parameters. """ # # Layout of active and overclock pixels in the as-readout data The layout is: # Amp0 || extended | overclock | data || data | overclock | extended || Amp1 # for each row; all rows are identical in drift-scan data # height = 1361 # number of rows in a frame width = 1024 # number of data pixels read out through one amplifier nExtended = 8 # number of pixels in the extended register nOverclock = 32 # number of (horizontal) overclock pixels # # Construct the needed bounding boxes given that geometrical information. # # Note that all the offsets are relative to the origin of this amp, not to its eventual # position in the CCD # record = ampCatalog.addNew() xtot = width + nExtended + nOverclock allPixels = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(xtot, height)) biasSec = geom.BoxI(geom.PointI(nExtended if i == 0 else width, 0), geom.ExtentI(nOverclock, height)) dataSec = geom.BoxI( geom.PointI(nExtended + nOverclock if i == 0 else 0, 0), geom.ExtentI(width, height)) emptyBox = geom.BoxI() bbox = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(width, height)) bbox.shift(geom.Extent2I(width * i, 0)) shiftp = geom.Extent2I(xtot * i, 0) allPixels.shift(shiftp) biasSec.shift(shiftp) dataSec.shift(shiftp) record.setBBox(bbox) record.setRawXYOffset(geom.ExtentI(0, 0)) record.setName('left' if i == 0 else 'right') record.setReadoutCorner(afwTable.LL if i == 0 else afwTable.LR) record.setGain(eparams['gain']) record.setReadNoise(eparams['readNoise']) record.setSaturation(eparams['fullWell']) record.setSuspectLevel(float("nan")) record.setLinearityType(NullLinearityType) record.setLinearityCoeffs([ 1., ]) record.setHasRawInfo(True) record.setRawFlipX(False) record.setRawFlipY(False) record.setRawBBox(allPixels) record.setRawDataBBox(dataSec) record.setRawHorizontalOverscanBBox(biasSec) record.setRawVerticalOverscanBBox(emptyBox) record.setRawPrescanBBox(emptyBox)
def makeCandidate(self, kSum, x, y, size=51): mi1 = afwImage.MaskedImageF(geom.Extent2I(size, size)) mi1.getVariance().set(1.0) # avoid NaNs mi1[size // 2, size // 2, afwImage.LOCAL] = (1, 0x0, 1) mi2 = afwImage.MaskedImageF(geom.Extent2I(size, size)) mi2.getVariance().set(1.0) # avoid NaNs mi2[size // 2, size // 2, afwImage.LOCAL] = (kSum, 0x0, kSum) kc = ipDiffim.makeKernelCandidate(x, y, mi1, mi2, self.ps) return kc
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 testGaussian(self, imsize=50): # Convolve a delta function with a known gaussian; try to # recover using delta-function basis gsize = self.ps["kernelSize"] tsize = imsize + gsize gaussFunction = afwMath.GaussianFunction2D(2, 3) gaussKernel = afwMath.AnalyticKernel(gsize, gsize, gaussFunction) kImageIn = afwImage.ImageD(geom.Extent2I(gsize, gsize)) gaussKernel.computeImage(kImageIn, False) # template image with a single hot pixel in the exact center tmi = afwImage.MaskedImageF(geom.Extent2I(tsize, tsize)) tmi.set(0, 0x0, 1e-4) cpix = tsize // 2 tmi[cpix, cpix, afwImage.LOCAL] = (1, 0x0, 1) # science image smi = afwImage.MaskedImageF(tmi.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(False) afwMath.convolve(smi, tmi, gaussKernel, convolutionControl) # get the actual kernel sum (since the image is not infinite) gscaling = afwMath.makeStatistics(smi, afwMath.SUM).getValue(afwMath.SUM) # grab only the non-masked subregion bbox = gaussKernel.shrinkBBox(smi.getBBox(afwImage.LOCAL)) tmi2 = afwImage.MaskedImageF(tmi, bbox, origin=afwImage.LOCAL) smi2 = afwImage.MaskedImageF(smi, bbox, origin=afwImage.LOCAL) # make sure its a valid subregion! for j in range(tmi2.getHeight()): for i in range(tmi2.getWidth()): self.assertEqual(tmi2.mask[i, j, afwImage.LOCAL], 0) self.assertEqual(smi2.mask[i, j, afwImage.LOCAL], 0) kc = ipDiffim.KernelCandidateF(0.0, 0.0, tmi2, smi2, self.ps) kList = ipDiffim.makeKernelBasisList(self.subconfig) kc.build(kList) self.assertEqual(kc.isInitialized(), True) kImageOut = kc.getImage() soln = kc.getKernelSolution(ipDiffim.KernelCandidateF.RECENT) self.assertAlmostEqual(soln.getKsum(), gscaling) self.assertAlmostEqual(soln.getBackground(), 0.0) for j in range(kImageOut.getHeight()): for i in range(kImageOut.getWidth()): self.assertAlmostEqual( kImageOut[i, j, afwImage.LOCAL] / kImageIn[i, j, afwImage.LOCAL], 1.0, 5)
def testRejection(self): # we need to construct a candidate whose shape does not # match the underlying basis # # so lets just make a kernel list with all the power in # the center, but the candidate requires some off center # power kc1 = self.makeCandidate(1, 0.0, 0.0) kc2 = self.makeCandidate(2, 0.0, 0.0) kc3 = self.makeCandidate(3, 0.0, 0.0) bskv1 = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps) bskv1.processCandidate(kc1) bskv1.processCandidate(kc2) bskv1.processCandidate(kc3) imagePca = ipDiffim.KernelPcaD() kpv = ipDiffim.KernelPcaVisitorF(imagePca) kpv.processCandidate(kc1) kpv.processCandidate(kc2) kpv.processCandidate(kc3) kpv.subtractMean() imagePca.analyze() eigenKernels = [] eigenKernels.append(kpv.getEigenKernels()[0]) self.assertEqual(len(eigenKernels), 1) # bogus candidate mi1 = afwImage.MaskedImageF(geom.Extent2I(self.size, self.size)) mi1.getVariance().set(0.1) mi1[self.size // 2, self.size // 2, afwImage.LOCAL] = (1, 0x0, 1) mi2 = afwImage.MaskedImageF(geom.Extent2I(self.size, self.size)) mi2.getVariance().set(0.1) # make it high enough to make the mean resids large mi2[self.size // 3, self.size // 3, afwImage.LOCAL] = (self.size**2, 0x0, 1) kc4 = ipDiffim.makeKernelCandidate(0, 0, mi1, mi2, self.ps) self.assertEqual(kc4.getStatus(), afwMath.SpatialCellCandidate.UNKNOWN) # process with eigenKernels bskv2 = ipDiffim.BuildSingleKernelVisitorF(eigenKernels, self.ps) bskv2.setSkipBuilt(False) bskv2.processCandidate(kc1) bskv2.processCandidate(kc2) bskv2.processCandidate(kc3) bskv2.processCandidate(kc4) self.assertEqual(bskv2.getNProcessed(), 4) self.assertEqual(bskv2.getNRejected(), 1) self.assertEqual(kc1.getStatus(), afwMath.SpatialCellCandidate.GOOD) self.assertEqual(kc2.getStatus(), afwMath.SpatialCellCandidate.GOOD) self.assertEqual(kc3.getStatus(), afwMath.SpatialCellCandidate.GOOD) self.assertEqual(kc4.getStatus(), afwMath.SpatialCellCandidate.BAD)
def testWholeImageGrid(self): """Test that a 1-cell `grid` is actually the whole image""" config = ZogyConfig() task = ZogyTask(config=config) bb = geom.Box2I(geom.Point2I(5, 10), geom.Extent2I(200, 300)) D = afwImage.ImageI(bb) grid = task.generateGrid(bb, geom.Extent2I(15, 15), bb.getDimensions()) self.assertTrue(len(grid) == 1, "Grid length is not 1") x = grid[0] D[x.innerBox] += 1 self.assertTrue(np.all(D.array == 1), "Single cell does not cover the original image.")
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 _testAddToCoaddImpl(self, useMask, uniformWeight=True): """Test coadd""" trueImageValue = 10.0 imBBox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(10, 20)) if useMask: coadd = afwImage.MaskedImageF(imBBox) weightMap = coadd.getImage().Factory(coadd.getBBox()) badBits = 0x1 badPixel = (float("NaN"), badBits, 0) truth = (trueImageValue, 0x0, 0) else: coadd = afwImage.ImageF(imBBox) weightMap = coadd.Factory(coadd.getBBox()) badPixel = float("NaN") truth = trueImageValue for i in range(0, 20, 3): image = coadd.Factory(coadd.getDimensions()) image.set(badPixel) subBBox = geom.Box2I(geom.Point2I(0, i), image.getDimensions() - geom.Extent2I(0, i)) subImage = image.Factory(image, subBBox, afwImage.LOCAL) subImage.set(truth) del subImage weight = 1.0 if uniformWeight else 1.0 + 0.1 * i if useMask: coaddUtils.addToCoadd(coadd, weightMap, image, badBits, weight) else: coaddUtils.addToCoadd(coadd, weightMap, image, weight) self.assertEqual(image[-1, -1, afwImage.LOCAL], truth) coadd /= weightMap if display: ds9.mtv(image, title="image", frame=1) ds9.mtv(coadd, title="coadd", frame=2) ds9.mtv(weightMap, title="weightMap", frame=3) stats = afwMath.makeStatistics(coadd, afwMath.MEAN | afwMath.STDEV) return [ trueImageValue, stats.getValue(afwMath.MEAN), 0.0, stats.getValue(afwMath.STDEV) ]
def testCreateBBox(self): """Test the bbox creation """ packConfig = PackageAlertsConfig() # Just create a minimum less than the default cutout. packConfig.minCutoutSize = self.cutoutSize - 5 packageAlerts = PackageAlertsTask(config=packConfig) bbox = packageAlerts.createDiaSourceBBox(packConfig.minCutoutSize - 5) self.assertTrue(bbox == geom.Extent2I(packConfig.minCutoutSize, packConfig.minCutoutSize)) # Test that the cutout size is correct. bbox = packageAlerts.createDiaSourceBBox(self.cutoutSize) self.assertTrue( bbox == geom.Extent2I(self.cutoutSize, self.cutoutSize))
def __init__(self, config): super().__init__(config) self._cellInnerDimensions = geom.Extent2I( *(val for val in config.cellInnerDimensions)) self._cellBorder = config.cellBorder self._numCellsPerPatchInner = config.numCellsPerPatchInner self._numCellsInPatchBorder = config.numCellsInPatchBorder self._patchInnerDimensions = geom.Extent2I( *(val * self._numCellsPerPatchInner for val in config.cellInnerDimensions)) # The patch border is the number of cells in the border + the cell border self._patchBorder = config.numCellsInPatchBorder * config.cellInnerDimensions[ 0] + self._cellBorder self._initialized = False
def testCreateExtent(self): """Test the extent creation for the cutout bbox. """ packConfig = PackageAlertsConfig() # Just create a minimum less than the default cutout. packConfig.minCutoutSize = self.cutoutSize - 5 packageAlerts = PackageAlertsTask(config=packConfig) extent = packageAlerts.createDiaSourceExtent(packConfig.minCutoutSize - 5) self.assertTrue(extent == geom.Extent2I(packConfig.minCutoutSize, packConfig.minCutoutSize)) # Test that the cutout size is correct. extent = packageAlerts.createDiaSourceExtent(self.cutoutSize) self.assertTrue( extent == geom.Extent2I(self.cutoutSize, self.cutoutSize))
def setUp(self): nSources = 10 # CFHT Filters from the camera mapper. afwImageUtils.resetFilters() afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301") afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401") afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601") afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701") afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801") self.bbox = geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(1024, 1153)) dataset = measTests.TestDataset(self.bbox) for srcIdx in range(nSources): dataset.addSource(100000.0, geom.Point2D(100, 100)) self.inputCatalogNoFlags, _ = make_input_source_catalog(dataset, False) self.inputCatalog, self.exposure = \ make_input_source_catalog(dataset, True) detector = DetectorWrapper(id=23, bbox=self.exposure.getBBox()).detector visit = afwImage.VisitInfo(exposureId=4321, exposureTime=200., date=dafBase.DateTime(nsecs=1400000000 * 10**9)) self.exposure.setDetector(detector) self.exposure.getInfo().setVisitInfo(visit) self.exposure.setFilter(afwImage.Filter('g.MP9401')) scale = 2 scaleErr = 1 self.photoCalib = afwImage.PhotoCalib(scale, scaleErr) self.exposure.setPhotoCalib(self.photoCalib)
def testVisit(self, nCell=3): bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps) sizeCellX = self.ps["sizeCellX"] sizeCellY = self.ps["sizeCellY"] kernelCellSet = afwMath.SpatialCellSet( geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(sizeCellX * nCell, sizeCellY * nCell)), sizeCellX, sizeCellY) nTot = 0 for candX in range(nCell): for candY in range(nCell): if candX == nCell // 2 and candY == nCell // 2: kc = self.makeCandidate(100.0, candX * sizeCellX + sizeCellX // 2, candY * sizeCellY + sizeCellY // 2) else: kc = self.makeCandidate(1.0, candX * sizeCellX + sizeCellX // 2, candY * sizeCellY + sizeCellY // 2) kernelCellSet.insertCandidate(kc) nTot += 1 kernelCellSet.visitCandidates(bskv, 1) self.assertEqual(bskv.getNProcessed(), nTot) self.assertEqual(bskv.getNRejected(), 0) for cell in kernelCellSet.getCellList(): for cand in cell.begin(False): self.assertEqual(cand.getStatus(), afwMath.SpatialCellCandidate.GOOD)
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 _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 vircamUpdateDetector(self, ccdExposure): """Update the detector bounding boxes to match the image VIRCAM CASU stacks are different sizes depending on Parameters ---------- ccdExposure : `lsst.afw.image.Exposure` The exposure to modify the bounding boxes for. """ detector = ccdExposure.getDetector() #update BBox to image size BBox = geom.Box2I( geom.Point2I(0, 0), geom.Extent2I(ccdExposure.getImage().array.shape[1], ccdExposure.getImage().array.shape[0])) self.log.info( "VISTA: Updating detector BBox to contain full stacked image [{},{}]." .format(ccdExposure.getImage().array.shape[1], ccdExposure.getImage().array.shape[0])) detBuilder = detector.rebuild() detBuilder.setBBox(BBox) amplifier = detBuilder.getAmplifiers()[0] #ampBuilder=amplifier.rebuild() amplifier.setRawBBox(BBox) amplifier.setBBox(BBox) amplifier.setRawDataBBox(BBox) ccdExposure.setDetector(detBuilder.finish())
def testSubMap(self): bbox = geom.BoxI(geom.Point2I(200, 100), geom.Extent2I(300, 400)) mapper = MinMapper2(root=ROOT) loc = mapper.map("raw_sub", {"ccd": 13, "bbox": bbox}, write=True) self.assertEqual(loc.getPythonType(), "lsst.afw.image.ExposureU") self.assertEqual(loc.getCppType(), "ImageU") self.assertEqual(loc.getStorageName(), "FitsStorage") self.assertEqual(loc.getLocations(), ["foo-13.fits"]) self.assertEqual(loc.getStorage().root, ROOT) self.assertEqual(loc.getAdditionalData().getScalar("ccd"), 13) self.assertEqual(loc.getAdditionalData().getScalar("width"), 300) self.assertEqual(loc.getAdditionalData().getScalar("height"), 400) self.assertEqual(loc.getAdditionalData().getScalar("llcX"), 200) self.assertEqual(loc.getAdditionalData().getScalar("llcY"), 100) checkCompression(self, loc.getAdditionalData()) loc = mapper.map("raw_sub", { "ccd": 13, "bbox": bbox, "imageOrigin": "PARENT" }, write=True) self.assertEqual(loc.getPythonType(), "lsst.afw.image.ExposureU") self.assertEqual(loc.getCppType(), "ImageU") self.assertEqual(loc.getStorageName(), "FitsStorage") self.assertEqual(loc.getLocations(), ["foo-13.fits"]) self.assertEqual(loc.getStorage().root, ROOT) self.assertEqual(loc.getAdditionalData().getScalar("ccd"), 13) self.assertEqual(loc.getAdditionalData().getScalar("width"), 300) self.assertEqual(loc.getAdditionalData().getScalar("height"), 400) self.assertEqual(loc.getAdditionalData().getScalar("llcX"), 200) self.assertEqual(loc.getAdditionalData().getScalar("llcY"), 100) self.assertEqual(loc.getAdditionalData().getScalar("imageOrigin"), "PARENT") checkCompression(self, loc.getAdditionalData())
def testVisit(self, nCell=3): ksv = ipDiffim.makeKernelSumVisitor(self.ps) sizeCellX = self.ps["sizeCellX"] sizeCellY = self.ps["sizeCellY"] kernelCellSet = afwMath.SpatialCellSet( geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(sizeCellX * nCell, sizeCellY * nCell)), sizeCellX, sizeCellY) for candX in range(nCell): for candY in range(nCell): if candX == nCell // 2 and candY == nCell // 2: kc = self.makeCandidate(100.0, candX * sizeCellX + sizeCellX // 2, candY * sizeCellY + sizeCellY // 2) else: kc = self.makeCandidate(1.0, candX * sizeCellX + sizeCellX // 2, candY * sizeCellY + sizeCellY // 2) kc.build(self.kList) kernelCellSet.insertCandidate(kc) ksv.setMode(ipDiffim.KernelSumVisitorF.AGGREGATE) kernelCellSet.visitCandidates(ksv, 1) ksv.processKsumDistribution() ksv.setMode(ipDiffim.KernelSumVisitorF.REJECT) kernelCellSet.visitCandidates(ksv, 1) self.assertEqual(ksv.getNRejected(), 1)
def makeExposure(imgArray, psfArray, imgVariance): """! Convert an image numpy.array and corresponding PSF numpy.array into an exposure. Add the (constant) variance plane equal to `imgVariance`. @param imgArray 2-d numpy.array containing the image @param psfArray 2-d numpy.array containing the PSF image @param imgVariance variance of input image @return a new exposure containing the image, PSF and desired variance plane """ # All this code to convert the template image array/psf array into an exposure. bbox = geom.Box2I( geom.Point2I(0, 0), geom.Point2I(imgArray.shape[1] - 1, imgArray.shape[0] - 1)) im1ex = afwImage.ExposureD(bbox) im1ex.getMaskedImage().getImage().getArray()[:, :] = imgArray im1ex.getMaskedImage().getVariance().getArray()[:, :] = imgVariance psfBox = geom.Box2I(geom.Point2I(-12, -12), geom.Point2I(12, 12)) # a 25x25 pixel psf psf = afwImage.ImageD(psfBox) psfBox.shift(geom.Extent2I(size[0] // 2, size[1] // 2)) im1_psf_sub = psfArray[psfBox.getMinX():psfBox.getMaxX() + 1, psfBox.getMinY():psfBox.getMaxY() + 1] psf.getArray()[:, :] = im1_psf_sub psfK = afwMath.FixedKernel(psf) psfNew = measAlg.KernelPsf(psfK) im1ex.setPsf(psfNew) wcs = makeWcs() im1ex.setWcs(wcs) return im1ex
def testImageStatisticsMask2(self): # Mask value that does not get ignored maskPlanes = self.ps.getArray("badMaskPlanes") for maskPlane in ("BAD", "EDGE", "CR", "SAT", "INTRP"): if maskPlane not in maskPlanes: maskVal = afwImage.Mask.getPlaneBitMask(maskPlane) break self.assertGreater(maskVal, 0) numArray = num.ones((20, 20)) mi = afwImage.MaskedImageF(geom.Extent2I(20, 20)) for j in range(mi.getHeight()): for i in range(mi.getWidth()): val = i + 2.3 * j if i == 19: mi[i, j, afwImage.LOCAL] = (val, maskVal, 1) numArray[j][i] = val else: mi[i, j, afwImage.LOCAL] = (val, 0x0, 1) numArray[j][i] = val imstat = ipDiffim.ImageStatisticsF(self.ps) imstat.apply(mi) self.assertAlmostEqual(imstat.getMean(), numArray.mean()) # note that these don't agree exactly... self.assertAlmostEqual(imstat.getRms(), numArray.std(), 1) self.assertEqual(imstat.getNpix(), 20 * 20)
def testGood(self): ti = afwImage.MaskedImageF(geom.Extent2I(100, 100)) ti.getVariance().set(0.1) ti[50, 50, afwImage.LOCAL] = (1., 0x0, 1.) sKernel = self.makeSpatialKernel(2) si = afwImage.MaskedImageF(ti.getDimensions()) convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(si, ti, sKernel, convolutionControl) bbox = geom.Box2I(geom.Point2I(25, 25), geom.Point2I(75, 75)) si = afwImage.MaskedImageF(si, bbox, origin=afwImage.LOCAL) ti = afwImage.MaskedImageF(ti, bbox, origin=afwImage.LOCAL) kc = ipDiffim.KernelCandidateF(50., 50., ti, si, self.ps) sBg = afwMath.PolynomialFunction2D(1) bgCoeffs = [0., 0., 0.] sBg.setParameters(bgCoeffs) # must be initialized bskv = ipDiffim.BuildSingleKernelVisitorF(self.kList, self.ps) bskv.processCandidate(kc) self.assertEqual(kc.isInitialized(), True) askv = ipDiffim.AssessSpatialKernelVisitorF(sKernel, sBg, self.ps) askv.processCandidate(kc) self.assertEqual(askv.getNProcessed(), 1) self.assertEqual(askv.getNRejected(), 0) self.assertEqual(kc.getStatus(), afwMath.SpatialCellCandidate.GOOD)
def bypass_defects(self, datasetType, pythonType, butlerLocation, dataId): """Return a defect based on the butler location returned by map_defects Parameters ---------- butlerLocation : `lsst.daf.persistence.ButlerLocation` locationList = path to defects FITS file dataId : `dict` Butler data ID; "ccd" must be set. Note: the name "bypass_XXX" means the butler makes no attempt to convert the ButlerLocation into an object, which is what we want for now, since that conversion is a bit tricky. """ detectorName = self._extractDetectorName(dataId) defectsFitsPath = butlerLocation.locationList[0] with fits.open(defectsFitsPath) as hduList: for hdu in hduList[1:]: if hdu.header["name"] != detectorName: continue defectList = Defects() for data in hdu.data: bbox = geom.Box2I( geom.Point2I(int(data['x0']), int(data['y0'])), geom.Extent2I(int(data['width']), int(data['height'])), ) defectList.append(bbox) return defectList raise RuntimeError("No defects for ccd %s in %s" % (detectorName, defectsFitsPath))
def testInsert(self): mi = afwImage.MaskedImageF(geom.Extent2I(10, 10)) kc = ipDiffim.makeKernelCandidate(0., 0., mi, mi, self.ps) kc.setStatus(afwMath.SpatialCellCandidate.GOOD) sizeCellX = self.ps["sizeCellX"] sizeCellY = self.ps["sizeCellY"] kernelCellSet = afwMath.SpatialCellSet(geom.Box2I(geom.Point2I(0, 0), geom.Extent2I(1, 1)), sizeCellX, sizeCellY) kernelCellSet.insertCandidate(kc) nSeen = 0 for cell in kernelCellSet.getCellList(): for cand in cell.begin(True): self.assertEqual(cand.getStatus(), afwMath.SpatialCellCandidate.GOOD) nSeen += 1 self.assertEqual(nSeen, 1)
def _setupPatches(self, minBBox, wcs): """Setup for patches of a particular size. We grow the bounding box to hold an exact multiple of the desired size (patchInnerDimensions), while keeping the center roughly the same. We return the final bounding box, and the number of patches in each dimension (as an Extent2I). Parameters ---------- minBBox : `lsst.geom.Box2I` Minimum bounding box for tract wcs : `lsst.afw.geom.SkyWcs` Wcs object Returns ------- bbox : `lsst.geom.Box2I final bounding box, number of patches numPatches : `int` """ bbox = geom.Box2I(minBBox) bboxMin = bbox.getMin() bboxDim = bbox.getDimensions() numPatches = geom.Extent2I(0, 0) for i, innerDim in enumerate(self._patchInnerDimensions): num = (bboxDim[i] + innerDim - 1) // innerDim # round up deltaDim = (innerDim * num) - bboxDim[i] if deltaDim > 0: bboxDim[i] = innerDim * num bboxMin[i] -= deltaDim // 2 numPatches[i] = num bbox = geom.Box2I(bboxMin, bboxDim) return bbox, numPatches