def makeMeasurementConfig(forced=False, nsigma=6.0, nIterForRadius=1, kfac=2.5): """Construct a (SingleFrame|Forced)MeasurementConfig with the requested parameters""" if forced: msConfig = measBase.ForcedMeasurementConfig() msConfig.algorithms.names = [ "base_TransformedCentroid", "base_TransformedShape", "ext_photometryKron_KronFlux" ] msConfig.slots.centroid = "base_TransformedCentroid" msConfig.slots.shape = "base_TransformedShape" msConfig.copyColumns = {"id": "objectId", "parent": "parentObjectId"} else: msConfig = measBase.SingleFrameMeasurementConfig() msConfig.algorithms.names = [ "base_SdssCentroid", "base_SdssShape", "ext_photometryKron_KronFlux", "base_SkyCoord" ] msConfig.slots.centroid = "base_SdssCentroid" msConfig.slots.shape = "base_SdssShape" msConfig.slots.apFlux = "ext_photometryKron_KronFlux" msConfig.slots.modelFlux = None msConfig.slots.psfFlux = None msConfig.slots.instFlux = None msConfig.slots.calibFlux = None # msConfig.algorithms.names.remove("correctfluxes") msConfig.plugins["ext_photometryKron_KronFlux"].nSigmaForRadius = nsigma msConfig.plugins[ "ext_photometryKron_KronFlux"].nIterForRadius = nIterForRadius msConfig.plugins["ext_photometryKron_KronFlux"].nRadiusForFlux = kfac msConfig.plugins[ "ext_photometryKron_KronFlux"].enforceMinimumRadius = False return msConfig
def testHsmPsfMoments(self): for width in (2.0, 3.0, 4.0): psf = afwDetection.GaussianPsf(35, 35, width) exposure = afwImage.ExposureF(45, 56) exposure.getMaskedImage().set(1.0, 0, 1.0) exposure.setPsf(psf) # perform the shape measurement msConfig = base.SingleFrameMeasurementConfig() msConfig.algorithms.names = ["ext_shapeHSM_HsmPsfMoments"] plugin, cat = makePluginAndCat(lsst.meas.extensions.shapeHSM.HsmPsfMomentsAlgorithm, "ext_shapeHSM_HsmPsfMoments", centroid="centroid", control=lsst.meas.extensions.shapeHSM.HsmPsfMomentsControl()) source = cat.addNew() source.set("centroid_x", 23) source.set("centroid_y", 34) offset = afwGeom.Point2I(23, 34) tmpSpans = afwGeom.SpanSet.fromShape(int(width), offset=offset) source.setFootprint(afwDetection.Footprint(tmpSpans)) plugin.measure(source, exposure) x = source.get("ext_shapeHSM_HsmPsfMoments_x") y = source.get("ext_shapeHSM_HsmPsfMoments_y") xx = source.get("ext_shapeHSM_HsmPsfMoments_xx") yy = source.get("ext_shapeHSM_HsmPsfMoments_yy") xy = source.get("ext_shapeHSM_HsmPsfMoments_xy") self.assertAlmostEqual(x, 0.0, 3) self.assertAlmostEqual(y, 0.0, 3) expected = afwEll.Quadrupole(afwEll.Axes(width, width, 0.0)) self.assertAlmostEqual(xx, expected.getIxx(), SHAPE_DECIMALS) self.assertAlmostEqual(xy, expected.getIxy(), SHAPE_DECIMALS) self.assertAlmostEqual(yy, expected.getIyy(), SHAPE_DECIMALS)
def testFlags(self): """Test all the failure modes of this algorithm, as well as checking that it succeeds when it should. Since this algorithm depends on having a ModelFlux and a PsfFlux measurement, it is a failure mode when either is NAN, or when ModelFluxFlag or PsfFluxFlag is True. When psfFluxFactor != 0, the PsfFluxErr cannot be NAN, but otherwise is ignored When modelFluxFactor != 0, the ModelFluxErr cannot be NAN, but otherwise is ignored """ config = measBase.SingleFrameMeasurementConfig() config.slots.psfFlux = "base_PsfFlux" config.slots.modelFlux = "base_GaussianFlux" abConfig = catCalc.CatalogCalculationConfig() def runFlagTest(psfFlux=100.0, modelFlux=200.0, psfFluxErr=1.0, modelFluxErr=2.0, psfFluxFlag=False, modelFluxFlag=False): task = self.makeSingleFrameMeasurementTask(config=config) abTask = catCalc.CatalogCalculationTask(schema=task.schema, config=abConfig) exposure, catalog = self.dataset.realize(10.0, task.schema, randomSeed=1) source = catalog[0] source.set("base_PsfFlux_instFlux", psfFlux) source.set("base_PsfFlux_instFluxErr", psfFluxErr) source.set("base_PsfFlux_flag", psfFluxFlag) source.set("base_GaussianFlux_instFlux", modelFlux) source.set("base_GaussianFlux_instFluxErr", modelFluxErr) source.set("base_GaussianFlux_flag", modelFluxFlag) abTask.plugins["base_ClassificationExtendedness"].calculate(source) return source.get("base_ClassificationExtendedness_flag") # Test no error case - all necessary values are set self.assertFalse(runFlagTest()) # Test psfFlux flag case - failure in PsfFlux self.assertTrue(runFlagTest(psfFluxFlag=True)) # Test modelFlux flag case - failure in ModelFlux self.assertTrue(runFlagTest(modelFluxFlag=True)) # Test modelFlux NAN case self.assertTrue(runFlagTest(modelFlux=float("NaN"), modelFluxFlag=True)) # Test psfFlux NAN case self.assertTrue(runFlagTest(psfFlux=float("NaN"), psfFluxFlag=True)) # Test modelFluxErr NAN case when modelErrFactor is zero and non-zero abConfig.plugins["base_ClassificationExtendedness"].modelErrFactor = 0. self.assertFalse(runFlagTest(modelFluxErr=float("NaN"))) abConfig.plugins["base_ClassificationExtendedness"].modelErrFactor = 1. self.assertTrue(runFlagTest(modelFluxErr=float("NaN"))) # Test psfFluxErr NAN case when psfErrFactor is zero and non-zero abConfig.plugins["base_ClassificationExtendedness"].psfErrFactor = 0. self.assertFalse(runFlagTest(psfFluxErr=float("NaN"))) abConfig.plugins["base_ClassificationExtendedness"].psfErrFactor = 1. self.assertTrue(runFlagTest(psfFluxErr=float("NaN")))
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 testSingleFrameMeasurementTransform(self): """Test applying a transform task to the results of single frame measurement.""" schema = afwTable.SourceTable.makeMinimalSchema() sfmConfig = measBase.SingleFrameMeasurementConfig(plugins=[PLUGIN_NAME]) # We don't use slots in this test for key in sfmConfig.slots: setattr(sfmConfig.slots, key, None) sfmTask = measBase.SingleFrameMeasurementTask(schema, config=sfmConfig) transformTask = TransformTask(measConfig=sfmConfig, inputSchema=sfmTask.schema, outputDataset="src") self._transformAndCheck(sfmConfig, sfmTask.schema, transformTask)
def makeConfig(self): config = measBase.SingleFrameMeasurementConfig() config.plugins = [self.algName] config.slots.centroid = None config.slots.apFlux = None config.slots.calibFlux = None config.slots.instFlux = None config.slots.modelFlux = None config.slots.psfFlux = None config.slots.shape = None return config
def testSingleFramePlugin(self): config = measBase.SingleFrameMeasurementConfig() # n.b. we use the truth value as ModelFlux config.slots.psfFlux = "base_PsfFlux" config.slots.modelFlux = "truth" task = self.makeSingleFrameMeasurementTask(config=config) abTask = catCalc.CatalogCalculationTask(schema=task.schema) exposure, catalog = self.dataset.realize(10.0, task.schema, randomSeed=0) task.run(catalog, exposure) abTask.run(catalog) self.assertLess(catalog[0].get("base_ClassificationExtendedness_value"), 0.5) self.assertGreater(catalog[1].get("base_ClassificationExtendedness_value"), 0.5)
def testFootprintsMeasure(self): """Check that we can measure the objects in a detectionSet""" xcentroid = [10.0, 14.0, 9.0] ycentroid = [8.0, 11.5061728, 14.0] flux = [51.0, 101.0, 20.0] ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED") if display: ds9.mtv(self.mi, frame=0) ds9.mtv(self.mi.getVariance(), frame=1) measureSourcesConfig = measBase.SingleFrameMeasurementConfig() measureSourcesConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] measureSourcesConfig.algorithms.names = ["base_NaiveCentroid", "base_SdssShape", "base_PsfFlux", "base_CircularApertureFlux"] measureSourcesConfig.slots.centroid = "base_NaiveCentroid" measureSourcesConfig.slots.psfFlux = "base_PsfFlux" measureSourcesConfig.slots.apFlux = "base_CircularApertureFlux_3_0" measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.instFlux = None measureSourcesConfig.slots.calibFlux = None schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig) measCat = afwTable.SourceCatalog(schema) # now run the SFM task with the test plugin sigma = 1e-10 psf = algorithms.DoubleGaussianPsf(11, 11, sigma) # i.e. a single pixel self.exposure.setPsf(psf) task.run(measCat, self.exposure) for i, source in enumerate(measCat): xc, yc = source.getX() - self.mi.getX0(), source.getY() - self.mi.getY0() if display: ds9.dot("+", xc, yc) self.assertAlmostEqual(source.getX(), xcentroid[i], 6) self.assertAlmostEqual(source.getY(), ycentroid[i], 6) self.assertEqual(source.getApFlux(), flux[i]) # 29 pixels in 3pixel circular ap. self.assertAlmostEqual(source.getApFluxErr(), math.sqrt(29), 6) # We're using a delta-function PSF, so the psfFlux should be the pixel under the centroid, # iff the object's centred in the pixel if xc == int(xc) and yc == int(yc): self.assertAlmostEqual(source.getPsfFlux(), self.exposure.getMaskedImage().getImage().get(int(xc + 0.5), int(yc + 0.5))) self.assertAlmostEqual(source.getPsfFluxErr(), self.exposure.getMaskedImage().getVariance().get(int(xc + 0.5), int(yc + 0.5)))
def testHsmPsfMoments(self, width, useSourceCentroidOffset, varyBBox, wrongBBox, center): psf = PyGaussianPsf(35, 35, width, varyBBox=varyBBox, wrongBBox=wrongBBox) exposure = afwImage.ExposureF(45, 56) exposure.getMaskedImage().set(1.0, 0, 1.0) exposure.setPsf(psf) # perform the shape measurement msConfig = base.SingleFrameMeasurementConfig() msConfig.algorithms.names = ["ext_shapeHSM_HsmPsfMoments"] control = lsst.meas.extensions.shapeHSM.HsmPsfMomentsControl() self.assertFalse(control.useSourceCentroidOffset) control.useSourceCentroidOffset = useSourceCentroidOffset plugin, cat = makePluginAndCat( lsst.meas.extensions.shapeHSM.HsmPsfMomentsAlgorithm, "ext_shapeHSM_HsmPsfMoments", centroid="centroid", control=control) source = cat.addNew() source.set("centroid_x", center[0]) source.set("centroid_y", center[1]) offset = geom.Point2I(*center) tmpSpans = afwGeom.SpanSet.fromShape(int(width), offset=offset) source.setFootprint(afwDetection.Footprint(tmpSpans)) plugin.measure(source, exposure) x = source.get("ext_shapeHSM_HsmPsfMoments_x") y = source.get("ext_shapeHSM_HsmPsfMoments_y") xx = source.get("ext_shapeHSM_HsmPsfMoments_xx") yy = source.get("ext_shapeHSM_HsmPsfMoments_yy") xy = source.get("ext_shapeHSM_HsmPsfMoments_xy") self.assertFalse(source.get("ext_shapeHSM_HsmPsfMoments_flag")) self.assertFalse( source.get("ext_shapeHSM_HsmPsfMoments_flag_no_pixels")) self.assertFalse( source.get("ext_shapeHSM_HsmPsfMoments_flag_not_contained")) self.assertFalse( source.get("ext_shapeHSM_HsmPsfMoments_flag_parent_source")) self.assertAlmostEqual(x, 0.0, 3) self.assertAlmostEqual(y, 0.0, 3) expected = afwEll.Quadrupole(afwEll.Axes(width, width, 0.0)) self.assertAlmostEqual(xx, expected.getIxx(), SHAPE_DECIMALS) self.assertAlmostEqual(xy, expected.getIxy(), SHAPE_DECIMALS) self.assertAlmostEqual(yy, expected.getIyy(), SHAPE_DECIMALS)
def setUp(self): im = afwImage.ImageF(self.monetFile("small.fits")) self.mi = afwImage.MaskedImageF(im, afwImage.Mask(im.getDimensions()), afwImage.ImageF(im.getDimensions())) self.ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(100)) if display: ds9.mtv(self.mi.getImage()) ds9.erase() for foot in self.ds.getFootprints(): bbox = foot.getBBox() x0, y0 = bbox.getMinX(), bbox.getMinY() x1, y1 = bbox.getMaxX(), bbox.getMaxY() xc = (x0 + x1) / 2.0 yc = (y0 + y1) / 2.0 if display: ds9.dot("+", xc, yc, ctype=ds9.BLUE) if False: x0 -= 0.5 y0 -= 0.5 x1 += 0.5 y1 += 0.5 ds9.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)], ctype=ds9.RED) msConfig = measBase.SingleFrameMeasurementConfig() msConfig.algorithms.names = ["base_GaussianCentroid"] msConfig.plugins["base_GaussianCentroid"].doFootprintCheck = False msConfig.slots.centroid = "base_GaussianCentroid" msConfig.slots.shape = None msConfig.slots.apFlux = None msConfig.slots.modelFlux = None msConfig.slots.psfFlux = None msConfig.slots.instFlux = None msConfig.slots.calibFlux = None schema = afwTable.SourceTable.makeMinimalSchema() self.task = measBase.SingleFrameMeasurementTask(schema, config=msConfig) self.ssMeasured = afwTable.SourceCatalog(schema) self.ssMeasured.table.defineCentroid("base_GaussianCentroid") self.ssTruth = afwTable.SourceCatalog(schema) self.ssTruth.table.defineCentroid("base_GaussianCentroid") self.readTruth(self.monetFile("positions.dat-original"))
def testPsfFlux(self): """Test that fluxes are measured correctly.""" # # Total flux in image # flux = afwMath.makeStatistics(self.exp.getMaskedImage(), afwMath.SUM).getValue() self.assertAlmostEqual(flux / self.instFlux, 1.0) # # Various algorithms # rad = 10.0 schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=float) schema.addField("centroid_y", type=float) schema.addField("centroid_flag", type='Flag') sfm_config = measBase.SingleFrameMeasurementConfig() sfm_config.doReplaceWithNoise = False sfm_config.plugins = ["base_CircularApertureFlux", "base_PsfFlux"] sfm_config.slots.centroid = "centroid" sfm_config.slots.shape = None sfm_config.slots.psfFlux = None sfm_config.slots.gaussianFlux = None sfm_config.slots.apFlux = None sfm_config.slots.modelFlux = None sfm_config.slots.calibFlux = None sfm_config.plugins["base_SdssShape"].maxShift = 10.0 sfm_config.plugins["base_CircularApertureFlux"].radii = [rad] task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config) measCat = afwTable.SourceCatalog(schema) source = measCat.addNew() source.set("centroid_x", self.xc) source.set("centroid_y", self.yc) task.run(measCat, self.exp) for algName in ["base_CircularApertureFlux_10_0", "base_PsfFlux"]: instFlux = source.get(algName + "_instFlux") flag = source.get(algName + "_flag") self.assertEqual(flag, False) self.assertAlmostEqual( instFlux / self.instFlux, 1.0, 4, "Measuring with %s: %g v. %g" % (algName, instFlux, self.instFlux))
def _runDetection(self, params): """!Run 'diaSource' detection on the diffim, including merging of positive and negative sources. Then run DipoleFitTask on the image and return the resulting catalog. """ # Create the various tasks and schema -- avoid code reuse. testImage = params.testImage detectTask, schema = testImage.detectDipoleSources(doMerge=False, minBinSize=32) measureConfig = measBase.SingleFrameMeasurementConfig() measureConfig.slots.calibFlux = None measureConfig.slots.modelFlux = None measureConfig.slots.gaussianFlux = None measureConfig.slots.shape = None measureConfig.slots.centroid = "ip_diffim_NaiveDipoleCentroid" measureConfig.doReplaceWithNoise = False measureConfig.plugins.names = [ "base_CircularApertureFlux", "base_PixelFlags", "base_SkyCoord", "base_PsfFlux", "ip_diffim_NaiveDipoleCentroid", "ip_diffim_NaiveDipoleFlux", "ip_diffim_PsfDipoleFlux" ] # Here is where we make the dipole fitting task. It can run the other measurements as well. # This is an example of how to pass it a custom config. measureTask = DipoleFitTask(config=measureConfig, schema=schema) table = afwTable.SourceTable.make(schema) detectResult = detectTask.run(table, testImage.diffim) # catalog = detectResult.sources # deblendTask.run(self.dipole, catalog, psf=self.dipole.getPsf()) fpSet = detectResult.fpSets.positive fpSet.merge(detectResult.fpSets.negative, 2, 2, False) sources = afwTable.SourceCatalog(table) fpSet.makeSources(sources) measureTask.run(sources, testImage.diffim, testImage.posImage, testImage.negImage) return sources
def mySetup(self): msConfig = measBase.SingleFrameMeasurementConfig() msConfig.algorithms.names = ["base_SdssCentroid"] msConfig.slots.centroid = "base_SdssCentroid" msConfig.slots.shape = None msConfig.slots.apFlux = None msConfig.slots.modelFlux = None msConfig.slots.psfFlux = None msConfig.slots.instFlux = None msConfig.slots.calibFlux = None schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=msConfig) measCat = afwTable.SourceCatalog(schema) source = measCat.addNew() fp = afwDetection.Footprint(self.exp.getBBox(afwImage.LOCAL)) fp.addPeak(50, 50, 1000.0) source.setFootprint(fp) # Then run the default SFM task. Results not checked task.run(measCat, self.exp) return source
def setUp(self): self.x0, self.y0 = 0, 0 self.nx, self.ny = 512, 512 #2048, 4096 self.sky = 100.0 self.nObj = 100 # make a detector with distortion self.detector = DetectorWrapper( bbox = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Extent2I(self.nx, self.ny)), orientation = cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)), radialDistortion = 0.925, ).detector # make a detector with no distortion self.flatDetector = DetectorWrapper( bbox = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.Extent2I(self.nx, self.ny)), orientation = cameraGeom.Orientation(afwGeom.Point2D(255.0, 255.0)), radialDistortion = 0.0, ).detector # detection policies detConfig = measAlg.SourceDetectionConfig() # Cannot use default background approximation order (6) for such a small image. detConfig.background.approxOrderX = 4 # measurement policies measConfig = measBase.SingleFrameMeasurementConfig() measConfig.algorithms.names = [ "base_SdssCentroid", "base_SdssShape", "base_GaussianFlux", "base_PsfFlux", ] measConfig.slots.centroid = "base_SdssCentroid" measConfig.slots.shape = "base_SdssShape" measConfig.slots.psfFlux = "base_PsfFlux" measConfig.slots.apFlux = None measConfig.slots.modelFlux = None measConfig.slots.instFlux = None measConfig.slots.calibFlux = None self.schema = afwTable.SourceTable.makeMinimalSchema() detConfig.validate() measConfig.validate() self.detTask = measAlg.SourceDetectionTask(config=detConfig, schema=self.schema) self.measTask = measBase.SingleFrameMeasurementTask(config=measConfig, schema=self.schema) # psf star selector starSelectorConfig = measAlg.SecondMomentStarSelectorTask.ConfigClass() starSelectorConfig.fluxLim = 5000.0 starSelectorConfig.histSize = 32 starSelectorConfig.clumpNSigma = 1.0 starSelectorConfig.badFlags = [] self.starSelector = measAlg.SecondMomentStarSelectorTask( config=starSelectorConfig, schema=self.schema ) # psf determiner psfDeterminerFactory = measAlg.psfDeterminerRegistry["pca"] psfDeterminerConfig = psfDeterminerFactory.ConfigClass() width, height = self.nx, self.ny nEigenComponents = 3 psfDeterminerConfig.sizeCellX = width//3 psfDeterminerConfig.sizeCellY = height//3 psfDeterminerConfig.nEigenComponents = nEigenComponents psfDeterminerConfig.spatialOrder = 1 psfDeterminerConfig.kernelSizeMin = 31 psfDeterminerConfig.nStarPerCell = 0 psfDeterminerConfig.nStarPerCellSpatialFit = 0 # unlimited self.psfDeterminer = psfDeterminerFactory(psfDeterminerConfig)
def setUp(self): self.schema = afwTable.SourceTable.makeMinimalSchema() config = measBase.SingleFrameMeasurementConfig() config.algorithms.names = [ "base_PixelFlags", "base_SdssCentroid", "base_GaussianFlux", "base_SdssShape", "base_CircularApertureFlux", "base_PsfFlux", ] config.algorithms["base_CircularApertureFlux"].radii = [3.0] config.slots.centroid = "base_SdssCentroid" config.slots.psfFlux = "base_PsfFlux" config.slots.apFlux = "base_CircularApertureFlux_3_0" config.slots.modelFlux = None config.slots.instFlux = None config.slots.calibFlux = None config.slots.shape = "base_SdssShape" self.measureTask = measBase.SingleFrameMeasurementTask(self.schema, config=config) width, height = 110, 301 self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) self.mi.set(0) sd = 3 # standard deviation of image self.mi.getVariance().set(sd * sd) self.mi.getMask().addMaskPlane("DETECTED") self.FWHM = 5 self.ksize = 31 # size of desired kernel sigma1 = 1.75 sigma2 = 2 * sigma1 self.exposure = afwImage.makeExposure(self.mi) self.exposure.setPsf( measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1, 0.1)) self.exposure.setDetector(DetectorWrapper().detector) # # Make a kernel with the exactly correct basis functions. Useful for debugging # basisKernelList = [] for sigma in (sigma1, sigma2): basisKernel = afwMath.AnalyticKernel( self.ksize, self.ksize, afwMath.GaussianFunction2D(sigma, sigma)) basisImage = afwImage.ImageD(basisKernel.getDimensions()) basisKernel.computeImage(basisImage, True) basisImage /= np.sum(basisImage.getArray()) if sigma == sigma1: basisImage0 = basisImage else: basisImage -= basisImage0 basisKernelList.append(afwMath.FixedKernel(basisImage)) order = 1 # 1 => up to linear spFunc = afwMath.PolynomialFunction2D(order) exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc) exactKernel.setSpatialParameters([[1.0, 0, 0], [0.0, 0.5 * 1e-2, 0.2e-2]]) self.exactPsf = measAlg.PcaPsf(exactKernel) rand = afwMath.Random() # make these tests repeatable by setting seed addNoise = True if addNoise: im = self.mi.getImage() afwMath.randomGaussianImage(im, rand) # N(0, 1) im *= sd # N(0, sd^2) del im xarr, yarr = [], [] for x, y in [ (20, 20), (60, 20), (30, 35), (50, 50), (20, 90), (70, 160), (25, 265), (75, 275), (85, 30), (50, 120), (70, 80), (60, 210), (20, 210), ]: xarr.append(x) yarr.append(y) for x, y in zip(xarr, yarr): dx = rand.uniform() - 0.5 # random (centered) offsets dy = rand.uniform() - 0.5 k = exactKernel.getSpatialFunction(1)( x, y) # functional variation of Kernel ... b = (k * sigma1**2 / ((1 - k) * sigma2**2) ) # ... converted double Gaussian's "b" # flux = 80000 - 20*x - 10*(y/float(height))**2 flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5)) I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2)) for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1): if iy < 0 or iy >= self.mi.getHeight(): continue for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1): if ix < 0 or ix >= self.mi.getWidth(): continue intensity = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b) Isample = rand.poisson( intensity) if addNoise else intensity self.mi.getImage().set( ix, iy, self.mi.getImage().get(ix, iy) + Isample) self.mi.getVariance().set( ix, iy, self.mi.getVariance().get(ix, iy) + intensity) # bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)) self.cellSet = afwMath.SpatialCellSet(bbox, 100) self.footprintSet = afwDetection.FootprintSet( self.mi, afwDetection.Threshold(100), "DETECTED") self.catalog = self.measure(self.footprintSet, self.exposure) for source in self.catalog: try: cand = measAlg.makePsfCandidate(source, self.exposure) self.cellSet.insertCandidate(cand) except Exception as e: print(e) continue
def testInputCounts(self, showPlot=False): # Generate a simulated coadd of four overlapping-but-offset CCDs. # Populate it with three sources. # Demonstrate that we can correctly recover the number of images which # contribute to each source. size = 20 # Size of images (pixels) value = 100.0 # Source flux ccdPositions = [ lsst.geom.Point2D(8, 0), lsst.geom.Point2D(10, 10), lsst.geom.Point2D(-8, -8), lsst.geom.Point2D(-8, 8) ] # Represent sources by a tuple of position and expected number of # contributing CCDs (based on the size/positions given above). Source = namedtuple("Source", ["pos", "count"]) sources = [ Source(pos=lsst.geom.Point2D(6, 6), count=2), Source(pos=lsst.geom.Point2D(10, 10), count=3), Source(pos=lsst.geom.Point2D(14, 14), count=1) ] # These lines are used in the creation of WCS information scale = 1.0e-5 * lsst.geom.degrees cdMatrix = afwGeom.makeCdMatrix(scale=scale) crval = lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees) # Construct the info needed to set the exposure object imageBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(size, size)) wcsRef = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(0, 0), crval=crval, cdMatrix=cdMatrix) # Create the exposure object, and set it up to be the output of a coadd exp = afwImage.ExposureF(size, size) exp.setWcs(wcsRef) exp.getInfo().setCoaddInputs( afwImage.CoaddInputs(afwTable.ExposureTable.makeMinimalSchema(), afwTable.ExposureTable.makeMinimalSchema())) # Set the fake CCDs that "went into" making this coadd, using the # differing wcs objects created above. ccds = exp.getInfo().getCoaddInputs().ccds for pos in ccdPositions: record = ccds.addNew() record.setWcs( afwGeom.makeSkyWcs(crpix=pos, crval=crval, cdMatrix=cdMatrix)) record.setBBox(imageBox) record.setValidPolygon(afwGeom.Polygon(lsst.geom.Box2D(imageBox))) # Configure a SingleFrameMeasurementTask to run InputCounts. measureSourcesConfig = measBase.SingleFrameMeasurementConfig() measureSourcesConfig.plugins.names = [ "base_PeakCentroid", "base_InputCount" ] measureSourcesConfig.slots.centroid = "base_PeakCentroid" measureSourcesConfig.slots.psfFlux = None measureSourcesConfig.slots.apFlux = None measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.gaussianFlux = None measureSourcesConfig.slots.calibFlux = None measureSourcesConfig.slots.shape = None measureSourcesConfig.validate() schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig) catalog = afwTable.SourceCatalog(schema) # Add simulated sources to the measurement catalog. for src in sources: spans = afwGeom.SpanSet.fromShape(1) spans = spans.shiftedBy(int(src.pos.getX()), int(src.pos.getY())) foot = afwDetection.Footprint(spans) peak = foot.getPeaks().addNew() peak.setFx(src.pos[0]) peak.setFy(src.pos[1]) peak.setPeakValue(value) catalog.addNew().setFootprint(foot) task.run(catalog, exp) for src, rec in zip(sources, catalog): self.assertEqual(rec.get("base_InputCount_value"), src.count) if display: ccdVennDiagram(exp)
def setUp(self): width, height = 100, 300 self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) self.mi.set(0) self.mi.getVariance().set(10) self.mi.getMask().addMaskPlane("DETECTED") self.FWHM = 5 self.ksize = 25 # size of desired kernel self.exposure = afwImage.makeExposure(self.mi) psf = roundTripPsf( 2, algorithms.DoubleGaussianPsf( self.ksize, self.ksize, self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1)) self.exposure.setPsf(psf) for x, y in [ (20, 20), #(30, 35), (50, 50), (60, 20), (60, 210), (20, 210) ]: flux = 10000 - 0 * x - 10 * y sigma = 3 + 0.01 * (y - self.mi.getHeight() / 2) psf = roundTripPsf( 3, algorithms.DoubleGaussianPsf(self.ksize, self.ksize, sigma, 1, 0.1)) im = psf.computeImage().convertF() im *= flux x0y0 = afwGeom.PointI(x - self.ksize // 2, y - self.ksize // 2) smi = self.mi.getImage().Factory( self.mi.getImage(), afwGeom.BoxI(x0y0, afwGeom.ExtentI(self.ksize)), afwImage.LOCAL) if False: # Test subtraction with non-centered psfs im = afwMath.offsetImage(im, 0.5, 0.5) smi += im del psf del im del smi roundTripPsf( 4, algorithms.DoubleGaussianPsf( self.ksize, self.ksize, self.FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1)) self.cellSet = afwMath.SpatialCellSet( afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(width, height)), 100) ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED") # # Prepare to measure # schema = afwTable.SourceTable.makeMinimalSchema() sfm_config = measBase.SingleFrameMeasurementConfig() sfm_config.plugins = [ "base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux", "base_SdssShape", "base_GaussianFlux", "base_PixelFlags" ] sfm_config.slots.centroid = "base_SdssCentroid" sfm_config.slots.shape = "base_SdssShape" sfm_config.slots.psfFlux = "base_PsfFlux" sfm_config.slots.instFlux = None sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0" sfm_config.slots.modelFlux = "base_GaussianFlux" sfm_config.slots.calibFlux = None sfm_config.plugins["base_SdssShape"].maxShift = 10.0 sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0] task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config) measCat = afwTable.SourceCatalog(schema) # detect the sources and run with the measurement task ds.makeSources(measCat) task.run(measCat, self.exposure) for source in measCat: self.cellSet.insertCandidate( algorithms.makePsfCandidate(source, self.exposure))
def testDetection(self): """Test object detection""" # # Fix defects # # Mask known bad pixels # measAlgorithmsDir = lsst.utils.getPackageDir('meas_algorithms') badPixels = defects.policyToBadRegionList(os.path.join(measAlgorithmsDir, "policy/BadPixels.paf")) # did someone lie about the origin of the maskedImage? If so, adjust bad pixel list if self.XY0.getX() != self.mi.getX0() or self.XY0.getY() != self.mi.getY0(): dx = self.XY0.getX() - self.mi.getX0() dy = self.XY0.getY() - self.mi.getY0() for bp in badPixels: bp.shift(-dx, -dy) algorithms.interpolateOverDefects(self.mi, self.psf, badPixels) # # Subtract background # bgGridSize = 64 # was 256 ... but that gives only one region and the spline breaks bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bctrl.setNxSample(int(self.mi.getWidth()/bgGridSize) + 1) bctrl.setNySample(int(self.mi.getHeight()/bgGridSize) + 1) backobj = afwMath.makeBackground(self.mi.getImage(), bctrl) self.mi.getImage()[:] -= backobj.getImageF() # # Remove CRs # crConfig = algorithms.FindCosmicRaysConfig() algorithms.findCosmicRays(self.mi, self.psf, 0, pexConfig.makePolicy(crConfig)) # # We do a pretty good job of interpolating, so don't propagagate the convolved CR/INTRP bits # (we'll keep them for the original CR/INTRP pixels) # savedMask = self.mi.getMask().Factory(self.mi.getMask(), True) saveBits = savedMask.getPlaneBitMask("CR") | \ savedMask.getPlaneBitMask("BAD") | \ savedMask.getPlaneBitMask("INTRP") # Bits to not convolve savedMask &= saveBits msk = self.mi.getMask() msk &= ~saveBits # Clear the saved bits del msk # # Smooth image # psf = algorithms.DoubleGaussianPsf(15, 15, self.FWHM/(2*math.sqrt(2*math.log(2)))) cnvImage = self.mi.Factory(self.mi.getBBox()) kernel = psf.getKernel() afwMath.convolve(cnvImage, self.mi, kernel, afwMath.ConvolutionControl()) msk = cnvImage.getMask() msk |= savedMask # restore the saved bits del msk threshold = afwDetection.Threshold(3, afwDetection.Threshold.STDEV) # # Only search the part of the frame that was PSF-smoothed # llc = lsst.geom.PointI(psf.getKernel().getWidth()//2, psf.getKernel().getHeight()//2) urc = lsst.geom.PointI(cnvImage.getWidth() - llc[0] - 1, cnvImage.getHeight() - llc[1] - 1) middle = cnvImage.Factory(cnvImage, lsst.geom.BoxI(llc, urc), afwImage.LOCAL) ds = afwDetection.FootprintSet(middle, threshold, "DETECTED") del middle # # Reinstate the saved (e.g. BAD) (and also the DETECTED | EDGE) bits in the unsmoothed image # savedMask[:] = cnvImage.getMask() msk = self.mi.getMask() msk |= savedMask del msk del savedMask if display: disp = afwDisplay.Display(frame=2) disp.mtv(self.mi, title=self._testMethodName + ": image") afwDisplay.Display(frame=3).mtv(cnvImage, title=self._testMethodName + ": cnvImage") # # Time to actually measure # schema = afwTable.SourceTable.makeMinimalSchema() sfm_config = measBase.SingleFrameMeasurementConfig() sfm_config.plugins = ["base_SdssCentroid", "base_CircularApertureFlux", "base_PsfFlux", "base_SdssShape", "base_GaussianFlux", "base_PixelFlags"] sfm_config.slots.centroid = "base_SdssCentroid" sfm_config.slots.shape = "base_SdssShape" sfm_config.slots.psfFlux = "base_PsfFlux" sfm_config.slots.gaussianFlux = None sfm_config.slots.apFlux = "base_CircularApertureFlux_3_0" sfm_config.slots.modelFlux = "base_GaussianFlux" sfm_config.slots.calibFlux = None sfm_config.plugins["base_SdssShape"].maxShift = 10.0 sfm_config.plugins["base_CircularApertureFlux"].radii = [3.0] task = measBase.SingleFrameMeasurementTask(schema, config=sfm_config) measCat = afwTable.SourceCatalog(schema) # detect the sources and run with the measurement task ds.makeSources(measCat) self.exposure.setPsf(self.psf) task.run(measCat, self.exposure) self.assertGreater(len(measCat), 0) for source in measCat: if source.get("base_PixelFlags_flag_edge"): continue if display: disp.dot("+", source.getX(), source.getY())
def testFootprintsMeasure(self): """Check that we can measure the objects in a detectionSet""" xcentroid = [10.0, 14.0, 9.0] ycentroid = [8.0, 11.5061728, 14.0] flux = [51.0, 101.0, 20.0] # sqrt of num pixels in aperture; note the second source is offset # from the pixel grid. fluxErr = [math.sqrt(29), math.sqrt(27), math.sqrt(29)] footprints = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED") if display: disp = afwDisplay.Display(frame=0) disp.mtv(self.mi, title=self._testMethodName + ": image") afwDisplay.Display(frame=1).mtv(self.mi.getVariance(), title=self._testMethodName + ": variance") measureSourcesConfig = measBase.SingleFrameMeasurementConfig() measureSourcesConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] # Numerical tests below assumes that we are not using sinc fluxes. measureSourcesConfig.algorithms["base_CircularApertureFlux"].maxSincRadius = 0.0 measureSourcesConfig.algorithms.names = ["base_NaiveCentroid", "base_SdssShape", "base_PsfFlux", "base_CircularApertureFlux"] measureSourcesConfig.slots.centroid = "base_NaiveCentroid" measureSourcesConfig.slots.psfFlux = "base_PsfFlux" measureSourcesConfig.slots.apFlux = "base_CircularApertureFlux_3_0" measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.gaussianFlux = None measureSourcesConfig.slots.calibFlux = None schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig) measCat = afwTable.SourceCatalog(schema) footprints.makeSources(measCat) # now run the SFM task with the test plugin sigma = 1e-10 psf = algorithms.DoubleGaussianPsf(11, 11, sigma) # i.e. a single pixel self.exposure.setPsf(psf) task.run(measCat, self.exposure) self.assertEqual(len(measCat), len(flux)) for i, source in enumerate(measCat): xc, yc = source.getX(), source.getY() if display: disp.dot("+", xc, yc) self.assertAlmostEqual(source.getX(), xcentroid[i], 6) self.assertAlmostEqual(source.getY(), ycentroid[i], 6) self.assertEqual(source.getApInstFlux(), flux[i]) self.assertAlmostEqual(source.getApInstFluxErr(), fluxErr[i], 6) # We're using a delta-function PSF, so the psfFlux should be the # pixel under the centroid, iff the object's centred in the pixel if xc == int(xc) and yc == int(yc): self.assertAlmostEqual(source.getPsfInstFlux(), self.exposure.getMaskedImage().getImage()[int(xc + 0.5), int(yc + 0.5)]) self.assertAlmostEqual(source.getPsfInstFluxErr(), self.exposure.getMaskedImage().getVariance()[int(xc + 0.5), int(yc + 0.5)])
def setUp(self): size = 128 # size of image (pixels) center = afwGeom.Point2D(size // 2, size // 2) # object center width = 2 # PSF width flux = 10.0 # Flux of object variance = 1.0 # Mean variance value varianceStd = 0.1 # Standard deviation of the variance value # Set a seed for predictable randomness np.random.seed(300) # Create a random image to be used as variance plane variancePlane = np.random.normal(variance, varianceStd, size * size).reshape(size, size) # Initial setup of an image exp = afwImage.ExposureF(size, size) image = exp.getMaskedImage().getImage() mask = exp.getMaskedImage().getMask() var = exp.getMaskedImage().getVariance() image.set(0.0) mask.set(0) var.getArray()[:, :] = variancePlane # Put down a PSF psfSize = int(6 * width + 1) # Size of PSF image; must be odd psf = afwDetection.GaussianPsf(psfSize, psfSize, width) exp.setPsf(psf) psfImage = psf.computeImage(center).convertF() psfImage *= flux image.Factory(image, psfImage.getBBox(afwImage.PARENT)).__iadd__(psfImage) var.Factory(var, psfImage.getBBox(afwImage.PARENT)).__iadd__(psfImage) # Put in some bad pixels to ensure they're ignored for i in range(-5, 6): bad = size // 2 + i * width var.getArray()[bad, :] = float("nan") mask.getArray()[bad, :] = mask.getPlaneBitMask("BAD") var.getArray()[:, bad] = float("nan") mask.getArray()[:, bad] = mask.getPlaneBitMask("BAD") # Put in some unmasked bad pixels outside the expected aperture, to ensure the aperture is working var.getArray()[0, 0] = float("nan") var.getArray()[0, -1] = float("nan") var.getArray()[-1, 0] = float("nan") var.getArray()[-1, -1] = float("nan") if display: import lsst.afw.display as afwDisplay afwDisplay.getDisplay(1).mtv(image) afwDisplay.getDisplay(2).mtv(mask) afwDisplay.getDisplay(3).mtv(var) config = measBase.SingleFrameMeasurementConfig() config.plugins.names = [ "base_NaiveCentroid", "base_SdssShape", "base_Variance" ] config.slots.centroid = "base_NaiveCentroid" config.slots.psfFlux = None config.slots.apFlux = None config.slots.modelFlux = None config.slots.instFlux = None config.slots.calibFlux = None config.slots.shape = "base_SdssShape" config.slots.psfShape = None config.plugins["base_Variance"].mask = ["BAD", "SAT"] config.validate() schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=config) catalog = afwTable.SourceCatalog(schema) spans = afwGeom.SpanSet.fromShape(int(width)) spans = spans.shiftedBy(int(center.getX()), int(center.getY())) foot = afwDetection.Footprint(spans) peak = foot.getPeaks().addNew() peak.setIx(int(center.getX())) peak.setIy(int(center.getY())) peak.setFx(center.getX()) peak.setFy(center.getY()) peak.setPeakValue(flux) source = catalog.addNew() source.setFootprint(foot) self.variance = variance self.varianceStd = varianceStd self.mask = mask self.catalog = catalog self.exp = exp self.task = task self.source = source
def testUndeblendedMeasurement(self): """Check undeblended measurement and aperture correction""" width, height = 100, 100 # Dimensions of image x0, y0 = 1234, 5678 # Offset of image radius = 3.0 # Aperture radius xCenter, yCenter = width//2, height//2 # Position of first source; integer values, for convenience xOffset, yOffset = 1, 1 # Offset from first source to second source flux1, flux2 = 1000, 1 # Flux of sources apCorrValue = 3.21 # Aperture correction value to apply image = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) image.setXY0(x0, y0) image.getVariance().set(1.0) schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=np.float64) schema.addField("centroid_y", type=np.float64) schema.addField("centroid_flag", type='Flag') schema.getAliasMap().set("slot_Centroid", "centroid") sfmConfig = measBase.SingleFrameMeasurementConfig() algName = "base_CircularApertureFlux" for subConfig in (sfmConfig.plugins, sfmConfig.undeblended): subConfig.names = [algName] subConfig[algName].radii = [radius] subConfig[algName].maxSincRadius = 0 # Disable sinc photometry because we're undersampled slots = sfmConfig.slots slots.centroid = "centroid" slots.shape = None slots.psfShape = None slots.apFlux = None slots.modelFlux = None slots.psfFlux = None slots.instFlux = None slots.calibFlux = None fieldName = lsst.meas.base.CircularApertureFluxAlgorithm.makeFieldPrefix(algName, radius) measBase.addApCorrName(fieldName) apCorrConfig = measBase.ApplyApCorrConfig() apCorrConfig.proxies = {"undeblended_" + fieldName: fieldName} sfm = measBase.SingleFrameMeasurementTask(config=sfmConfig, schema=schema) apCorr = measBase.ApplyApCorrTask(config=apCorrConfig, schema=schema) cat = afwTable.SourceCatalog(schema) parent = cat.addNew() parent.set("centroid_x", x0 + xCenter) parent.set("centroid_y", y0 + yCenter) spanSetParent = afwGeom.SpanSet.fromShape(int(radius)) spanSetParent = spanSetParent.shiftedBy(x0 + xCenter, y0 + yCenter) parent.setFootprint(afwDetection.Footprint(spanSetParent)) # First child is bright, dominating the blend child1 = cat.addNew() child1.set("centroid_x", parent.get("centroid_x")) child1.set("centroid_y", parent.get("centroid_y")) child1.setParent(parent.getId()) image.set(xCenter, yCenter, (flux1, 0, 0)) spanSetChild1 = afwGeom.SpanSet.fromShape(1) spanSetChild1 = spanSetChild1.shiftedBy(x0 + xCenter, y0 + yCenter) foot1 = afwDetection.Footprint(spanSetChild1) child1.setFootprint(afwDetection.HeavyFootprintF(foot1, image)) # Second child is fainter, but we want to be able to measure it! child2 = cat.addNew() child2.set("centroid_x", parent.get("centroid_x") + xOffset) child2.set("centroid_y", parent.get("centroid_y") + yOffset) child2.setParent(parent.getId()) image.set(xCenter + xOffset, yCenter + yOffset, (flux2, 0, 0)) spanSetChild2 = afwGeom.SpanSet.fromShape(1) tmpPoint = (x0 + xCenter + xOffset, y0 + yCenter + yOffset) spanSetChild2 = spanSetChild2.shiftedBy(*tmpPoint) foot2 = afwDetection.Footprint(spanSetChild2) child2.setFootprint(afwDetection.HeavyFootprintF(foot2, image)) spans = foot1.spans.union(foot2.spans) bbox = afwGeom.Box2I() bbox.include(foot1.getBBox()) bbox.include(foot2.getBBox()) parent.setFootprint(afwDetection.Footprint(spans, bbox)) exposure = afwImage.makeExposure(image) sfm.run(cat, exposure) def checkSource(source, baseName, expectedFlux): """Check that we get the expected results""" self.assertEqual(source.get(baseName + "_flux"), expectedFlux) self.assertGreater(source.get(baseName + "_fluxSigma"), 0) self.assertFalse(source.get(baseName + "_flag")) # Deblended checkSource(child1, fieldName, flux1) checkSource(child2, fieldName, flux2) # Undeblended checkSource(child1, "undeblended_" + fieldName, flux1 + flux2) checkSource(child2, "undeblended_" + fieldName, flux1 + flux2) # Apply aperture correction apCorrMap = afwImage.ApCorrMap() apCorrMap[fieldName + "_flux"] = afwMath.ChebyshevBoundedField( image.getBBox(), apCorrValue*np.ones((1, 1), dtype=np.float64) ) apCorrMap[fieldName + "_fluxSigma"] = afwMath.ChebyshevBoundedField( image.getBBox(), apCorrValue*np.zeros((1, 1), dtype=np.float64) ) apCorr.run(cat, apCorrMap) # Deblended checkSource(child1, fieldName, flux1*apCorrValue) checkSource(child2, fieldName, flux2*apCorrValue) # Undeblended checkSource(child1, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue) checkSource(child2, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue) self.assertIn(fieldName + "_apCorr", schema) self.assertIn(fieldName + "_apCorrSigma", schema) self.assertIn("undeblended_" + fieldName + "_apCorr", schema) self.assertIn("undeblended_" + fieldName + "_apCorrSigma", schema)
def run(self, dataRef, selectDataList=[]): """Draw randoms for a given patch """ # first test if the forced-src file exists # do not process if the patch doesn't exist try: dataRef.get(self.config.coaddName + "Coadd_forced_src") except: self.log.info("No forced_src file found for %s. Skipping..." % (dataRef.dataId)) return # verbose self.log.info("Processing %s" % (dataRef.dataId)) # create a seed that depends on patch id # so it is consistent among filters if self.config.seed == -1: p = [int(d) for d in dataRef.dataId["patch"].split(",") ] numpy.random.seed(seed=dataRef.dataId["tract"]*10000+p[0]*10+ p[1]) else: numpy.random.seed(seed=self.config.seed) # compute sky mean and sky std_dev for this patch # in 2" diameter apertures (~12 pixels x 0.17"/pixel) # import source list for getting sky objects sources = dataRef.get(self.config.coaddName + "Coadd_meas") if True: sky_apertures = sources['base_CircularApertureFlux_12_0_flux'][sources['merge_peak_sky']] select = numpy.isfinite(sky_apertures) sky_mean = numpy.mean(sky_apertures[select]) sky_std = numpy.std(sky_apertures[select]) # NOTE: to get 5-sigma limiting magnitudes: # print -2.5*numpy.log10(5.0*sky_std/coadd.getCalib().getFluxMag0()[0]) else: sky_mean = 0.0 sky_std = 0.0 # get coadd, coadd info and coadd psf object coadd = dataRef.get(self.config.coaddName + "Coadd_calexp") psf = coadd.getPsf() var = coadd.getMaskedImage().getVariance().getArray() skyInfo = self.getSkyInfo(dataRef) # wcs and reference point (wrt tract) # See http://hsca.ipmu.jp/hscsphinx_test/scripts/print_coord.html # for coordinate routines. wcs = coadd.getWcs() xy0 = coadd.getXY0() # dimension in pixels dim = coadd.getDimensions() # define measurement algorithms # mostly copied from /data1a/ana/hscPipe5/Linux64/meas_base/5.3-hsc/tests/testInputCount.py measureSourcesConfig = measBase.SingleFrameMeasurementConfig() measureSourcesConfig.plugins.names = ['base_PixelFlags', 'base_PeakCentroid', 'base_InputCount', 'base_SdssShape'] measureSourcesConfig.slots.centroid = "base_PeakCentroid" measureSourcesConfig.slots.psfFlux = None measureSourcesConfig.slots.apFlux = None measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.instFlux = None measureSourcesConfig.slots.calibFlux = None measureSourcesConfig.slots.shape = None # it seems it is still necessary to manually add the # bright-star mask flag by hand measureSourcesConfig.plugins['base_PixelFlags'].masksFpCenter.append("BRIGHT_OBJECT") measureSourcesConfig.plugins['base_PixelFlags'].masksFpAnywhere.append("BRIGHT_OBJECT") measureSourcesConfig.validate() # add PSF shape # sdssShape_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF xx from SDSS algorithm", units="pixel") # shape_sdss_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF yy from SDSS algorithm", units="pixel") # shape_sdss_psf = self.schema.addField("shape_sdss_psf", type="MomentsD", doc="PSF xy from SDSS algorithm", units="pixel") # additional columns # random number to adjust sky density adjust_density = self.schema.addField("adjust_density", type=float, doc="Random number between [0:1] to adjust sky density", units='') # sky mean and variance for the entire patch sky_mean_key = self.schema.addField("sky_mean", type=float, doc="Mean of sky value in 2\" diamter apertures", units='count') sky_std_key = self.schema.addField("sky_std", type=float, doc="Standard deviation of sky value in 2\" diamter apertures", units='count') # pixel variance at random point position pix_variance = self.schema.addField("pix_variance", type=float, doc="Pixel variance at random point position", units="flx^2") # add healpix map value (if healpix map is given) if self.depthMap.map is not None: depth_key = self.schema.addField("isFullDepthColor", type="Flag", doc="True if full depth and full colors at point position", units='') # task and output catalog task = measBase.SingleFrameMeasurementTask(self.schema, config=measureSourcesConfig) table = afwTable.SourceTable.make(self.schema, self.makeIdFactory(dataRef)) catalog = afwTable.SourceCatalog(table) if self.config.N == -1: # to output a constant random # number density, first compute # the area in degree pixel_area = coadd.getWcs().getPixelScale().asDegrees()**2 area = pixel_area * dim[0] * dim[1] N = self.iround(area*self.config.Nden*60.0*60.0) else: # fixed number if random points N = self.config.N # verbose self.log.info("Drawing %d random points" % (N)) # loop over N random points for i in range(N): # for i in range(100): # draw one random point x = numpy.random.random()*(dim[0]-1) y = numpy.random.random()*(dim[1]-1) # get coordinates radec = wcs.pixelToSky(afwGeom.Point2D(x + xy0.getX(), y + xy0.getY())) xy = wcs.skyToPixel(radec) # new record in table record = catalog.addNew() record.setCoord(radec) # get PSF moments and evaluate size #size_psf = 1.0 #try: # shape_sdss_psf_val = psf.computeShape(afwGeom.Point2D(xy)) #except: # pass #else: # record.set(shape_sdss_psf, shape_sdss_psf_val) # size_psf = shape_sdss_psf_val.getDeterminantRadius() # object has no footprint radius = 0 spanset1 = SpanSet.fromShape(radius, stencil=Stencil.CIRCLE, offset=afwGeom.Point2I(xy)) foot = Footprint(spanset1) foot.addPeak(xy[0], xy[1], 0.0) record.setFootprint(foot) # draw a number between 0 and 1 to adjust sky density record.set(adjust_density, numpy.random.random()) # add sky properties record.set(sky_mean_key, sky_mean) record.set(sky_std_key, sky_std) # add local (pixel) variance record.set(pix_variance, float(var[self.iround(y), self.iround(x)])) # required for setPrimaryFlags record.set(catalog.getCentroidKey(), afwGeom.Point2D(xy)) # add healpix map value if self.depthMap.map is not None: mapIndex = healpy.pixelfunc.ang2pix(self.depthMap.nside, numpy.pi/2.0 - radec[1].asRadians(), radec[0].asRadians(), nest=self.depthMap.nest) record.setFlag(depth_key, self.depthMap.map[mapIndex]) # run measurements task.run(catalog, coadd) self.setPrimaryFlags.run(catalog, skyInfo.skyMap, skyInfo.tractInfo, skyInfo.patchInfo, includeDeblend=False) # write catalog if self.config.fileOutName == "": if self.config.dirOutName == "" : fileOutName = dataRef.get(self.config.coaddName + "Coadd_forced_src_filename")[0].replace('forced_src', 'ran') self.log.info("WARNING: the output file will be written in {0:s}.".format(fileOutName)) else: fileOutName = "{0}/{1}/{2}/{3}/ran-{1}-{2}-{3}.fits".format(self.config.dirOutName,dataRef.dataId["filter"],dataRef.dataId["tract"],dataRef.dataId["patch"]) else: fileOutName = self.config.fileOutName self.mkdir_p(os.path.dirname(fileOutName)) catalog.writeFits(fileOutName) # to do. Define output name in init (not in paf) and # allow parallel processing # write sources # if self.config.doWriteSources: # dataRef.put(result.sources, self.dataPrefix + 'src') return