Пример #1
0
    def test_chebyshev_evaluate(self, seed=1000):
        """
        Test the evaluation of chebyshev polynomials.

        Parameters
        ----------
        seed: `int`, optional
           Numpy random seed
        """
        # Set numpy seed for stability
        np.random.seed(seed=seed)

        xPos = self.xSize * np.random.rand(self.nStar)
        yPos = self.ySize * np.random.rand(self.nStar)

        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Point2I(self.xSize - 1, self.ySize - 1))

        # Compute the chebyshev values using the fgcm code
        fgcmField = fgcm.fgcmUtilities.Cheb2dField(self.xSize, self.ySize,
                                                   self.pars)
        fgcmValues = fgcmField.evaluate(xPos, yPos)

        # Compute the chebyshev values using the afw code
        field = afwMath.ChebyshevBoundedField(bbox, self.pars)
        fieldValues = field.evaluate(xPos, yPos)

        self.assertFloatsAlmostEqual(fieldValues, fgcmValues, rtol=5e-15)
    def _getChebyshevPhotoCalib(self, coefficients, err, xyMax, offset,
                                scaling):
        """
        Get the PhotoCalib object from a chebyshev polynomial zeropoint.

        Parameters
        ----------
        coefficients: `np.array`
           Flattened array of chebyshev coefficients
        err: `float`
           Error on zeropoint
        xyMax: `list` of length 2
           Maximum x and y of the chebyshev bounding box
        offset: `float`
           Absolute calibration offset
        scaling: `float`
           Flat scaling value from fgcmBuildStars

        Returns
        -------
        photoCalib: `afwImage.PhotoCalib`
        """

        orderPlus1 = self.chebyshevOrder + 1
        pars = np.zeros((orderPlus1, orderPlus1))

        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0.0, 0.0),
                               lsst.geom.Point2I(*xyMax))
        # Take the zeropoint, apply the absolute relative calibration offset,
        # and whatever flat-field scaling was applied
        pars[:, :] = (coefficients.reshape(orderPlus1, orderPlus1) *
                      (offset * units.ABmag).to_value(units.nJy) * scaling)

        field = afwMath.ChebyshevBoundedField(bbox, pars)
        calibMean = field.mean()

        calibErr = (np.log(10.) / 2.5) * calibMean * err

        photoCalib = afwImage.PhotoCalib(field, calibErr)

        return photoCalib
Пример #3
0
    def _getChebyshevBoundedField(self,
                                  coefficients,
                                  xyMax,
                                  offset=0.0,
                                  scaling=1.0):
        """
        Make a ChebyshevBoundedField from fgcm coefficients, with optional offset
        and scaling.

        Parameters
        ----------
        coefficients: `numpy.array`
           Flattened array of chebyshev coefficients
        xyMax: `list` of length 2
           Maximum x and y of the chebyshev bounding box
        offset: `float`, optional
           Absolute calibration offset.  Default is 0.0
        scaling: `float`, optional
           Flat scaling value from fgcmBuildStars.  Default is 1.0

        Returns
        -------
        boundedField: `lsst.afw.math.ChebyshevBoundedField`
        """

        orderPlus1 = int(np.sqrt(coefficients.size))
        pars = np.zeros((orderPlus1, orderPlus1))

        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0.0, 0.0),
                               lsst.geom.Point2I(*xyMax))

        pars[:, :] = (coefficients.reshape(orderPlus1, orderPlus1) *
                      (10.**(offset / -2.5)) * scaling)

        boundedField = afwMath.ChebyshevBoundedField(bbox, pars)

        return boundedField
    def testCoaddApCorrMap(self):
        """Check that we can create and use a coadd ApCorrMap."""
        coaddBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 100))
        scale = 5.0e-5*afwGeom.degrees
        cdMatrix = afwGeom.makeCdMatrix(scale=scale)
        crval = afwGeom.SpherePoint(0.0, 0.0, afwGeom.degrees)
        center = afwGeom.Point2D(afwGeom.Extent2D(coaddBox.getDimensions())*0.5)
        coaddWcs = afwGeom.makeSkyWcs(crpix=afwGeom.Point2D(0, 0), crval=crval, cdMatrix=cdMatrix)
        schema = afwTable.ExposureTable.makeMinimalSchema()
        weightKey = schema.addField("customweightname", type="D", doc="Coadd weight")
        catalog = afwTable.ExposureCatalog(schema)

        # Non-overlapping
        num = 5
        inputBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(10, 10))
        validBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(7, 7))
        pointList = []
        pointListValid = []

        for i in range(num):
            value = np.array([[1]], dtype=float)  # Constant with value = i+1
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value*(i + 1))
            apCorrMap.set("only", bf)

            point = afwGeom.Point2D(0, 0) - afwGeom.Extent2D(coaddBox.getDimensions())*(i+0.5)/num
            wcs = afwGeom.makeSkyWcs(crpix=point, crval=crval, cdMatrix=cdMatrix)
            center = afwGeom.Box2D(inputBox).getCenter()
            pointList.append(coaddWcs.skyToPixel(wcs.pixelToSky(center)))

            # This point will only be valid for the second overlapping record
            pointValid = center + afwGeom.Extent2D(4, 4)
            pointListValid.append(coaddWcs.skyToPixel(wcs.pixelToSky(pointValid)))

            # A record with the valid polygon defining a limited region
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 1)
            record['id'] = i
            record.setValidPolygon(afwGeom.Polygon(afwGeom.Box2D(validBox)))
            catalog.append(record)

            # An overlapping record with the whole region as valid
            record = catalog.getTable().makeRecord()
            record.setWcs(wcs)
            record.setBBox(inputBox)
            apCorrMap = afwImage.ApCorrMap()
            bf = afwMath.ChebyshevBoundedField(inputBox, value*(i + 2))
            apCorrMap.set("only", bf)
            record.setApCorrMap(apCorrMap)
            record.set(weightKey, i + 2)
            record['id'] = i + num
            record.setValidPolygon(afwGeom.Polygon(afwGeom.Box2D(inputBox)))
            catalog.append(record)

        apCorrMap = measAlg.makeCoaddApCorrMap(catalog, coaddBox, coaddWcs, "customweightname")
        # This will test a point where both records contribute
        self.assertApCorrMap(apCorrMap, pointList)
        # Only the second record will be valid for this point
        self.assertApCorrMapValid(apCorrMap, pointListValid)

        filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "coaddApCorrMap.fits")
        exposure = afwImage.ExposureF(1, 1)
        exposure.getInfo().setApCorrMap(apCorrMap)
        exposure.writeFits(filename)
        exposure = afwImage.ExposureF(filename)
        self.assertApCorrMap(exposure.getInfo().getApCorrMap(), pointList)
        self.assertApCorrMapValid(exposure.getInfo().getApCorrMap(), pointListValid)
        os.unlink(filename)
