def run(): if len(sys.argv) < 2: srcExposure = afwImage.ExposureF(InputExposurePath) if WarpSubregion: bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(2000, 2000)) srcExposure = afwImage.ExposureF(srcExposure, bbox, afwImage.LOCAL, False) else: srcExposure = afwImage.ExposureF(sys.argv[1]) srcMaskedImage = srcExposure.getMaskedImage() srcMetadata = afwImage.DecoratedImageF(InputExposurePath).getMetadata() srcWcs = afwGeom.SkyWcs(srcMetadata) srcDim = srcExposure.getDimensions() srcCtrPos = afwGeom.Box2D(srcMaskedImage.getBBox()).getCenter() srcCtrSky = srcWcs.applyForward(srcCtrPos) srcScale = srcWcs.getPixelScale() # make the destination exposure small enough that even after rotation and offset # (by reasonable amounts) there are no edge pixels destDim = afwGeom.Extent2I(*[int(sd * 0.5) for sd in srcDim]) destMaskedImage = afwImage.MaskedImageF(destDim) destCrPix = afwGeom.Box2D(destMaskedImage.getBBox()).getCenter() maskKernelName = "" cacheSize = 0 print("Warping", InputExposurePath) print("Source (sub)image size:", srcDim) print("Destination image size:", destDim) print() print( "test# interp scaleFac destSkyOff rotAng kernel goodPix time/iter" ) print( ' (pix) (bear°, len") (deg) (sec)' ) testNum = 1 for interpLength in (0, 1, 5, 10): for scaleFac in (1.2, ): destScale = srcScale / scaleFac for offsetOrientDegLenArcsec in (( 0.0, 0.0), ): # ((0.0, 0.0), (-35.0, 10.5)): # offset (bearing, length) from sky at center of source to sky at center of dest offset = (offsetOrientDegLenArcsec[0] * afwGeom.degrees, offsetOrientDegLenArcsec[1] * afwGeom.arcseconds) destCtrSky = srcCtrSky.offset(*offset) for rotAngDeg, kernelName in ( (0.0, "bilinear"), (0.0, "lanczos2"), (0.0, "lanczos3"), (45.0, "lanczos3"), ): warpingControl = afwMath.WarpingControl( kernelName, maskKernelName, cacheSize, interpLength, ) destWcs = afwGeom.SkyWcs( crpix=destCrPix, crval=destCtrSky, cdMatrix=afwGeom.makeCdMatrix(scale=destScale, orientation=rotAngDeg * afwGeom.degrees, flipX=False)) destToSrc = destWcs.then(srcWcs.getInverse()) dTime, nIter, goodPix = timeWarp(destMaskedImage, srcMaskedImage, destToSrc, warpingControl) print( "%4d %5d %8.1f %6.1f, %6.1f %7.1f %10s %8d %6.2f" % (testNum, interpLength, scaleFac, offsetOrientDegLenArcsec[0], offsetOrientDegLenArcsec[1], rotAngDeg, kernelName, goodPix, dTime / float(nIter))) if SaveImages: destMaskedImage.writeFits( "warpedMaskedImage%03d.fits" % (testNum, )) testNum += 1
def testMtv(self): """Test basic image display""" exp = afwImage.ExposureF(self.fileName) self.display0.mtv(exp, title="parent")
def setUp(self): self.configAL = ipDiffim.ImagePsfMatchTask.ConfigClass() self.configAL.kernel.name = "AL" self.subconfigAL = self.configAL.kernel.active self.configDF = ipDiffim.ImagePsfMatchTask.ConfigClass() self.configDF.kernel.name = "DF" self.subconfigDF = self.configDF.kernel.active self.configDFr = ipDiffim.ImagePsfMatchTask.ConfigClass() self.configDFr.kernel.name = "DF" self.subconfigDFr = self.configDFr.kernel.active self.subconfigDF.useRegularization = False self.subconfigDFr.useRegularization = True self.subconfigDFr.lambdaValue = 1000.0 self.subconfigAL.fitForBackground = fitForBackground self.subconfigDF.fitForBackground = fitForBackground self.subconfigDFr.fitForBackground = fitForBackground self.subconfigAL.constantVarianceWeighting = constantVarianceWeighting self.subconfigDF.constantVarianceWeighting = constantVarianceWeighting self.subconfigDFr.constantVarianceWeighting = constantVarianceWeighting self.kListAL = ipDiffim.makeKernelBasisList(self.subconfigAL) self.kListDF = ipDiffim.makeKernelBasisList(self.subconfigDF) self.kListDFr = ipDiffim.makeKernelBasisList(self.subconfigDFr) self.hMatDFr = ipDiffim.makeRegularizationMatrix( pexConfig.makePolicy(self.subconfigDFr)) self.bskvAL = ipDiffim.BuildSingleKernelVisitorF( self.kListAL, pexConfig.makePolicy(self.subconfigAL)) self.bskvDF = ipDiffim.BuildSingleKernelVisitorF( self.kListDF, pexConfig.makePolicy(self.subconfigDF)) self.bskvDFr = ipDiffim.BuildSingleKernelVisitorF( self.kListDFr, pexConfig.makePolicy(self.subconfigDF), self.hMatDFr) defSciencePath = globals()['defSciencePath'] defTemplatePath = globals()['defTemplatePath'] if defSciencePath and defTemplatePath: self.scienceExposure = afwImage.ExposureF(defSciencePath) self.templateExposure = afwImage.ExposureF(defTemplatePath) else: defDataDir = lsst.utils.getPackageDir('afwdata') defSciencePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v26-e0", "v26-e0-c011-a00.sci.fits") defTemplatePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v5-e0", "v5-e0-c011-a00.sci.fits") self.scienceExposure = afwImage.ExposureF(defSciencePath) self.templateExposure = afwImage.ExposureF(defTemplatePath) warper = afwMath.Warper.fromConfig(self.subconfigAL.warpingConfig) self.templateExposure = warper.warpExposure( self.scienceExposure.getWcs(), self.templateExposure, destBBox=self.scienceExposure.getBBox()) # tmi = self.templateExposure.getMaskedImage() smi = self.scienceExposure.getMaskedImage() # Object detection detConfig = self.subconfigAL.detectionConfig detPolicy = pexConfig.makePolicy(detConfig) detPolicy.set("detThreshold", 50.) detPolicy.set("detThresholdType", "stdev") detPolicy.set("detOnTemplate", False) kcDetect = ipDiffim.KernelCandidateDetectionF(detPolicy) kcDetect.apply(tmi, smi) self.footprints = kcDetect.getFootprints()
def testPeakLikelihoodFlux(self): """Test measurement with PeakLikelihoodFlux.""" # make and measure a series of exposures containing just one star, approximately centered bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 101)) kernelWidth = 35 var = 100 fwhm = 3.0 sigma = fwhm / FwhmPerSigma convolutionControl = afwMath.ConvolutionControl() psf = afwDetection.GaussianPsf(kernelWidth, kernelWidth, sigma) psfKernel = psf.getLocalKernel() psfImage = psf.computeKernelImage() sumPsfSq = np.sum(psfImage.getArray()**2) psfSqArr = psfImage.getArray()**2 for flux in (1000, 10000): ctrInd = afwGeom.Point2I(50, 51) ctrPos = afwGeom.Point2D(ctrInd) kernelBBox = psfImage.getBBox() kernelBBox.shift(afwGeom.Extent2I(ctrInd)) # compute predicted flux error unshMImage = makeFakeImage(bbox, [ctrPos], [flux], fwhm, var) # filter image by PSF unshFiltMImage = afwImage.MaskedImageF(unshMImage.getBBox()) afwMath.convolve(unshFiltMImage, unshMImage, psfKernel, convolutionControl) # compute predicted flux = value of image at peak / sum(PSF^2) # this is a sanity check of the algorithm, as much as anything predFlux = unshFiltMImage.getImage().get(ctrInd[0], ctrInd[1]) / sumPsfSq self.assertLess(abs(flux - predFlux), flux * 0.01) # compute predicted flux error based on filtered pixels # = sqrt(value of filtered variance at peak / sum(PSF^2)^2) predFluxErr = math.sqrt(unshFiltMImage.getVariance().get( ctrInd[0], ctrInd[1])) / sumPsfSq # compute predicted flux error based on unfiltered pixels # = sqrt(sum(unfiltered variance * PSF^2)) / sum(PSF^2) # and compare to that derived from filtered pixels; # again, this is a test of the algorithm varView = afwImage.ImageF(unshMImage.getVariance(), kernelBBox) varArr = varView.getArray() unfiltPredFluxErr = math.sqrt(np.sum(varArr * psfSqArr)) / sumPsfSq self.assertLess(abs(unfiltPredFluxErr - predFluxErr), predFluxErr * 0.01) for fracOffset in (afwGeom.Extent2D(0, 0), afwGeom.Extent2D(0.2, -0.3)): adjCenter = ctrPos + fracOffset if fracOffset == afwGeom.Extent2D(0, 0): maskedImage = unshMImage filteredImage = unshFiltMImage else: maskedImage = makeFakeImage(bbox, [adjCenter], [flux], fwhm, var) # filter image by PSF filteredImage = afwImage.MaskedImageF( maskedImage.getBBox()) afwMath.convolve(filteredImage, maskedImage, psfKernel, convolutionControl) exp = afwImage.makeExposure(filteredImage) exp.setPsf(psf) control = measBase.PeakLikelihoodFluxControl() plugin, cat = makePluginAndCat( measBase.PeakLikelihoodFluxAlgorithm, "test", control, centroid="centroid") source = cat.makeRecord() source.set("centroid_x", adjCenter.getX()) source.set("centroid_y", adjCenter.getY()) plugin.measure(source, exp) measFlux = source.get("test_flux") measFluxErr = source.get("test_fluxSigma") self.assertLess(abs(measFlux - flux), flux * 0.003) self.assertLess(abs(measFluxErr - predFluxErr), predFluxErr * 0.2) # try nearby points and verify that the flux is smaller; # this checks that the sub-pixel shift is performed in the correct direction for dx in (-0.2, 0, 0.2): for dy in (-0.2, 0, 0.2): if dx == dy == 0: continue offsetCtr = afwGeom.Point2D(adjCenter[0] + dx, adjCenter[1] + dy) source = cat.makeRecord() source.set("centroid_x", offsetCtr.getX()) source.set("centroid_y", offsetCtr.getY()) plugin.measure(source, exp) self.assertLess(source.get("test_flux"), measFlux) # source so near edge of image that PSF does not overlap exposure should result in failure for edgePos in ( (1, 50), (50, 1), (50, bbox.getHeight() - 1), (bbox.getWidth() - 1, 50), ): source = cat.makeRecord() source.set("centroid_x", edgePos[0]) source.set("centroid_y", edgePos[1]) with self.assertRaises(lsst.pex.exceptions.RangeError): plugin.measure(source, exp) # no PSF should result in failure: flags set noPsfExposure = afwImage.ExposureF(filteredImage) source = cat.makeRecord() source.set("centroid_x", edgePos[0]) source.set("centroid_y", edgePos[1]) with self.assertRaises(lsst.pex.exceptions.InvalidParameterError): plugin.measure(source, noPsfExposure)
def assembleCcd(self, assembleInput): """!Assemble a set of amps into a single CCD size image @param[in] assembleInput -- Either a dictionary of amp lsst.afw.image.Exposures or a single lsst.afw.image.Exposure containing all raw amps. If a dictionary of amp exposures, the key should be the amp name. @return assembledCcd -- An lsst.afw.image.Exposure of the assembled amp sections. @throws TypeError with the following string: <DL> <DT> Expected either a dictionary of amp exposures or a single raw exposure <DD> The input exposures to be assembled do not adhere to the required format. </DL> @throws RuntimeError with the following string: <DL> <DT> No ccd detector found <DD> The detector set on the input exposure is not set. </DL> """ ccd = None if isinstance(assembleInput, dict): # assembleInput is a dictionary of amp name: amp exposure # Assume all amps have the same detector, so get the detector from an arbitrary amp ccd = next(iter(assembleInput.values())).getDetector() def getNextExposure(amp): return assembleInput[amp.getName()] elif hasattr(assembleInput, "getMaskedImage"): # assembleInput is a single exposure ccd = assembleInput.getDetector() def getNextExposure(amp): return assembleInput else: raise TypeError( "Expected either a dictionary of amp exposures or a single raw exposure" ) if ccd is None: raise RuntimeError("No ccd detector found") if not self.config.doTrim: outBox = cameraGeomUtils.calcRawCcdBBox(ccd) else: outBox = ccd.getBBox() outExposure = afwImage.ExposureF(outBox) outMI = outExposure.getMaskedImage() if self.config.doTrim: assemble = cameraGeom.assembleAmplifierImage else: assemble = cameraGeom.assembleAmplifierRawImage for amp in ccd: inMI = getNextExposure(amp).getMaskedImage() assemble(outMI, inMI, amp) # # If we are returning an "untrimmed" image (with overscans and extended register) we # need to update the ampInfo table in the Detector as we've moved the amp images into # place in a single Detector image # if not self.config.doTrim: ccd = cameraGeom.makeUpdatedDetector(ccd) outExposure.setDetector(ccd) self.postprocessExposure(outExposure=outExposure, inExposure=getNextExposure(ccd[0])) return outExposure
def getSkyMap(center_coord, width, height, filter, units, source, map_type): """Merge multiple patches from a SkyMap into a single image. This function takes advantage of the fact that all tracts in a SkyMap share the same WCS and should have identical pixels where they overlap. @center_coord: base coordinate of the box RA and Dec (minimum values, lower left corner) @width: in Pixel @height: in Pixels @filter: valid filter for the data set such as 'i', 'r', 'g' @units: 'pixel' or 'arcsecond' (defaults to 'pixel') @source: source for Butler, such as "/lsst7/releaseW13EP" @map_type: type of SkyMap, such as "deepCoadd_skyMap" """ # Get the basic SkyMap information butler = lsst.daf.persistence.Butler(source) sky_map = butler.get(map_type) dest_tract_info = sky_map.findTract(center_coord) dest_wcs = dest_tract_info.getWcs() # Determine target area. if units != 'arcsecond' and units != 'pixel': units = 'pixel' dest_bbox = _bbox_for_coords(dest_wcs, center_coord, width, height, units) dest_corner_coords = [ dest_wcs.pixelToSky(pixPos) for pixPos in afw_geom.Box2D(dest_bbox).getCorners() ] # Collect patches of the SkyMap that are in the target region. # Create source exposures from the patches within each tract # as all patches from a tract share a WCS. exposure_list = [] tract_patch_list = sky_map.findTractPatchList(dest_corner_coords) for j, tract_patch in enumerate(tract_patch_list): tract_info = tract_patch[0] patch_list = tract_patch[1] log.info("tract_info[{}]={}".format(j, tract_info)) log.info("patch_list[{}]={}".format(j, patch_list)) src_wcs = tract_info.getWcs() src_bbox = afw_geom.Box2I() for patch_info in patch_list: src_bbox.include(patch_info.getOuterBBox()) src_exposure = afw_image.ExposureF(src_bbox, src_wcs) # blank, so far exposure_list.append(src_exposure) # load srcExposures with patches tract_id = tract_info.getId() for patch_info in patch_list: patch_index = patch_info.getIndex() patch_index_str = ','.join(str(i) for i in patch_index) log.info("butler.get dataId=filter:{}, tract:{}, " "patch:{}".format(filter, tract_id, patch_index_str)) patch_exposure = butler.get("deepCoadd", dataId={ "filter": filter, "tract": tract_id, "patch": patch_index_str }) src_view = afw_image.ExposureF(src_exposure, patch_exposure.getBBox()) src_view_img = src_view.getMaskedImage() patch_img = patch_exposure.getMaskedImage() src_view_img[:] = patch_img # Copy the pixels from the source exposures to the destination exposures. dest_exposure_list = [] for j, src_exposure in enumerate(exposure_list): src_image = src_exposure.getMaskedImage() src_wcs = src_exposure.getWcs() if j == 0: expo_bbox = dest_bbox # dest_bbox only correct for first image else: # Determine the correct BBox (in pixels) for the current src_wcs ll_corner = afw_geom.Point2I( src_wcs.skyToPixel(dest_corner_coords[0])) ur_corner = afw_geom.Point2I( src_wcs.skyToPixel(dest_corner_coords[2])) # Handle negative values for in expo_bbox. if ll_corner.getX() < 0: ll_corner.setX(0) if ll_corner.getY() < 0: ll_corner.setY(0) if ur_corner.getX() < 0: ur_corner.setX(0) log.warn("getSkyMap negative X for ur_corner") if ur_corner.getY() < 0: ur_corner.setY(0) log.warn("getSkyMap negative Y for ur_corner") expo_bbox = afw_geom.Box2I(ll_corner, ur_corner) log.info("j={} expo_bbox={} sBBox={}".format(j, expo_bbox, src_exposure.getBBox())) dest_exposure = afw_image.ExposureF(expo_bbox, src_wcs) dest_img = dest_exposure.getMaskedImage() begin_x = expo_bbox.getBeginX() - src_image.getX0() end_x = expo_bbox.getEndX() - src_image.getX0() begin_y = expo_bbox.getBeginY() - src_image.getY0() end_y = expo_bbox.getEndY() - src_image.getY0() new_width = src_exposure.getBBox().getEndX() - expo_bbox.getBeginX() new_height = src_exposure.getBBox().getEndY() - expo_bbox.getBeginY() # Do a final check to make sure that the we're not going past the end of src_image. src_img_len_x = src_image.getWidth() if end_x > src_img_len_x: new_width = src_img_len_x - begin_x end_x = src_img_len_x s_img_len_y = src_image.getHeight() if end_y > s_img_len_y: new_width = s_img_len_y - begin_y end_y = s_img_len_y log.debug("begin_x={} end_x={}".format(begin_x, end_x)) log.debug("new_width{} = sBBox.EndX{} - sBBox.BeginX{}".format( new_width, src_exposure.getBBox().getEndX(), expo_bbox.getBeginX())) log.debug("begin_y={} end_y={}".format(begin_y, end_y)) log.debug("new_height{} = sBBox.EndY{} - sBBox.BeginY{}".format( new_height, src_exposure.getBBox().getEndY(), expo_bbox.getBeginY())) dest_img[0:new_width, 0:new_height] = src_image[begin_x:end_x, begin_y:end_y] dest_exposure_list.append(dest_exposure) # If there's only one exposure in the list (and there usually is) just return it. if len(dest_exposure_list) == 1: return dest_exposure_list[0] # Need to stitch together the multiple destination exposures. log.debug("getSkyMap stitching together multiple destExposures") warper_config = afw_math.WarperConfig() warper = afw_math.Warper.fromConfig(warper_config) stitched_exposure = stitch_exposures_good_pixel_copy( dest_wcs, dest_bbox, dest_exposure_list, warper) return stitched_exposure
def runModelType(self, fitForBackground): self.subconfig.fitForBackground = fitForBackground templateSubImage = afwImage.ExposureF(self.templateImage, self.bbox) scienceSubImage = afwImage.ExposureF(self.scienceImage, self.bbox) self.subconfig.spatialModelType = 'chebyshev1' psfmatch1 = ipDiffim.ImagePsfMatchTask(config=self.config) results1 = psfmatch1.subtractExposures(templateSubImage, scienceSubImage, doWarping=True) spatialKernel1 = results1.psfMatchingKernel backgroundModel1 = results1.backgroundModel self.subconfig.spatialModelType = 'polynomial' psfmatch2 = ipDiffim.ImagePsfMatchTask(config=self.config) results2 = psfmatch2.subtractExposures(templateSubImage, scienceSubImage, doWarping=True) spatialKernel2 = results2.psfMatchingKernel backgroundModel2 = results2.backgroundModel # Got the types right? self.assertTrue(spatialKernel1.getSpatialFunctionList() [0].toString().startswith('Chebyshev1Function2')) self.assertTrue(spatialKernel2.getSpatialFunctionList() [0].toString().startswith('PolynomialFunction2')) # First order term has zero spatial variation and sum = kernel sum kp1par0 = spatialKernel1.getSpatialFunctionList()[0].getParameters() kp2par0 = spatialKernel2.getSpatialFunctionList()[0].getParameters() self.assertAlmostEqual(kp1par0[0], kp2par0[0], delta=1e-5) for i in range(1, len(kp1par0)): self.assertAlmostEqual(kp1par0[i], 0.0, delta=1e-5) self.assertAlmostEqual(kp1par0[i], kp2par0[i], delta=1e-5) if fitForBackground: # Nterms (zeroth order model) self.assertEqual(backgroundModel1.getNParameters(), 1) self.assertEqual(backgroundModel2.getNParameters(), 1) # Same value of function coefficients (different to 0.001 level) self.assertAlmostEqual(backgroundModel1.getParameters()[0], backgroundModel2.getParameters()[0], delta=1e-3) # Functions evaluate to same value at origin (0.001 difference) self.assertAlmostEqual(backgroundModel1(0, 0), backgroundModel2(0, 0), delta=1e-3) # At at different location within image self.assertAlmostEqual(backgroundModel1(10, 10), backgroundModel2(10, 10), delta=1e-3) else: # More improtant is the kernel needs to be then same when realized at a coordinate kim1 = afwImage.ImageD(spatialKernel1.getDimensions()) kim2 = afwImage.ImageD(spatialKernel2.getDimensions()) ksum1 = spatialKernel1.computeImage(kim1, False, 0.0, 0.0) ksum2 = spatialKernel2.computeImage(kim2, False, 0.0, 0.0) self.assertAlmostEqual(ksum1, ksum2, delta=1e-5) for y in range(kim1.getHeight()): for x in range(kim1.getHeight()): self.assertAlmostEqual(kim1[x, y, afwImage.LOCAL], kim2[x, y, afwImage.LOCAL], delta=1e-1) # Nterms (zeroth order) self.assertEqual(backgroundModel1.getNParameters(), 1) self.assertEqual(backgroundModel2.getNParameters(), 1) # Zero value in function self.assertAlmostEqual(backgroundModel1.getParameters()[0], 0.0, delta=1e-7) self.assertAlmostEqual(backgroundModel2.getParameters()[0], 0.0, delta=1e-7) # Function evaluates to zero self.assertAlmostEqual(backgroundModel1(0, 0), 0.0, delta=1e-7) self.assertAlmostEqual(backgroundModel2(0, 0), 0.0, delta=1e-7) # Spatially... self.assertAlmostEqual(backgroundModel1(10, 10), 0.0, delta=1e-7) self.assertAlmostEqual(backgroundModel2(10, 10), 0.0, delta=1e-7)
def testArchiveImports(self): # This file was saved with a Psf defined in testTableArchivesLib, so we'll only be able # to load it if the module-importer mechanism works. filename = os.path.join(testPath, "data", "archiveImportTest.fits") exposure = afwImage.ExposureF(filename) self.assertIsNotNone(exposure.getPsf())
def warpAndCoadd(coaddPath, exposureListPath, config): """Create a coadd by warping and psf-matching Inputs: - coaddPath: path to desired coadd; ovewritten if it exists - exposureListPath: a file containing a list of paths to input exposures; blank lines and lines that start with # are ignored - config: an instance of WarpAndCoaddConfig The first exposure in exposureListPath is used as the reference: all other exposures are warped to match to it. """ weightPath = os.path.splitext(coaddPath)[0] + "_weight.fits" bbox = afwGeom.Box2I( afwGeom.Point2I(config.bboxMin[0], config.bboxMin[1]), afwGeom.Extent2I(config.bboxSize[0], config.bboxSize[1]), ) print("SaveDebugImages =", config.saveDebugImages) print("bbox =", bbox) # process exposures accumGoodTime = 0 coadd = None expNum = 0 numExposuresInCoadd = 0 numExposuresFailed = 0 with file(exposureListPath, "rU") as infile: for exposurePath in infile: exposurePath = exposurePath.strip() if not exposurePath or exposurePath.startswith("#"): continue expNum += 1 try: print("Processing exposure: %s" % (exposurePath,), file=sys.stderr) startTime = time.time() exposure = afwImage.ExposureF(exposurePath, 0, bbox, afwImage.LOCAL) if config.saveDebugImages: exposure.writeFits("exposure%s.fits" % (expNum,)) if not coadd: print("Create warper and coadd with size and WCS matching the first/reference exposure", file=sys.stderr) warper = afwMath.Warper.fromConfig(config.warp) coadd = coaddChiSq.Coadd.fromConfig( bbox=exposure.getBBox(), wcs=exposure.getWcs(), config=config.coadd) print("badPixelMask=", coadd.getBadPixelMask()) print("Add reference exposure to coadd (without warping)", file=sys.stderr) coadd.addExposure(exposure) else: print("Warp exposure", file=sys.stderr) warpedExposure = warper.warpExposure( destWcs=coadd.getWcs(), srcExposure=exposure, maxBBox=coadd.getBBox(), ) if config.saveDebugImages: warpedExposure.writeFits("warped%s.fits" % (expNum,)) print("Add warped exposure to coadd", file=sys.stderr) coadd.addExposure(warpedExposure) # ignore time for first exposure since nothing happens to it deltaTime = time.time() - startTime print("Elapsed time for processing exposure: %0.1f sec" % (deltaTime,), file=sys.stderr) accumGoodTime += deltaTime numExposuresInCoadd += 1 except Exception as e: print("Exposure %s failed: %s" % (exposurePath, e), file=sys.stderr) traceback.print_exc(file=sys.stderr) numExposuresFailed += 1 continue coaddExposure = coadd.getCoadd() coaddExposure.writeFits(coaddPath) print("Wrote coadd: %s" % (coaddPath,), file=sys.stderr) weightMap = coadd.getWeightMap() weightMap.writeFits(weightPath) print("Wrote weightMap: %s" % (weightPath,), file=sys.stderr) print("Coadded %d exposures and failed %d" % (numExposuresInCoadd, numExposuresFailed), file=sys.stderr) if numExposuresInCoadd > 1: timePerGoodExposure = accumGoodTime / float(numExposuresInCoadd - 1) print("Processing speed: %.1f seconds/exposure (ignoring first and failed)" % (timePerGoodExposure,), file=sys.stderr)
def setUp(self): self.calexpOrig = afwImage.ExposureF( os.path.join(DATA_DIR, "ticket1738.fits")) self.calexp = afwImage.ExposureF( os.path.join(DATA_DIR, "ticket1738.fits"))
def run(self, exposure, referencePsfModel, kernelSum=1.0): """!Psf-match an exposure to a model Psf @param exposure: Exposure to Psf-match to the reference Psf model; it must return a valid PSF model via exposure.getPsf() @param referencePsfModel: The Psf model to match to (an lsst.afw.detection.Psf) @param kernelSum: A multipicative factor to apply to the kernel sum (default=1.0) @return - psfMatchedExposure: the Psf-matched Exposure. This has the same parent bbox, Wcs, Calib and Filter as the input Exposure but no Psf. In theory the Psf should equal referencePsfModel but the match is likely not exact. - psfMatchingKernel: the spatially varying Psf-matching kernel - kernelCellSet: SpatialCellSet used to solve for the Psf-matching kernel Raise a RuntimeError if the Exposure does not contain a Psf model """ if not exposure.hasPsf(): raise RuntimeError("exposure does not contain a Psf model") maskedImage = exposure.getMaskedImage() self.log.log(pexLog.Log.INFO, "compute Psf-matching kernel") kernelCellSet = self._buildCellSet(exposure, referencePsfModel) width, height = referencePsfModel.getLocalKernel().getDimensions() psfAttr1 = measAlg.PsfAttributes(exposure.getPsf(), width // 2, height // 2) psfAttr2 = measAlg.PsfAttributes(referencePsfModel, width // 2, height // 2) s1 = psfAttr1.computeGaussianWidth( psfAttr1.ADAPTIVE_MOMENT) # gaussian sigma in pixels s2 = psfAttr2.computeGaussianWidth( psfAttr2.ADAPTIVE_MOMENT) # gaussian sigma in pixels fwhm1 = s1 * sigma2fwhm # science Psf fwhm2 = s2 * sigma2fwhm # template Psf basisList = makeKernelBasisList(self.kConfig, fwhm1, fwhm2, metadata=self.metadata) spatialSolution, psfMatchingKernel, backgroundModel = self._solve( kernelCellSet, basisList) if psfMatchingKernel.isSpatiallyVarying(): sParameters = num.array(psfMatchingKernel.getSpatialParameters()) sParameters[0][0] = kernelSum psfMatchingKernel.setSpatialParameters(sParameters) else: kParameters = num.array(psfMatchingKernel.getKernelParameters()) kParameters[0] = kernelSum psfMatchingKernel.setKernelParameters(kParameters) self.log.log(pexLog.Log.INFO, "Psf-match science exposure to reference") psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs()) psfMatchedExposure.setFilter(exposure.getFilter()) psfMatchedExposure.setCalib(exposure.getCalib()) psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage() # Normalize the psf-matching kernel while convolving since its magnitude is meaningless # when PSF-matching one model to another. doNormalize = True afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, doNormalize) self.log.log(pexLog.Log.INFO, "done") return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure, psfMatchingKernel=psfMatchingKernel, kernelCellSet=kernelCellSet, metadata=self.metadata)
def run(self, snap0, snap1, defects=None): """Combine two snaps @param[in] snap0: snapshot exposure 0 @param[in] snap1: snapshot exposure 1 @defects[in] defect list (for repair task) @return a pipe_base Struct with fields: - exposure: snap-combined exposure - sources: detected sources, or None if detection not performed """ # initialize optional outputs sources = None if self.config.doRepair: self.log.info("snapCombine repair") psf = self.makeInitialPsf(snap0, fwhmPix=self.config.repairPsfFwhm) snap0.setPsf(psf) snap1.setPsf(psf) self.repair.run(snap0, defects=defects, keepCRs=False) self.repair.run(snap1, defects=defects, keepCRs=False) repair0frame = getDebugFrame(self._display, "repair0") if repair0frame: getDisplay(repair0frame).mtv(snap0) repair1frame = getDebugFrame(self._display, "repair1") if repair1frame: getDisplay(repair1frame).mtv(snap1) if self.config.doDiffIm: if self.config.doPsfMatch: self.log.info("snapCombine psfMatch") diffRet = self.diffim.run(snap0, snap1, "subtractExposures") diffExp = diffRet.subtractedImage # Measure centroid and width of kernel; dependent on ticket #1980 # Useful diagnostic for the degree of astrometric shift between snaps. diffKern = diffRet.psfMatchingKernel width, height = diffKern.getDimensions() # TBD... #psfAttr = measAlg.PsfAttributes(diffKern, width//2, height//2) else: diffExp = afwImage.ExposureF(snap0, True) diffMi = diffExp.getMaskedImage() diffMi -= snap1.getMaskedImage() psf = self.makeInitialPsf(snap0) diffExp.setPsf(psf) table = afwTable.SourceTable.make(self.schema) table.setMetadata(self.algMetadata) detRet = self.detection.makeSourceCatalog(table, diffExp) sources = detRet.sources fpSets = detRet.fpSets if self.config.doMeasurement: self.measurement.measure(diffExp, sources) mask0 = snap0.getMaskedImage().getMask() mask1 = snap1.getMaskedImage().getMask() fpSets.positive.setMask(mask0, "DETECTED") fpSets.negative.setMask(mask1, "DETECTED") maskD = diffExp.getMaskedImage().getMask() fpSets.positive.setMask(maskD, "DETECTED") fpSets.negative.setMask(maskD, "DETECTED_NEGATIVE") combinedExp = self.addSnaps(snap0, snap1) return pipeBase.Struct( exposure=combinedExp, sources=sources, )
def plotPixelResiduals(exposure, warpedTemplateExposure, diffExposure, kernelCellSet, kernel, background, testSources, config, origVariance = False, nptsFull = 1e6, keepPlots = True, titleFs=14): """Plot diffim residuals for LOCAL and SPATIAL models""" candidateResids = [] spatialResids = [] nonfitResids = [] for cell in kernelCellSet.getCellList(): for cand in cell.begin(True): # only look at good ones # Be sure if not (cand.getStatus() == afwMath.SpatialCellCandidate.GOOD): continue cand = diffimLib.cast_KernelCandidateF(cand) diffim = cand.getDifferenceImage(diffimLib.KernelCandidateF.ORIG) orig = cand.getScienceMaskedImage() ski = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(ski, False, int(cand.getXCenter()), int(cand.getYCenter())) sk = afwMath.FixedKernel(ski) sbg = background(int(cand.getXCenter()), int(cand.getYCenter())) sdiffim = cand.getDifferenceImage(sk, sbg) # trim edgs due to convolution bbox = kernel.shrinkBBox(diffim.getBBox()) tdiffim = diffim.Factory(diffim, bbox) torig = orig.Factory(orig, bbox) tsdiffim = sdiffim.Factory(sdiffim, bbox) if origVariance: candidateResids.append(np.ravel(tdiffim.getImage().getArray() / np.sqrt(torig.getVariance().getArray()))) spatialResids.append(np.ravel(tsdiffim.getImage().getArray() / np.sqrt(torig.getVariance().getArray()))) else: candidateResids.append(np.ravel(tdiffim.getImage().getArray() / np.sqrt(tdiffim.getVariance().getArray()))) spatialResids.append(np.ravel(tsdiffim.getImage().getArray() / np.sqrt(tsdiffim.getVariance().getArray()))) fullIm = diffExposure.getMaskedImage().getImage().getArray() fullMask = diffExposure.getMaskedImage().getMask().getArray() if origVariance: fullVar = exposure.getMaskedImage().getVariance().getArray() else: fullVar = diffExposure.getMaskedImage().getVariance().getArray() bitmaskBad = 0 bitmaskBad |= afwImage.MaskU.getPlaneBitMask('NO_DATA') bitmaskBad |= afwImage.MaskU.getPlaneBitMask('SAT') idx = np.where((fullMask & bitmaskBad) == 0) stride = int(len(idx[0]) // nptsFull) sidx = idx[0][::stride], idx[1][::stride] allResids = fullIm[sidx] / np.sqrt(fullVar[sidx]) testFootprints = diffimTools.sourceToFootprintList(testSources, warpedTemplateExposure, exposure, config, pexLog.getDefaultLog()) for fp in testFootprints: subexp = diffExposure.Factory(diffExposure, fp["footprint"].getBBox()) subim = subexp.getMaskedImage().getImage() if origVariance: subvar = afwImage.ExposureF(exposure, fp["footprint"].getBBox()).getMaskedImage().getVariance() else: subvar = subexp.getMaskedImage().getVariance() nonfitResids.append(np.ravel(subim.getArray() / np.sqrt(subvar.getArray()))) candidateResids = np.ravel(np.array(candidateResids)) spatialResids = np.ravel(np.array(spatialResids)) nonfitResids = np.ravel(np.array(nonfitResids)) try: import pylab from matplotlib.font_manager import FontProperties except ImportError, e: print "Unable to import pylab: %s" % e return
def run(self, exposure, referencePsfModel, kernelSum=1.0): """Psf-match an exposure to a model Psf Parameters ---------- exposure : `lsst.afw.image.Exposure` Exposure to Psf-match to the reference Psf model; it must return a valid PSF model via exposure.getPsf() referencePsfModel : `lsst.afw.detection.Psf` The Psf model to match to kernelSum : `float`, optional A multipicative factor to apply to the kernel sum (default=1.0) Returns ------- result : `struct` - ``psfMatchedExposure`` : the Psf-matched Exposure. This has the same parent bbox, Wcs, PhotoCalib and Filter as the input Exposure but no Psf. In theory the Psf should equal referencePsfModel but the match is likely not exact. - ``psfMatchingKernel`` : the spatially varying Psf-matching kernel - ``kernelCellSet`` : SpatialCellSet used to solve for the Psf-matching kernel - ``referencePsfModel`` : Validated and/or modified reference model used Raises ------ RuntimeError if the Exposure does not contain a Psf model """ if not exposure.hasPsf(): raise RuntimeError("exposure does not contain a Psf model") maskedImage = exposure.getMaskedImage() self.log.info("compute Psf-matching kernel") result = self._buildCellSet(exposure, referencePsfModel) kernelCellSet = result.kernelCellSet referencePsfModel = result.referencePsfModel fwhmScience = exposure.getPsf().computeShape().getDeterminantRadius()*sigma2fwhm fwhmModel = referencePsfModel.computeShape().getDeterminantRadius()*sigma2fwhm basisList = makeKernelBasisList(self.kConfig, fwhmScience, fwhmModel, metadata=self.metadata) spatialSolution, psfMatchingKernel, backgroundModel = self._solve(kernelCellSet, basisList) if psfMatchingKernel.isSpatiallyVarying(): sParameters = np.array(psfMatchingKernel.getSpatialParameters()) sParameters[0][0] = kernelSum psfMatchingKernel.setSpatialParameters(sParameters) else: kParameters = np.array(psfMatchingKernel.getKernelParameters()) kParameters[0] = kernelSum psfMatchingKernel.setKernelParameters(kParameters) self.log.info("Psf-match science exposure to reference") psfMatchedExposure = afwImage.ExposureF(exposure.getBBox(), exposure.getWcs()) psfMatchedExposure.setFilter(exposure.getFilter()) psfMatchedExposure.setPhotoCalib(exposure.getPhotoCalib()) psfMatchedExposure.getInfo().setVisitInfo(exposure.getInfo().getVisitInfo()) psfMatchedExposure.setPsf(referencePsfModel) psfMatchedMaskedImage = psfMatchedExposure.getMaskedImage() # Normalize the psf-matching kernel while convolving since its magnitude is meaningless # when PSF-matching one model to another. convolutionControl = afwMath.ConvolutionControl() convolutionControl.setDoNormalize(True) afwMath.convolve(psfMatchedMaskedImage, maskedImage, psfMatchingKernel, convolutionControl) self.log.info("done") return pipeBase.Struct(psfMatchedExposure=psfMatchedExposure, psfMatchingKernel=psfMatchingKernel, kernelCellSet=kernelCellSet, metadata=self.metadata, )
table = afwTable.SourceTable.make(schema) lsst_images = {} for filter_ in filter_names: lsst_images[filter_] = afwImage.ImageF('%s/image_%s.fits' % (output_dir, filter_)) # Run only detection on each filter detections = {} exposures = {} for filter_ in filter_names: print 'detecting in ', filter_ lsst_image = lsst_images[filter_] exposure = afwImage.ExposureF(lsst_image.getBBox(afwImage.PARENT)) exposure.getMaskedImage().getImage().getArray( )[:, :] = lsst_image.getArray() exposure.getMaskedImage().getVariance().set(noise_sigma**2) exposure.setPsf(kernelPsf) exposure.setWcs(wcs) exposure.setCalib(calib) exposures[filter_] = exposure result = detectTask.makeSourceCatalog(table, exposure) detections[filter_] = result.sources result.sources.writeFits('%s/det_%s.fits' % (args.output_dir, filter_)) # merge detection lists together merged = afwDet.FootprintMergeList(schema, [filter_ for filter_ in filter_names])
variance = %0.1f """ % (coaddPath, numImages, config.imageShape, config.imageSigma, config.variance)) np.random.seed(0) coadd = None for imInd in range(numImages): print("Create exposure %d" % (imInd, ), file=sys.stderr) maskedImage = afwTestUtils.makeGaussianNoiseMaskedImage( dimensions=config.imageShape, sigma=config.imageSigma, variance=config.variance) # the WCS doesn't matter; the default will do wcs = afwImage.Wcs() exposure = afwImage.ExposureF(maskedImage, wcs) if not coadd: print("Create coadd", file=sys.stderr) coadd = coaddChiSq.Coadd.fromConfig(bbox=exposure.getBBox(), wcs=exposure.getWcs(), config=config.coadd) print("badPixelMask=", coadd.getBadPixelMask(), file=sys.stderr) coadd.addExposure(exposure) print("Save weight map as %s" % (weightPath, ), file=sys.stderr) weightMap = coadd.getWeightMap() weightMap.writeFits(weightPath) coaddExposure = coadd.getCoadd() print("Save coadd as %s" % (coaddPath, ), file=sys.stderr)
def readImage(self, image): exp = afwImage.ExposureF(image) self.log.info("Read %dx%d image" % (exp.getWidth(), exp.getHeight())) return exp
def subtractExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True): """Register, Psf-match and subtract two Exposures. Do the following, in order: - Warp templateExposure to match scienceExposure, if their WCSs do not already match - Determine a PSF matching kernel and differential background model that matches templateExposure to scienceExposure - PSF-match templateExposure to scienceExposure - Compute subtracted exposure (see return values for equation). Parameters ---------- templateExposure : `lsst.afw.image.Exposure` Exposure to PSF-match to scienceExposure scienceExposure : `lsst.afw.image.Exposure` Reference Exposure templateFwhmPix : `float` FWHM (in pixels) of the Psf in the template image (image to convolve) scienceFwhmPix : `float` FWHM (in pixels) of the Psf in the science image candidateList : `list`, optional A list of footprints/maskedImages for kernel candidates; if `None` then source detection is run. - Currently supported: list of Footprints or measAlg.PsfCandidateF doWarping : `bool` What to do if ``templateExposure``` and ``scienceExposure`` WCSs do not match: - if `True` then warp ``templateExposure`` to match ``scienceExposure`` - if `False` then raise an Exception convolveTemplate : `bool` Convolve the template image or the science image - if `True`, ``templateExposure`` is warped if doWarping, ``templateExposure`` is convolved - if `False`, ``templateExposure`` is warped if doWarping, ``scienceExposure is`` convolved Returns ------- result : `lsst.pipe.base.Struct` An `lsst.pipe.base.Struct` containing these fields: - ``subtractedExposure`` : subtracted Exposure scienceExposure - (matchedImage + backgroundModel) - ``matchedImage`` : ``templateExposure`` after warping to match ``templateExposure`` (if doWarping true), and convolving with psfMatchingKernel - ``psfMatchingKernel`` : PSF matching kernel - ``backgroundModel`` : differential background model - ``kernelCellSet`` : SpatialCellSet used to determine PSF matching kernel """ results = self.matchExposures( templateExposure=templateExposure, scienceExposure=scienceExposure, templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix, candidateList=candidateList, doWarping=doWarping, convolveTemplate=convolveTemplate ) subtractedExposure = afwImage.ExposureF(scienceExposure, True) if convolveTemplate: subtractedMaskedImage = subtractedExposure.getMaskedImage() subtractedMaskedImage -= results.matchedExposure.getMaskedImage() subtractedMaskedImage -= results.backgroundModel else: subtractedExposure.setMaskedImage(results.warpedExposure.getMaskedImage()) subtractedMaskedImage = subtractedExposure.getMaskedImage() subtractedMaskedImage -= results.matchedExposure.getMaskedImage() subtractedMaskedImage -= results.backgroundModel # Preserve polarity of differences subtractedMaskedImage *= -1 # Place back on native photometric scale subtractedMaskedImage /= results.psfMatchingKernel.computeImage( afwImage.ImageD(results.psfMatchingKernel.getDimensions()), False) import lsstDebug display = lsstDebug.Info(__name__).display displayDiffIm = lsstDebug.Info(__name__).displayDiffIm maskTransparency = lsstDebug.Info(__name__).maskTransparency if not maskTransparency: maskTransparency = 0 if display: afwDisplay.setDefaultMaskTransparency(maskTransparency) if display and displayDiffIm: disp = afwDisplay.Display(frame=lsstDebug.frame) disp.mtv(templateExposure, title="Template") lsstDebug.frame += 1 disp = afwDisplay.Display(frame=lsstDebug.frame) disp.mtv(results.matchedExposure, title="Matched template") lsstDebug.frame += 1 disp = afwDisplay.Display(frame=lsstDebug.frame) disp.mtv(scienceExposure, title="Science Image") lsstDebug.frame += 1 disp = afwDisplay.Display(frame=lsstDebug.frame) disp.mtv(subtractedExposure, title="Difference Image") lsstDebug.frame += 1 results.subtractedExposure = subtractedExposure return results
def runXY0(self, poly, fitForBackground=False): self.subconfig.spatialModelType = poly self.subconfig.fitForBackground = fitForBackground templateSubImage = afwImage.ExposureF(self.templateImage.clone(), self.bbox) scienceSubImage = afwImage.ExposureF(self.scienceImage.clone(), self.bbox) # Have an XY0 psfmatch = ipDiffim.ImagePsfMatchTask(config=self.config) fwhm = psfmatch.getFwhmPix(self.psf) results1 = psfmatch.subtractExposures(templateSubImage, scienceSubImage, doWarping=True, templateFwhmPix=fwhm, scienceFwhmPix=fwhm) spatialKernel1 = results1.psfMatchingKernel backgroundModel1 = results1.backgroundModel kernelCellSet1 = results1.kernelCellSet # And then take away XY0 templateSubImage = afwImage.ExposureF(self.templateImage.clone(), self.bbox) scienceSubImage = afwImage.ExposureF(self.scienceImage.clone(), self.bbox) templateSubImage.setXY0(geom.Point2I(0, 0)) scienceSubImage.setXY0(geom.Point2I(0, 0)) results2 = psfmatch.subtractExposures(templateSubImage, scienceSubImage, doWarping=True, templateFwhmPix=fwhm, scienceFwhmPix=fwhm) spatialKernel2 = results2.psfMatchingKernel backgroundModel2 = results2.backgroundModel kernelCellSet2 = results2.kernelCellSet # need to count up the candidates first, since its a running tally count = 0 for cell in kernelCellSet1.getCellList(): for cand1 in cell.begin(False): count += 1 for cell in kernelCellSet1.getCellList(): for cand1 in cell.begin(False): if cand1.getStatus() == afwMath.SpatialCellCandidate.UNKNOWN: continue if cand1.getStatus() == afwMath.SpatialCellCandidate.BAD: continue cand2 = kernelCellSet2.getCandidateById(cand1.getId() + count) # positions are nearly the same (different at the 0.01 pixel level) self.assertAlmostEqual(cand1.getXCenter(), cand2.getXCenter(), delta=1e-1) self.assertAlmostEqual(cand1.getYCenter(), cand2.getYCenter() + self.offset, delta=1e-1) # kernels are the same im1 = cand1.getKernelImage(ipDiffim.KernelCandidateF.RECENT) im2 = cand2.getKernelImage(ipDiffim.KernelCandidateF.RECENT) for y in range(im1.getHeight()): for x in range(im1.getWidth()): self.assertAlmostEqual(im1[x, y, afwImage.LOCAL], im2[x, y, afwImage.LOCAL], delta=1e-7) # Spatial fits are the same skp1 = spatialKernel1.getSpatialParameters() skp2 = spatialKernel2.getSpatialParameters() bgp1 = backgroundModel1.getParameters() bgp2 = backgroundModel2.getParameters() # first term = kernel sum, 0, 0 self.assertAlmostEqual(skp1[0][0], skp2[0][0], delta=1e-6) # On other terms, the spatial terms are the same, the zpt terms are different for nk in range(1, len(skp1)): # Zeropoint if poly == 'polynomial': self.assertNotEqual(skp1[nk][0], skp2[nk][0]) elif poly == 'chebyshev1': # Cheby remaps coords, so model should be the same! self.assertAlmostEqual(skp1[nk][0], skp2[nk][0], delta=1e-4) else: self.fail() # Spatial terms for np in range(1, len(skp1[nk])): self.assertAlmostEqual(skp1[nk][np], skp2[nk][np], delta=1e-4) for np in range(len(bgp1)): self.assertAlmostEqual(bgp1[np], bgp2[np], delta=1e-4)
# We need to fit for a TAN-SIP x = np.arange(0, 1489 + stepSize, stepSize) y = np.arange(0, 2048 + stepSize, stepSize) coords = np.meshgrid(x, y) xs = np.ravel(coords[0]).astype(np.float) ys = np.ravel(coords[1]).astype(np.float) mapper = CoordinateMapper(node_rad, incl_rad, dRow0, dRow1, dRow2, dRow3, dCol0, dCol1, dCol2, dCol3, a, b, c, d, e, f) wcs = createWcs(xs, ys, mapper) if doValidate: validate(xs, ys, mapper, wcs) return wcs if __name__ == '__main__': infile = sys.argv[1] filt = sys.argv[2] camcol = int(sys.argv[3]) field = int(sys.argv[4]) wcs = convertasTrans(infile, filt, camcol, field, doValidate=True) if len(sys.argv) > 5: fpC = sys.argv[5] image = afwImage.ImageF(fpC) mi = afwImage.MaskedImageF(image) exp = afwImage.ExposureF(mi, wcs) exp.writeFits("/tmp/exp.fits")
def testSetPolygonIntersect(self): # Create a detector detector = DetectorWrapper().detector numPolygonPoints = 50 # Create an exposure with bounding box defined by detector exposure = afwImage.ExposureF(detector.getBBox()) exposure.setDetector(detector) pixelSizeMm = exposure.getDetector().getPixelSize()[0] pixX0 = exposure.getX0() pixY0 = exposure.getY0() pixX1 = pixX0 + exposure.getWidth() - 1 pixY1 = pixY0 + exposure.getHeight() - 1 fpCenter = exposure.getDetector().getCenter(FOCAL_PLANE) fpCenterX = fpCenter[0] fpCenterY = fpCenter[1] pixCenter = exposure.getDetector().getCenter(PIXELS) # 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 setValidPolygonCcdIntersect(exposure, fpPolygon) # Since the ccd is fully contained in the fpPolygon, the intersection # should be the ccdPolygon itself ccdPolygonPix = afwGeom.Polygon( exposure.getDetector().getCorners(PIXELS)) self.assertEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # Make a polygon that is entirely within, but smaller than, the ccd # (radius of 0.2*min of width/height) fpRadius = 0.2 * min(exposure.getWidth() * pixelSizeMm, exposure.getHeight() * pixelSizeMm) fpPolygon = makeCircularPolygon(fpCenterX, fpCenterY, fpRadius, numPolygonPoints) # Set the polygon that is the intersection of fpPolygon and ccd setValidPolygonCcdIntersect(exposure, fpPolygon) # all vertices of polygon should be contained within the ccd for x in exposure.getInfo().getValidPolygon(): self.assertTrue(ccdPolygonPix.contains(lsst.geom.Point2D(x))) # intersection is smaller than the ccd self.assertNotEqual(exposure.getInfo().getValidPolygon(), ccdPolygonPix) # make a simple square polygon that partly intersects the ccd, centered # at ccd center fpPolygonSize = max(exposure.getWidth() * pixelSizeMm, exposure.getHeight() * pixelSizeMm) fpPolygon = makeSquarePolygon(fpCenterX, fpCenterY, fpPolygonSize) setValidPolygonCcdIntersect(exposure, fpPolygon) # Check that the polygon contains the central pixel (offset by one to # actually be "contained") pixCenterPlusOne = lsst.geom.Point2D(pixCenter[0] + 1, pixCenter[1] + 1) self.assertTrue(exposure.getInfo().getValidPolygon().contains( lsst.geom.Point2D(pixCenterPlusOne))) # Check that the polygon contains the upper right ccd edge self.assertTrue(exposure.getInfo().getValidPolygon().contains( lsst.geom.Point2D(pixX1, pixY1)))
def runDataRef(self, sensorRefList, calibType): """Process a calibration frame. @param sensorRef: sensor-level butler data reference @return pipe_base Struct containing these fields: - masterExpList: amp exposures of master calibration products """ referenceAmps = sensorRefList[0].subItems(level="channel") masterExpList = [] dataIdList = [] expmeta = None for amp in referenceAmps: if amp.dataId['snap'] == 1: continue self.log.info("Amp: Processing %s", amp.dataId) print("dataid %s" % (amp.dataId)) butler = amp.butlerSubset.butler ampMIList = [] for sRef in sensorRefList: self.log.info("Sensor: Processing %s", sRef.dataId) ampSnapMIList = [] dataId = eval(amp.dataId.__repr__()) dataId['visit'] = sRef.dataId['visit'] for snap in (0, 1): dataId['snap'] = snap ampExposure = sRef.butlerSubset.butler.get('raw', dataId) if expmeta is None: expmeta = ampExposure.getMetadata() expfilter = ampExposure.getFilter() expPhotoCalib = ampExposure.getPhotoCalib() ampDetector = ampExposure.getDetector() ampExposure = self.convertIntToFloat(ampExposure) ampExpDataView = ampExposure.Factory(ampExposure, ampDetector.getDiskDataSec()) self.saturationDetection(ampExposure, ampDetector) self.overscanCorrection(ampExposure, ampDetector) if calibType in ('flat', 'dark'): self.biasCorrection(ampExpDataView, amp) if False: self.darkCorrection(ampExpDataView, amp) self.updateVariance(ampExpDataView, ampDetector) ampSnapMIList.append(ampExpDataView.getMaskedImage()) ampMIList.append(self.combineMIList(ampSnapMIList)) masterFrame = self.combineMIList(ampMIList) # Fix saturation too??? self.fixDefectsAndSat(masterFrame, ampDetector) exp = afwImage.ExposureF(masterFrame) self.copyMetadata(exp, expmeta, calibType) exp.setDetector(ampDetector) exp.setWcs(None) exp.setPhotoCalib(expPhotoCalib) if calibType == 'flat': exp.setFilter(expfilter) if self.config.doWrite and calibType != 'flat': print("writing file %s" % dataId) butler.put(exp, calibType, dataId=amp.dataId) masterExpList.append(exp) dataIdList.append(amp.dataId) if self.config.doWrite and calibType == 'flat': self.normChipAmps(masterExpList) for exp, dataId in zip(masterExpList, dataIdList): print("writing flat file %s" % dataId) butler.put(exp, calibType, dataId) return pipeBase.Struct( masterFrameList=masterExpList, )
def testExposure(self): inExposure = afwImage.ExposureF(self.maskedImage) outExposure = exposureFromImage(inExposure) self.assertIs(inExposure, outExposure)
def getExposure(): afwImage.ExposureF(inFilePathSmallImage)
def subtractExposures(self, templateExposure, scienceExposure, templateFwhmPix=None, scienceFwhmPix=None, candidateList=None, doWarping=True, convolveTemplate=True): """!Register, Psf-match and subtract two Exposures Do the following, in order: - Warp templateExposure to match scienceExposure, if their WCSs do not already match - Determine a PSF matching kernel and differential background model that matches templateExposure to scienceExposure - PSF-match templateExposure to scienceExposure - Compute subtracted exposure (see return values for equation). @param templateExposure: exposure to PSF-match to scienceExposure @param scienceExposure: reference Exposure @param templateFwhmPix: FWHM (in pixels) of the Psf in the template image (image to convolve) @param scienceFwhmPix: FWHM (in pixels) of the Psf in the science image @param candidateList: a list of footprints/maskedImages for kernel candidates; if None then source detection is run. - Currently supported: list of Footprints or measAlg.PsfCandidateF @param doWarping: what to do if templateExposure's and scienceExposure's WCSs do not match: - if True then warp templateExposure to match scienceExposure - if False then raise an Exception @param convolveTemplate: convolve the template image or the science image - if True, templateExposure is warped if doWarping, templateExposure is convolved - if False, templateExposure is warped if doWarping, scienceExposure is convolved @return a pipeBase.Struct containing these fields: - subtractedExposure: subtracted Exposure = scienceExposure - (matchedImage + backgroundModel) - matchedImage: templateExposure after warping to match templateExposure (if doWarping true), and convolving with psfMatchingKernel - psfMatchingKernel: PSF matching kernel - backgroundModel: differential background model - kernelCellSet: SpatialCellSet used to determine PSF matching kernel """ results = self.matchExposures(templateExposure=templateExposure, scienceExposure=scienceExposure, templateFwhmPix=templateFwhmPix, scienceFwhmPix=scienceFwhmPix, candidateList=candidateList, doWarping=doWarping, convolveTemplate=convolveTemplate) subtractedExposure = afwImage.ExposureF(scienceExposure, True) if convolveTemplate: subtractedMaskedImage = subtractedExposure.getMaskedImage() subtractedMaskedImage -= results.matchedExposure.getMaskedImage() subtractedMaskedImage -= results.backgroundModel else: subtractedExposure.setMaskedImage( results.warpedExposure.getMaskedImage()) subtractedMaskedImage = subtractedExposure.getMaskedImage() subtractedMaskedImage -= results.matchedExposure.getMaskedImage() subtractedMaskedImage -= results.backgroundModel # Preserve polarity of differences subtractedMaskedImage *= -1 # Place back on native photometric scale subtractedMaskedImage /= results.psfMatchingKernel.computeImage( afwImage.ImageD(results.psfMatchingKernel.getDimensions()), False) import lsstDebug display = lsstDebug.Info(__name__).display displayDiffIm = lsstDebug.Info(__name__).displayDiffIm maskTransparency = lsstDebug.Info(__name__).maskTransparency if not maskTransparency: maskTransparency = 0 if display: ds9.setMaskTransparency(maskTransparency) if display and displayDiffIm: ds9.mtv(templateExposure, frame=lsstDebug.frame, title="Template") lsstDebug.frame += 1 ds9.mtv(results.matchedExposure, frame=lsstDebug.frame, title="Matched template") lsstDebug.frame += 1 ds9.mtv(scienceExposure, frame=lsstDebug.frame, title="Science Image") lsstDebug.frame += 1 ds9.mtv(subtractedExposure, frame=lsstDebug.frame, title="Difference Image") lsstDebug.frame += 1 results.subtractedExposure = subtractedExposure return results
def __call__(self, source, exposure): fp = source.getFootprint() peaks = fp.getPeaks() peaksF = [pk.getF() for pk in peaks] fbb = fp.getBBox() fmask = afwImage.Mask(fbb) fmask.setXY0(fbb.getMinX(), fbb.getMinY()) fp.spans.setMask(fmask, 1) psf = exposure.getPsf() psfSigPix = psf.computeShape().getDeterminantRadius() psfFwhmPix = psfSigPix * self.sigma2fwhm subimage = afwImage.ExposureF(exposure, bbox=fbb, deep=True) cpsf = deblendBaseline.CachingPsf(psf) # if fewer than 2 peaks, just return a copy of the source if len(peaks) < 2: return source.getTable().copyRecord(source) # make sure you only deblend 2 peaks; take the brighest and faintest speaks = [(p.getPeakValue(), p) for p in peaks] speaks.sort() dpeaks = [speaks[0][1], speaks[-1][1]] # and only set these peaks in the footprint (peaks is mutable) peaks.clear() for peak in dpeaks: peaks.append(peak) if True: # Call top-level deblend task fpres = deblendBaseline.deblend(fp, exposure.getMaskedImage(), psf, psfFwhmPix, log=self.log, psfChisqCut1=self.psfChisqCut1, psfChisqCut2=self.psfChisqCut2, psfChisqCut2b=self.psfChisqCut2b) else: # Call lower-level _fit_psf task # Prepare results structure fpres = deblendBaseline.DeblenderResult(fp, exposure.getMaskedImage(), psf, psfFwhmPix, self.log) for pki, (pk, pkres, pkF) in enumerate(zip(dpeaks, fpres.deblendedParents[0].peaks, peaksF)): self.log.debug('Peak %i', pki) deblendBaseline._fitPsf(fp, fmask, pk, pkF, pkres, fbb, dpeaks, peaksF, self.log, cpsf, psfFwhmPix, subimage.getMaskedImage().getImage(), subimage.getMaskedImage().getVariance(), self.psfChisqCut1, self.psfChisqCut2, self.psfChisqCut2b) deblendedSource = source.getTable().copyRecord(source) deblendedSource.setParent(source.getId()) peakList = deblendedSource.getFootprint().getPeaks() peakList.clear() for i, peak in enumerate(fpres.deblendedParents[0].peaks): if peak.psfFitFlux > 0: suffix = "pos" else: suffix = "neg" c = peak.psfFitCenter self.log.info("deblended.centroid.dipole.psf.%s %f %f", suffix, c[0], c[1]) self.log.info("deblended.chi2dof.dipole.%s %f", suffix, peak.psfFitChisq / peak.psfFitDof) self.log.info("deblended.flux.dipole.psf.%s %f", suffix, peak.psfFitFlux * np.sum(peak.templateImage.getArray())) peakList.append(peak.peak) return deblendedSource
def cutoutImage(butler, skymap, specObjID, ra, dec, bands, width=60.): # width is in arcsec #coord = afwCoord.Coord(afwGeom.Point2D(ra, dec)) coord = lsstGeom.SpherePoint(ra, dec, lsstGeom.degrees) tract, patch, wcs = findTractPatch(skymap, coord) print(tract, patch) ipx, ipy = map(int, patch.split(',')) #x, y = wcs.skyToPixel(coord.toIcrs()) x, y = wcs.skyToPixel(coord) ix = int(math.floor(x + 0.5)) iy = int(math.floor(y + 0.5)) width_in_pixel = int( width / wcs.getPixelScale().asArcseconds() / 2) * 2 + 1 pxmin, pymin, pxmax, pymax = getCorners(skymap, tract, ipx, ipy) bbox = lsstGeom.Box2I( lsstGeom.Point2I(ix - width_in_pixel // 2, iy - width_in_pixel // 2), lsstGeom.Point2I(ix + width_in_pixel // 2, iy + width_in_pixel // 2)) xmin, ymin = bbox.getBegin() xmax, ymax = bbox.getEnd() xmax -= 1 ymax -= 1 patches = list() bboxes = list() patches.append((ipx, ipy)) bboxes.append(getBBox(xmin, ymin, xmax, ymax, pxmin, pymin, pxmax, pymax)) if ix - width_in_pixel // 2 < pxmin: patches.append((ipx - 1, ipy)) _pxmin, _pymin, _pxmax, _pymax = getCorners(skymap, tract, ipx - 1, ipy) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) if iy - width_in_pixel // 2 < pymin: patches.append((ipx, ipy - 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy - 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) patches.append((ipx - 1, ipy - 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx - 1, ipy - 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) elif iy + width_in_pixel // 2 > pymax: patches.append((ipx, ipy + 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy + 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) patches.append((ipx - 1, ipy + 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx - 1, ipy + 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) else: pass elif ix + width_in_pixel // 2 > pxmax: patches.append((ipx + 1, ipy)) _pxmin, _pymin, _pxmax, _pymax = getCorners(skymap, tract, ipx + 1, ipy) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) if iy - width_in_pixel // 2 < pymin: patches.append((ipx, ipy - 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy - 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) patches.append((ipx + 1, ipy - 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx + 1, ipy - 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) elif iy + width_in_pixel // 2 > pymax: patches.append((ipx, ipy + 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy + 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) patches.append((ipx + 1, ipy + 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx + 1, ipy + 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) else: pass else: if iy - width_in_pixel // 2 < pymin: patches.append((ipx, ipy - 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy - 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) elif iy + width_in_pixel // 2 > pymax: patches.append((ipx, ipy + 1)) _pxmin, _pymin, _pxmax, _pymax = getCorners( skymap, tract, ipx, ipy + 1) bboxes.append( getBBox(xmin, ymin, xmax, ymax, _pxmin, _pymin, _pxmax, _pymax)) else: pass for band in bands: try: fname = butler.get('deepCoadd_calexp_filename', { 'tract': tract, 'patch': patch, 'filter': band })[0] exposure = afwImage.ExposureF(fname, origin=afwImage.PARENT) psfExp = exposure.getPsf().computeImage(lsstGeom.Point2D(ix, iy)) psf_fname = '%s_%s_psf.fits' % (specObjID, band) psfExp.writeFits(psf_fname) x0, y0 = exposure.getXY0() newExp = afwImage.ExposureF(width_in_pixel, width_in_pixel) wcs = exposure.getWcs() for _patch, _bbox in zip(patches, bboxes): fname = butler.get('deepCoadd_calexp_filename', { 'tract': tract, 'patch': '%d,%d' % (_patch), 'filter': band })[0] exposure = afwImage.ExposureF(fname, bbox=_bbox, origin=afwImage.PARENT) sub = afwImage.MaskedImageF( newExp.getMaskedImage(), lsstGeom.Box2I( lsstGeom.Point2I(_bbox.getMinX() - xmin, _bbox.getMinY() - ymin), _bbox.getDimensions()), afwImage.PARENT) #sub <<= exposure.getMaskedImage() sub.assign(exposure.getMaskedImage()) image_fname = '%s_%s.fits' % (specObjID, band) newExp.setXY0(lsstGeom.Point2I(xmin, ymin)) newExp.setWcs(wcs) newExp.writeFits(image_fname) except Exception as e: print(e.args)
from astropy.io import fits import lsst.afw.image.basicUtils as bu import lsst.skymap as skymap import lsst.daf.persistence as dafPersist import numpy as np import os import sys import lsst.log logger = lsst.log.Log.getDefaultLogger() logger.setLevel(lsst.log.FATAL) HOME_PATH = os.path.expanduser("~") fn = HOME_PATH + "/lsst_data/raw/crblasted0289697/instcal0289697.12.fits" image = afwImage.ExposureF(fn) charImage = CharacterizeImageTask() charRes = charImage.characterize(image, exposureIdInfo=None, background=None) # try out one exposure visit = 289697 ccdnum = 1 filterName = 'g' """ folder data should have the following structure - for every visit there should be folder <visitnumber> and <crblastedvisitnumber> <visitnumber> should have three files: dqmask0288935.fits.fz instcal0288935.fits.fz wtmap0288935.fits.fz, where visit number is 0288935 <crblasted> should have one file per ccd called instcal0288935.1.fits where visit number is 0288935 and ccd number is 1 All fo this data is available at:https://lsst-web.ncsa.illinois.edu/~yusra/hits_calexp_dir/ root folder in this case data, should also have a file _mapper with the following line.
def setUp(self, CFHT=True): lambdaValue = 1.0 self.config1 = ipDiffim.ImagePsfMatchTask.ConfigClass() self.config1.kernel.name = "DF" self.subconfig1 = self.config1.kernel.active self.config2 = ipDiffim.ImagePsfMatchTask.ConfigClass() self.config2.kernel.name = "DF" self.subconfig2 = self.config2.kernel.active self.config3 = ipDiffim.ImagePsfMatchTask.ConfigClass() self.config3.kernel.name = "DF" self.subconfig3 = self.config3.kernel.active self.config4 = ipDiffim.ImagePsfMatchTask.ConfigClass() self.config4.kernel.name = "DF" self.subconfig4 = self.config4.kernel.active self.subconfig1.useRegularization = False self.subconfig2.useRegularization = True self.subconfig2.lambdaType = "absolute" self.subconfig2.lambdaValue = lambdaValue self.subconfig2.regularizationType = "centralDifference" self.subconfig2.centralRegularizationStencil = 5 self.subconfig3.useRegularization = True self.subconfig3.lambdaType = "absolute" self.subconfig3.lambdaValue = lambdaValue self.subconfig3.regularizationType = "centralDifference" self.subconfig3.centralRegularizationStencil = 9 self.subconfig4.useRegularization = True self.subconfig4.lambdaType = "absolute" self.subconfig4.lambdaValue = lambdaValue self.subconfig4.regularizationType = "forwardDifference" self.subconfig4.forwardRegularizationOrders = [1, 2] self.kList1 = ipDiffim.makeKernelBasisList(self.subconfig1) self.bskv1 = ipDiffim.BuildSingleKernelVisitorF( self.kList1, pexConfig.makePolicy(self.subconfig1)) self.kList2 = ipDiffim.makeKernelBasisList(self.subconfig2) self.hMat2 = ipDiffim.makeRegularizationMatrix( pexConfig.makePolicy(self.subconfig2)) self.bskv2 = ipDiffim.BuildSingleKernelVisitorF( self.kList2, pexConfig.makePolicy(self.subconfig2), self.hMat2) self.kList3 = ipDiffim.makeKernelBasisList(self.subconfig3) self.hMat3 = ipDiffim.makeRegularizationMatrix( pexConfig.makePolicy(self.subconfig3)) self.bskv3 = ipDiffim.BuildSingleKernelVisitorF( self.kList3, pexConfig.makePolicy(self.subconfig3), self.hMat3) self.kList4 = ipDiffim.makeKernelBasisList(self.subconfig4) self.hMat4 = ipDiffim.makeRegularizationMatrix( pexConfig.makePolicy(self.subconfig4)) self.bskv4 = ipDiffim.BuildSingleKernelVisitorF( self.kList4, pexConfig.makePolicy(self.subconfig4), self.hMat4) # known input images defDataDir = lsst.utils.getPackageDir('afwdata') if CFHT: defSciencePath = os.path.join(defDataDir, 'CFHT', 'D4', CFHTTORUN) defTemplatePath = os.path.join(defDataDir, 'CFHT', 'D4', CFHTTORUN + '_tmpl') # no need to remap self.scienceExposure = afwImage.ExposureF(defSciencePath) self.templateExposure = afwImage.ExposureF(defTemplatePath) else: defSciencePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v26-e0", "v26-e0-c011-a00.sci") defTemplatePath = os.path.join(defDataDir, "DC3a-Sim", "sci", "v5-e0", "v5-e0-c011-a00.sci") self.scienceExposure = afwImage.ExposureF(defSciencePath) self.templateExposure = afwImage.ExposureF(defTemplatePath) warper = afwMath.Warper.fromConfig(self.subconfig1.warpingConfig) self.templateExposure = warper.warpExposure( self.scienceExposure.getWcs(), self.templateExposure, destBBox=self.scienceExposure.getBBox()) diffimTools.backgroundSubtract(self.subconfig1.afwBackgroundConfig, [ self.scienceExposure.getMaskedImage(), self.templateExposure.getMaskedImage() ]) # image statistics self.dStats = ipDiffim.ImageStatisticsF() # tmi = self.templateExposure.getMaskedImage() smi = self.scienceExposure.getMaskedImage() detConfig = self.subconfig1.detectionConfig detPolicy = pexConfig.makePolicy(detConfig) detPolicy.set("detThreshold", 50.) detPolicy.set("detOnTemplate", False) kcDetect = ipDiffim.KernelCandidateDetectionF(detPolicy) kcDetect.apply(tmi, smi) self.footprints = kcDetect.getFootprints()
def testComputeExposureSummary(self): """Make a fake exposure and background and compute summary. """ np.random.seed(12345) # Make an exposure with a noise image exposure = afwImage.ExposureF(100, 100) skySigma = 10.0 exposure.getImage().getArray()[:, :] = np.random.normal(0.0, skySigma, size=(100, 100)) exposure.getVariance().getArray()[:, :] = skySigma**2. # Set the visitInfo date = DateTime(date=59234.7083333334, system=DateTime.DateSystem.MJD) observatory = Observatory(-70.7366*lsst.geom.degrees, -30.2407*lsst.geom.degrees, 2650.) visitInfo = afwImage.VisitInfo(exposureTime=10.0, date=date, observatory=observatory) exposure.getInfo().setVisitInfo(visitInfo) # Install a Gaussian PSF psfSize = 2.0 psf = GaussianPsf(5, 5, psfSize) exposure.setPsf(psf) # Install a simple WCS scale = 0.2*lsst.geom.arcseconds raCenter = 300.0*lsst.geom.degrees decCenter = 0.0*lsst.geom.degrees cdMatrix = makeCdMatrix(scale=scale) skyWcs = makeSkyWcs(crpix=exposure.getBBox().getCenter(), crval=lsst.geom.SpherePoint(raCenter, decCenter), cdMatrix=cdMatrix) exposure.setWcs(skyWcs) # Install a simple photoCalib photoCalib = afwImage.PhotoCalib(calibrationMean=0.3) zp = 2.5*np.log10(photoCalib.getInstFluxAtZeroMagnitude()) exposure.setPhotoCalib(photoCalib) # Compute the background image bgGridSize = 10 bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bctrl.setNxSample(int(exposure.getMaskedImage().getWidth()/bgGridSize) + 1) bctrl.setNySample(int(exposure.getMaskedImage().getHeight()/bgGridSize) + 1) backobj = afwMath.makeBackground(exposure.getMaskedImage().getImage(), bctrl) background = afwMath.BackgroundList() background.append(backobj) # Run the task expSummaryTask = ComputeExposureSummaryStatsTask() summary = expSummaryTask.run(exposure, None, background) # Test the outputs self.assertFloatsAlmostEqual(summary.psfSigma, psfSize) self.assertFloatsAlmostEqual(summary.psfIxx, psfSize**2.) self.assertFloatsAlmostEqual(summary.psfIyy, psfSize**2.) self.assertFloatsAlmostEqual(summary.psfIxy, 0.0) self.assertFloatsAlmostEqual(summary.psfArea, 23.088975164455444) delta = (scale*50).asDegrees() for a, b in zip(summary.raCorners, [raCenter.asDegrees() + delta, raCenter.asDegrees() - delta, raCenter.asDegrees() - delta, raCenter.asDegrees() + delta]): self.assertFloatsAlmostEqual(a, b, atol=1e-10) for a, b in zip(summary.decCorners, [decCenter.asDegrees() - delta, decCenter.asDegrees() - delta, decCenter.asDegrees() + delta, decCenter.asDegrees() + delta]): self.assertFloatsAlmostEqual(a, b, atol=1e-10) self.assertFloatsAlmostEqual(summary.ra, raCenter.asDegrees(), atol=1e-10) self.assertFloatsAlmostEqual(summary.decl, decCenter.asDegrees(), atol=1e-10) self.assertFloatsAlmostEqual(summary.zeroPoint, zp) # Need to compare background level and noise # These are only approximately 0+/-10 because of the small image self.assertFloatsAlmostEqual(summary.skyBg, -0.079, atol=1e-3) self.assertFloatsAlmostEqual(summary.skyNoise, 9.816, atol=1e-3) self.assertFloatsAlmostEqual(summary.meanVar, skySigma**2.) self.assertFloatsAlmostEqual(summary.zenithDistance, 59.42888, atol=1e-5)