Esempio n. 1
0
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
Esempio n. 2
0
    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)
Esempio n. 3
0
    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
Esempio n. 5
0
 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
Esempio n. 7
0
 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)
Esempio n. 8
0
    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)))
Esempio n. 9
0
    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)
Esempio n. 10
0
    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"))
Esempio n. 11
0
    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))
Esempio n. 12
0
    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
Esempio n. 13
0
    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
Esempio n. 14
0
    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
Esempio n. 16
0
    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)
Esempio n. 17
0
    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))
Esempio n. 18
0
    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())
Esempio n. 19
0
    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)])
Esempio n. 20
0
    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)
Esempio n. 22
0
    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