Пример #5
0
    def _outputZeropoints(self, butler, offsets):
        """
        Output the zeropoints in jointcal_photoCalib format.

        Parameters
        ----------
        butler: lsst.daf.persistence.Butler
        """

        self.log.info("Outputting jointcal_photoCalib objects")

        zptCat = butler.get('fgcmZeropoints', fgcmcycle=self.useCycle)
        visitCat = butler.get('fgcmVisitCatalog')

        # Only output those that we have a calibration
        selected = (zptCat['fgcmflag'] < 16)

        # Get the mapping from filtername to dataId filter name
        filterMapping = {}
        nFound = 0
        for rec in zptCat[selected]:
            if rec['filtername'] in filterMapping:
                continue
            dataId = {
                self.visitDataRefName: int(rec['visit']),
                self.ccdDataRefName: int(rec['ccd'])
            }
            dataRef = butler.dataRef('raw', dataId=dataId)
            filterMapping[rec['filtername']] = dataRef.dataId['filter']
            nFound += 1
            if nFound == len(self.filterToBand):
                break

        # Get a mapping from filtername to the offsets
        offsetMapping = {}
        for f in self.filterToBand:
            offsetMapping[f] = offsets[self.bands.index(self.filterToBand[f])]

        # Get a mapping from "ccd" to the ccd index used for the scaling
        camera = butler.get('camera')
        ccdMapping = {}
        for ccdIndex, detector in enumerate(camera):
            ccdMapping[detector.getId()] = ccdIndex

        # And a mapping to get the flat-field scaling values
        scalingMapping = {}
        for rec in visitCat:
            scalingMapping[rec['visit']] = rec['scaling']

        # Make a fixed variable to hold the parameters to build a ChebyshevBoundedField
        orderPlus1 = self.chebyshevOrder + 1

        pars = np.zeros((orderPlus1, orderPlus1))

        for rec in zptCat[selected]:

            if self.superStarSubCcd:
                # Spatially varying zeropoint
                bbox = lsst.geom.Box2I(
                    lsst.geom.Point2I(0.0, 0.0),
                    lsst.geom.Point2I(*rec['fgcmfzptchebxymax']))

                # Take the zeropoint, apply the absolute relative calibration offset,
                # and whatever flat-field scaling was applied
                pars[:, :] = (
                    rec['fgcmfzptcheb'].reshape(orderPlus1, orderPlus1) *
                    10.**(offsetMapping[rec['filtername']] / (-2.5)) *
                    scalingMapping[rec['visit']][ccdMapping[rec['ccd']]])

                # Apply absolute relative calibration offset to 0/0 term

                field = afwMath.ChebyshevBoundedField(bbox, pars)
                calibMean = field.mean()

                calibErr = (np.log(10.) / 2.5) * calibMean * rec['fgcmzpterr']

                photoCalib = afwImage.PhotoCalib(field, calibErr)

            else:
                # Spatially constant zeropoint

                # Take the zeropoint, apply the absolute relative calibration offset,
                # and whatever flat-field scaling was applied

                calibMean = (
                    10.**(rec['fgcmzpt'] / (-2.5)) *
                    10.**(offsetMapping[rec['filtername']] / (-2.5)) *
                    scalingMapping[rec['visit']][ccdMapping[rec['ccd']]])
                calibErr = (np.log(10.) / 2.5) * calibMean * rec['fgcmzpterr']
                photoCalib = afwImage.PhotoCalib(calibMean, calibErr)

            butler.put(photoCalib,
                       'jointcal_photoCalib',
                       dataId={
                           self.visitDataRefName: int(rec['visit']),
                           self.ccdDataRefName: int(rec['ccd']),
                           'filter': filterMapping[rec['filtername']],
                           'tract': 0
                       })

        self.log.info("Done outputting jointcal_photoCalib objects")
    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)