Пример #1
0
    def test(self):
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("ccd", int, doc="CCD number")
        schema.addField("visit", long, doc="Visit number")
        schema.addField("goodpix", int, doc="Number of good pixels")
        schema.addField("weight", float, doc="Weighting for this CCD")
        ccds = afwTable.ExposureCatalog(schema)

        wcs = afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees),
                               afwGeom.Point2D(0.0, 0.0), 1.0e-4, 0.0, 0.0, 1.0e-4)

        new = ccds.addNew()
        new.set("id", 0)
        new.set("bbox.min", afwGeom.Point2I(0,0))
        new.set("bbox.max", afwGeom.Point2I(1024,1024))

        # The following lines are critical for reproducing the bug, because
        # the code is reading a double starting at the 'ccd' (offset 24), and
        # it sees a zero (from the zero in 'ccd' and the leading zeros in 'visit').
        new.set("ccd", 0)
        new.set("visit", 6789)

        new.set("goodpix", 987654321)
        new.set("weight", 1.0)
        new.setPsf(measAlg.SingleGaussianPsf(23, 23, 2.345))
        new.setWcs(wcs)

        # In the presence of the bug, the following fails with:
        # LsstCppException: 0: lsst::pex::exceptions::RuntimeErrorException thrown at src/CoaddPsf.cc:134 in lsst::afw::geom::Point2D lsst::meas::algorithms::{anonymous}::computeAveragePosition(const ExposureCatalog&, const lsst::afw::image::Wcs&, lsst::afw::table::Key<double>)
        # 0: Message: Could not find a valid average position for CoaddPsf
        measAlg.CoaddPsf(ccds, wcs)
Пример #2
0
 def testTicket2872(self):
     """Test that CoaddPsf.getAveragePosition() is always a position at which
     we can call computeImage().
     """
     schema = afwTable.ExposureTable.makeMinimalSchema()
     weightKey = schema.addField("weight",
                                 type=float,
                                 doc="photometric weight")
     catalog = afwTable.ExposureCatalog(schema)
     cdelt = (0.2 * afwGeom.arcseconds).asDegrees()
     wcs = afwImage.makeWcs(
         afwCoord.IcrsCoord(afwGeom.Point2D(45.0, 45.0), afwGeom.degrees),
         afwGeom.Point2D(50, 50), cdelt, 0.0, 0.0, cdelt)
     kernel = measAlg.DoubleGaussianPsf(7, 7, 2.0).getKernel()
     psf1 = measAlg.KernelPsf(kernel, afwGeom.Point2D(0, 50))
     psf2 = measAlg.KernelPsf(kernel, afwGeom.Point2D(100, 50))
     record1 = catalog.addNew()
     record1.setPsf(psf1)
     record1.setWcs(wcs)
     record1.setD(weightKey, 1.0)
     record1.setBBox(
         afwGeom.Box2I(afwGeom.Point2I(-40, 0), afwGeom.Point2I(40, 100)))
     record2 = catalog.addNew()
     record2.setPsf(psf2)
     record2.setWcs(wcs)
     record2.setD(weightKey, 1.0)
     record2.setBBox(
         afwGeom.Box2I(afwGeom.Point2I(60, 0), afwGeom.Point2I(140, 100)))
     coaddPsf = measAlg.CoaddPsf(catalog, wcs)
     naiveAvgPos = afwGeom.Point2D(50, 50)
     self.assertRaises(pexExceptions.InvalidParameterError,
                       coaddPsf.computeKernelImage, naiveAvgPos)
     # important test is that this doesn't throw:
     coaddPsf.computeKernelImage()
Пример #3
0
    def test(self):
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("ccd", np.int32, doc="CCD number")
        schema.addField("visit", np.int32, doc="Visit number")
        schema.addField("goodpix", np.int32, doc="Number of good pixels")
        schema.addField("weight", float, doc="Weighting for this CCD")
        ccds = afwTable.ExposureCatalog(schema)

        wcs = afwImage.makeWcs(afwCoord.Coord(0.0*afwGeom.degrees, 0.0*afwGeom.degrees),
                               afwGeom.Point2D(0.0, 0.0), 1.0e-4, 0.0, 0.0, 1.0e-4)

        new = ccds.addNew()
        new.set("id", 0)
        new.set("bbox_min_x", 0)
        new.set("bbox_min_y", 0)
        new.set("bbox_max_x", 1024)
        new.set("bbox_max_y", 1024)

        # The following lines are critical for reproducing the bug, because
        # the code is reading a double starting at the 'ccd' (offset 24), and
        # it sees a zero (from the zero in 'ccd' and the leading zeros in 'visit').
        new.set("ccd", 0)
        new.set("visit", 6789)

        new.set("goodpix", 987654321)
        new.set("weight", 1.0)
        new.setPsf(measAlg.SingleGaussianPsf(23, 23, 2.345))
        new.setWcs(wcs)

        # In the presence of the bug, the following fails with
        # lsst::pex::exceptions::RuntimeError thrown in src/CoaddPsf.cc
        # with message: "Could not find a valid average position for CoaddPsf"
        measAlg.CoaddPsf(ccds, wcs)
Пример #4
0
    def runQuantum(self, butlerQC, inputRefs, outputRefs):
        visit = butlerQC.quantum.dataId['visit']

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField('visit', type='L', doc='visit number')

        metadata = dafBase.PropertyList()
        metadata.add("COMMENT", "Catalog id is detector id, sorted")
        metadata.add("COMMENT", "Only detectors with data have entries")

        photoCalibCat = afwTable.ExposureCatalog(schema)
        photoCalibCat.setMetadata(metadata)
        photoCalibCat.reserve(len(inputRefs.photoCalibList))

        photoCalibList = butlerQC.get(inputRefs.photoCalibList)
        for dataRef in photoCalibList:
            detector = dataRef.dataId['detector']
            photoCalib = dataRef.get()
            rec = photoCalibCat.addNew()
            rec['id'] = detector
            rec['visit'] = visit
            rec.setPhotoCalib(photoCalib)

        photoCalibCat.sort()

        butlerQC.put(photoCalibCat, outputRefs.photoCalibGlobalCatalog)
Пример #5
0
    def testValidPolygonPsf(self):
        """Test that we can use the validPolygon on exposures in the coadd psf"""
        print "ValidPolygonTest"
        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Each of the 9 has its peculiar Psf, Wcs, weight, bounding box, and valid region.
        for i in range(1, 10, 1):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)
            record.setPsf(psf)
            crpix = afwGeom.PointD(1000 - 10.0 * i, 1000.0 - 10.0 * i)
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

            record.setWcs(wcs)
            record['weight'] = 1.0 * (i + 1)
            record['id'] = i
            bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(1000, 1000))
            record.setBBox(bbox)
            validPolygon_bbox = afwGeom.Box2D(
                afwGeom.Point2D(0, 0), afwGeom.Extent2D(i * 100, i * 100))
            validPolygon = Polygon(validPolygon_bbox)
            record.setValidPolygon(validPolygon)
            mycatalog.append(record)

        # Create the coaddpsf and check at three different points to ensure that the validPolygon is working
        mypsf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(50, 50), True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(50, 50))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))

        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(500, 500),
                                                 True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(500, 500))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))

        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(850, 850),
                                                 True)
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(850, 850))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))
    def testCreate(self):
        """Check that we can create a CoaddPsf with 9 elements"""
        print "CreatePsfTest"
        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        #also test that the weight field name is correctly observed
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("customweightname", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Each of the 9 has its peculiar Psf, Wcs, weight, and bounding box.
        for i in range(1, 10, 1):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)
            record.setPsf(psf)
            crpix = afwGeom.PointD(i * 1000.0, i * 1000.0)
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

            record.setWcs(wcs)
            record['customweightname'] = 1.0 * (i + 1)
            record['id'] = i
            bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(i * 1000, i * 1000))
            record.setBBox(bbox)
            mycatalog.append(record)

        #create the coaddpsf
        mypsf = measAlg.CoaddPsf(mycatalog, wcsref, 'customweightname')

        # check to be sure that we got the right number of components, in the right order
        self.assertTrue(mypsf.getComponentCount() == 9)
        for i in range(1, 10, 1):
            wcs = mypsf.getWcs(i - 1)
            psf = mypsf.getPsf(i - 1)
            bbox = mypsf.getBBox(i - 1)
            weight = mypsf.getWeight(i - 1)
            id = mypsf.getId(i - 1)
            self.assertTrue(i == id)
            self.assertTrue(weight == 1.0 * (i + 1))
            self.assertTrue(bbox.getBeginX() == 0)
            self.assertTrue(bbox.getBeginY() == 0)
            self.assertTrue(bbox.getEndX() == 1000 * i)
            self.assertTrue(bbox.getEndY() == 1000 * i)
            self.assertTrue(wcs.getPixelOrigin().getX() == (1000.0 * i))
            self.assertTrue(wcs.getPixelOrigin().getY() == (1000.0 * i))
            m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments(
                psf, afwGeom.Point2D(0, 0))
            self.assertTrue(testRelDiff(i * i, mxx, .01))
            self.assertTrue(testRelDiff(i * i, myy, .01))
    def setUp(self):
        scale = 5.55555555e-05*lsst.geom.degrees
        self.cdMatrix = afwGeom.makeCdMatrix(scale=scale, flipX=True)
        self.crpix = lsst.geom.PointD(1000, 1000)
        self.crval = lsst.geom.SpherePoint(0.0, 0.0, lsst.geom.degrees)
        self.wcsref = afwGeom.makeSkyWcs(crpix=self.crpix, crval=self.crval, cdMatrix=self.cdMatrix)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        self.weightKey = schema.addField("weight", type="D", doc="Coadd weight")
        self.mycatalog = afwTable.ExposureCatalog(schema)
Пример #8
0
 def testExposureRecordPersistence(self):
     """Test that the ValidPolygon is saved with an ExposureRecord"""
     with lsst.utils.tests.getTempFilePath(".fits") as filename:
         cat1 = afwTable.ExposureCatalog(
             afwTable.ExposureTable.makeMinimalSchema())
         record1 = cat1.addNew()
         record1.setValidPolygon(self.polygon)
         cat1.writeFits(filename)
         cat2 = afwTable.ExposureCatalog.readFits(filename)
         record2 = cat2[0]
         polygon2 = record2.getValidPolygon()
         self.assertEqual(self.polygon, polygon2)
Пример #9
0
 def testExposureRecordPersistence(self):
     """Test that the ValidPolygon is saved with an ExposureRecord"""
     filename = "testValidPolygon.fits"
     cat1 = afwTable.ExposureCatalog(afwTable.ExposureTable.makeMinimalSchema())
     record1 = cat1.addNew()
     record1.setValidPolygon(self.polygon)
     cat1.writeFits(filename)
     cat2 = afwTable.ExposureCatalog.readFits(filename)
     record2 = cat2[0]
     polygon2 = record2.getValidPolygon()
     self.assertEqual(self.polygon, polygon2)
     os.remove(filename)
Пример #10
0
    def _constructPsf(self, mapperResults, exposure):
        """Construct a CoaddPsf based on PSFs from individual subExposures

        Currently uses (and returns) a CoaddPsf. TBD if we want to
        create a custom subclass of CoaddPsf to differentiate it.

        Parameters
        ----------
        mapperResults : `list`
            list of `pipeBase.Struct` returned by `ImageMapper.run`.
            For this to work, each element of `mapperResults` must contain
            a `subExposure` element, from which the component Psfs are
            extracted (thus the reducerTask cannot have
            `reduceOperation = 'none'`.
        exposure : `lsst.afw.image.Exposure`
            the original exposure which is used here solely for its
            bounding-box and WCS.

        Returns
        -------
        psf : `lsst.meas.algorithms.CoaddPsf`
            A psf constructed from the PSFs of the individual subExposures.
        """
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # We're just using the exposure's WCS (assuming that the subExposures'
        # WCSs are the same, which they better be!).
        wcsref = exposure.getWcs()
        for i, res in enumerate(mapperResults):
            record = mycatalog.getTable().makeRecord()
            if 'subExposure' in res.getDict():
                subExp = res.subExposure
                if subExp.getWcs() != wcsref:
                    raise ValueError(
                        'Wcs of subExposure is different from exposure')
                record.setPsf(subExp.getPsf())
                record.setWcs(subExp.getWcs())
                record.setBBox(subExp.getBBox())
            elif 'psf' in res.getDict():
                record.setPsf(res.psf)
                record.setWcs(wcsref)
                record.setBBox(res.bbox)
            record['weight'] = 1.0
            record['id'] = i
            mycatalog.append(record)

        # create the coaddpsf
        psf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')
        return psf
Пример #11
0
    def setUp(self):
        self.cd11 = 5.55555555e-05
        self.cd12 = 0.0
        self.cd21 = 0.0
        self.cd22 = 5.55555555e-05
        self.crval1 = 0.0
        self.crval2 = 0.0
        self.crpix = afwGeom.PointD(1000, 1000)
        self.crval = afwCoord.Coord(afwGeom.Point2D(self.crval1, self.crval2))
        self.wcsref = afwImage.makeWcs(self.crval, self.crpix, self.cd11, self.cd12, self.cd21, self.cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        self.weightKey = schema.addField("weight", type="D", doc="Coadd weight")
        self.mycatalog = afwTable.ExposureCatalog(schema)
Пример #12
0
    def testCreate(self):
        """Check that we can create a CoaddPsf with 9 elements."""
        print("CreatePsfTest")

        # also test that the weight field name is correctly observed
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("customweightname", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Each of the 9 has its peculiar Psf, Wcs, weight, and bounding box.
        for i in range(1, 10, 1):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0)
            record.setPsf(psf)
            crpix = lsst.geom.PointD(i * 1000.0, i * 1000.0)
            wcs = afwGeom.makeSkyWcs(crpix=crpix,
                                     crval=self.crval,
                                     cdMatrix=self.cdMatrix)

            record.setWcs(wcs)
            record['customweightname'] = 1.0 * (i + 1)
            record['id'] = i
            bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                                   lsst.geom.Extent2I(i * 1000, i * 1000))
            record.setBBox(bbox)
            mycatalog.append(record)

        # create the coaddpsf
        mypsf = measAlg.CoaddPsf(mycatalog, self.wcsref, 'customweightname')

        # check to be sure that we got the right number of components, in the right order
        self.assertEqual(mypsf.getComponentCount(), 9)
        for i in range(1, 10, 1):
            wcs = mypsf.getWcs(i - 1)
            psf = mypsf.getPsf(i - 1)
            bbox = mypsf.getBBox(i - 1)
            weight = mypsf.getWeight(i - 1)
            id = mypsf.getId(i - 1)
            self.assertEqual(i, id)
            self.assertEqual(weight, 1.0 * (i + 1))
            self.assertEqual(bbox.getBeginX(), 0)
            self.assertEqual(bbox.getBeginY(), 0)
            self.assertEqual(bbox.getEndX(), 1000 * i)
            self.assertEqual(bbox.getEndY(), 1000 * i)
            self.assertAlmostEqual(wcs.getPixelOrigin().getX(), (1000.0 * i))
            self.assertAlmostEqual(wcs.getPixelOrigin().getY(), (1000.0 * i))
            m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments(
                psf, lsst.geom.Point2D(0, 0))
            self.assertAlmostEqual(i * i, mxx, delta=0.01)
            self.assertAlmostEqual(i * i, myy, delta=0.01)
Пример #13
0
    def getCoaddPsf(self, exposure):
        import lsst.afw.table as afwTable
        import lsst.afw.image as afwImage
        import lsst.afw.math as afwMath
        import lsst.afw.geom as afwGeom
        import lsst.meas.algorithms as measAlg

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        wcsref = exposure.getWcs()
        extentX = int(exposure.getWidth() * 0.05)
        extentY = int(exposure.getHeight() * 0.05)
        ind = 0
        for x in np.linspace(extentX, exposure.getWidth() - extentX, 10):
            for y in np.linspace(extentY, exposure.getHeight() - extentY, 10):
                x = int(x)
                y = int(y)
                image = self.getImage(x, y)

                psf = afwImage.ImageD(image.shape[0], image.shape[1])
                psf.getArray()[:, :] = image
                psfK = afwMath.FixedKernel(psf)
                psf = measAlg.KernelPsf(psfK)

                record = mycatalog.getTable().makeRecord()
                record.setPsf(psf)
                record.setWcs(wcsref)

                bbox = afwGeom.Box2I(
                    afwGeom.Point2I(
                        int(np.floor(x - extentX)) - 5,
                        int(np.floor(y - extentY)) - 5),
                    afwGeom.Point2I(
                        int(np.floor(x + extentX)) + 5,
                        int(np.floor(y + extentY)) + 5))
                record.setBBox(bbox)
                record['weight'] = 1.0
                record['id'] = ind
                ind += 1
                mycatalog.append(record)

        # create the coaddpsf
        psf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')
        return psf
    def testDefaultSize(self):
        """Test of both default size and specified size"""
        print "DefaultSizeTest"
        sigma0 = 5
        # set the peak of the outer guassian to 0 so this is really a single gaussian.

        psf = measAlg.DoubleGaussianPsf(60, 60, 1.5 * sigma0, 1, 0.0)

        if False and display:
            im = psf.computeImage(afwGeom.PointD(xwid / 2, ywid / 2))
            ds9.mtv(im, title="N(%g) psf" % sigma0, frame=0)

        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        # Now make the catalog
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)
        record = mycatalog.getTable().makeRecord()
        psf = measAlg.DoubleGaussianPsf(100, 100, 10.0, 1.00, 1.0)
        record.setPsf(psf)
        wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)
        record.setWcs(wcs)
        record['weight'] = 1.0
        record['id'] = 1
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Extent2I(2000, 2000))
        record.setBBox(bbox)
        mycatalog.append(record)

        mypsf = measAlg.CoaddPsf(mycatalog, wcsref)  #, 'weight')

        m1coadd, m2coadd = getCoaddSecondMoments(mypsf, afwGeom.Point2D(0, 0))
        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(1000, 1000))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
        self.assertTrue(testRelDiff(m2, m2coadd, .01))
    def testFractionalPixel(self):
        """Check that we can create a CoaddPsf with 10 elements"""
        print "FractionalPixelTest"
        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        cd21 = 5.55555555e-05
        cd12 = 5.55555555e-05
        cd11 = 0.0
        cd22 = 0.0

        wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)
        # make a single record with an oblong Psf
        record = mycatalog.getTable().makeRecord()
        psf = makeBiaxialGaussianPsf(100, 100, 6.0, 6.0, 0.0)
        record.setPsf(psf)
        record.setWcs(wcs)
        record['weight'] = 1.0
        record['id'] = 1
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Extent2I(2000, 2000))
        record.setBBox(bbox)
        mycatalog.append(record)
        mypsf = measAlg.CoaddPsf(mycatalog, wcsref)
        img = psf.computeImage(afwGeom.PointD(0.25, 0.75))
        img = psf.computeImage(afwGeom.PointD(0.25, 0.75))
        img = psf.computeImage(afwGeom.PointD(1000, 1000))
        m0, xbar, ybar, mxx, myy, x0, y0 = getPsfMoments(
            psf, afwGeom.Point2D(0.25, 0.75))
        cm0, cxbar, cybar, cmxx, cmyy, cx0, cy0 = getPsfMoments(
            mypsf, afwGeom.Point2D(0.25, 0.75))
        self.assertTrue(testRelDiff(x0 + xbar, cx0 + cxbar, .01))
        self.assertTrue(testRelDiff(y0 + ybar, cy0 + cybar, .01))
Пример #16
0
    def testGoodPix(self):
        """Demonstrate that we can goodPix information in the CoaddPsf"""
        cd11, cd12, cd21, cd22 = 5.55555555e-05, 0.0, 0.0, 5.55555555e-05
        crval1, crval2 = 0.0, 0.0
        bboxSize = afwGeom.Extent2I(2000, 2000)
        crpix = afwGeom.PointD(bboxSize / 2.0)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        schema.addField("goodpix", type="I", doc="Number of good pixels")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Create several records, each with its own peculiar center and numGoodPixels.
        # Each PSF has the same shape and size, and the position offsets are small
        # relative to the FWHM, in order to make it easy to predict the resulting
        # weighted mean position.
        xwsum = 0
        ywsum = 0
        wsum = 0
        for i, (xOff, yOff, numGoodPix) in enumerate((
            (30.0, -20.0, 25),
            (32.0, -21.0, 10),
            (28.0, -19.0, 30),
        )):
            xwsum -= xOff * numGoodPix
            ywsum -= yOff * numGoodPix
            wsum += numGoodPix
            record = mycatalog.getTable().makeRecord()
            record.setPsf(measAlg.DoubleGaussianPsf(25, 25, 10, 1.00, 0.0))
            offPix = crpix + afwGeom.Extent2D(xOff, yOff)
            wcs = afwImage.makeWcs(crval, offPix, cd11, cd12, cd21, cd22)
            record.setWcs(wcs)
            record['weight'] = 1.0
            record['id'] = i
            record['goodpix'] = numGoodPix
            record.setBBox(afwGeom.Box2I(afwGeom.Point2I(0, 0), bboxSize))
            mycatalog.append(record)

        mypsf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')
        predPos = afwGeom.Point2D(xwsum / wsum, ywsum / wsum)
        self.assertPairsNearlyEqual(predPos, mypsf.getAveragePosition())
Пример #17
0
    def testValidPolygonPsf(self):
        """Demonstrate that we can use the validPolygon on Exposures in the CoaddPsf"""
        cd11, cd12, cd21, cd22 = 5.55555555e-05, 0.0, 0.0, 5.55555555e-05
        crval1, crval2 = 0.0, 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        # Create 9 separate records, each with its own peculiar Psf, Wcs,
        # weight, bounding box, and valid region.
        for i in range(1, 10):
            record = mycatalog.getTable().makeRecord()
            record.setPsf(measAlg.DoubleGaussianPsf(100, 100, i, 1.00, 0.0))
            crpix = afwGeom.PointD(1000 - 10.0 * i, 1000.0 - 10.0 * i)
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)
            record.setWcs(wcs)
            record['weight'] = 1.0 * (i + 1)
            record['id'] = i
            record.setBBox(
                afwGeom.Box2I(afwGeom.Point2I(0, 0),
                              afwGeom.Extent2I(1000, 1000)))
            validPolygon = Polygon(
                afwGeom.Box2D(afwGeom.Point2D(0, 0),
                              afwGeom.Extent2D(i * 100, i * 100)))
            record.setValidPolygon(validPolygon)
            mycatalog.append(record)

        # Create the CoaddPsf and check at three different points to ensure that the validPolygon is working
        mypsf = measAlg.CoaddPsf(mycatalog, wcsref, 'weight')

        for position in [
                afwGeom.Point2D(50, 50),
                afwGeom.Point2D(500, 500),
                afwGeom.Point2D(850, 850)
        ]:
            m1coadd, m2coadd = getCoaddSecondMoments(mypsf, position, True)
            m1, m2 = getPsfSecondMoments(mypsf, position)
            self.assertAlmostEqual(m1, m1coadd, delta=0.01)
            self.assertAlmostEqual(m2, m2coadd, delta=0.01)
    def testWeight(self):
        """Check that we can measure a single Gaussian's attributes"""
        print "WeightTest"
        sigma0 = 5
        # set the peak of the outer guassian to 0 so this is really a single gaussian.

        psf = measAlg.DoubleGaussianPsf(60, 60, 1.5 * sigma0, 1, 0.0)

        if False and display:
            im = psf.computeImage(afwGeom.PointD(xwid / 2, ywid / 2))
            ds9.mtv(im, title="N(%g) psf" % sigma0, frame=0)

        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        sigma = [5, 6, 7, 8]  # 5 pixels is the same as a sigma of 1 arcsec.

        # lay down a simple pattern of four ccds, set in a pattern of 1000 pixels around the center
        offsets = [(1999, 1999), (1999, 0), (0, 0), (0, 1999)]

        #       Imagine a ccd in each of positions +-1000 pixels from the center
        for i in range(4):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, sigma[i], 1.00, 0.0)
            record.setPsf(psf)
            crpix = afwGeom.PointD(offsets[i][0], offsets[i][1])
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

            # print out the coorinates of this supposed 2000x2000 ccd in wcsref coordinates
            record.setWcs(wcs)
            record['weight'] = 1.0 * (i + 1)
            record['id'] = i
            bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(2000, 2000))
            record.setBBox(bbox)
            mycatalog.append(record)

        mypsf = measAlg.CoaddPsf(mycatalog, wcsref)  #, 'weight')

        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(1000, 1000))
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(1000, 1000))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))

        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(1000, 1001))
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(1000, 1001))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))

        m1, m2 = getCoaddSecondMoments(mypsf, afwGeom.Point2D(1001, 1000))
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(1001, 1000))
        self.assertTrue(testRelDiff(m1, m1coadd, .01))
Пример #19
0
matchedCat = []
truthPositions = []
for i, cat in enumerate(catalogs):
    print("Matching catalog {}".format(i))
    match, positions = matchCatalogs(cat)
    matchedCat.append(match)
    truthPositions.append(positions)

truthPositions = np.array(truthPositions)

stamps = []
replaced = []
variance = []
filteredCat = []
psfList = []
expCat = afwTable.ExposureCatalog(afwTable.ExposureTable.makeMinimalSchema())

place = 0
for im, cat, positions in zip(images, matchedCat, truthPositions):
    print("processing {}".format(place))
    result = filterObjects(im, cat, positions, expCat)
    stamps += result[0]
    replaced += result[1]
    variance += result[2]
    filteredCat.append(result[3])
    psfList += result[4]
    place += 1

finalCatalog = afwTable.SourceCatalog(filteredCat[0].schema)
finalCatalog.reserve(len(stamps))
for n in range(len(filteredCat)):
Пример #20
0
    def setUp(self):
        tract = 0
        band = 'r'
        patch = 0
        visits = [100, 101]
        # Good to test crossing 0.
        ra_center = 0.0
        dec_center = -45.0
        pixel_scale = 0.2
        coadd_zp = 27.0

        # Generate a mock skymap with one patch
        config = DiscreteSkyMap.ConfigClass()
        config.raList = [ra_center]
        config.decList = [dec_center]
        config.radiusList = [150 * pixel_scale / 3600.]
        config.patchInnerDimensions = (350, 350)
        config.patchBorder = 50
        config.tractOverlap = 0.0
        config.pixelScale = pixel_scale
        sky_map = DiscreteSkyMap(config)

        visit_summaries = [
            makeMockVisitSummary(visit,
                                 ra_center=ra_center,
                                 dec_center=dec_center) for visit in visits
        ]
        visit_summary_refs = [
            MockVisitSummaryReference(visit_summary, visit)
            for visit_summary, visit in zip(visit_summaries, visits)
        ]
        self.visit_summary_dict = {
            visit: ref.get()
            for ref, visit in zip(visit_summary_refs, visits)
        }

        # Generate an input map.  Note that this does not need to be consistent
        # with the visit_summary projections, we're just tracking values.
        input_map = hsp.HealSparseMap.make_empty(
            nside_coverage=256,
            nside_sparse=32768,
            dtype=hsp.WIDE_MASK,
            wide_mask_maxbits=len(visits) * 2)
        patch_poly = afwGeom.Polygon(
            geom.Box2D(sky_map[tract][patch].getOuterBBox()))
        sph_pts = sky_map[tract].getWcs().pixelToSky(
            patch_poly.convexHull().getVertices())
        patch_poly_radec = np.array([(sph.getRa().asDegrees(),
                                      sph.getDec().asDegrees())
                                     for sph in sph_pts])
        poly = hsp.Polygon(ra=patch_poly_radec[:-1, 0],
                           dec=patch_poly_radec[:-1, 1],
                           value=[0])
        poly_pixels = poly.get_pixels(nside=input_map.nside_sparse)
        # The input map has full coverage for bits 0 and 1
        input_map.set_bits_pix(poly_pixels, [0])
        input_map.set_bits_pix(poly_pixels, [1])

        input_map_ref = MockInputMapReference(input_map,
                                              patch=patch,
                                              tract=tract)
        self.input_map_dict = {patch: input_map_ref}

        coadd = afwImage.ExposureF(sky_map[tract][patch].getOuterBBox(),
                                   sky_map[tract].getWcs())
        instFluxMag0 = 10.**(coadd_zp / 2.5)
        pc = afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0)
        coadd.setPhotoCalib(pc)

        # Mock the coadd input ccd table
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("ccd", type="I")
        schema.addField("visit", type="I")
        schema.addField("weight", type="F")
        ccds = afwTable.ExposureCatalog(schema)
        ccds.resize(2)
        ccds['id'] = np.arange(2)
        ccds['visit'][0] = visits[0]
        ccds['visit'][1] = visits[1]
        ccds['ccd'][0] = 0
        ccds['ccd'][1] = 1
        ccds['weight'] = 10.0
        for ccd_row in ccds:
            summary = self.visit_summary_dict[ccd_row['visit']].find(
                ccd_row['ccd'])
            ccd_row.setWcs(summary.getWcs())
            ccd_row.setPsf(summary.getPsf())
            ccd_row.setBBox(summary.getBBox())
            ccd_row.setPhotoCalib(summary.getPhotoCalib())

        inputs = afwImage.CoaddInputs()
        inputs.ccds = ccds
        coadd.getInfo().setCoaddInputs(inputs)

        coadd_ref = MockCoaddReference(coadd, patch=patch, tract=tract)
        self.coadd_dict = {patch: coadd_ref}

        self.tract = tract
        self.band = band
        self.sky_map = sky_map
        self.input_map = input_map
    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)
Пример #22
0
    def _outputZeropoints(self,
                          camera,
                          zptCat,
                          visitCat,
                          offsets,
                          bands,
                          physicalFilterMap,
                          tract=None):
        """Output the zeropoints in fgcm_photoCalib format.

        Parameters
        ----------
        camera : `lsst.afw.cameraGeom.Camera`
            Camera from the butler.
        zptCat : `lsst.afw.table.BaseCatalog`
            FGCM zeropoint catalog from `FgcmFitCycleTask`.
        visitCat : `lsst.afw.table.BaseCatalog`
            FGCM visitCat from `FgcmBuildStarsTask`.
        offsets : `numpy.array`
            Float array of absolute calibration offsets, one for each filter.
        bands : `list` [`str`]
            List of band names from FGCM output.
        physicalFilterMap : `dict`
            Dictionary of mappings from physical filter to FGCM band.
        tract: `int`, optional
            Tract number to output.  Default is None (global calibration)

        Returns
        -------
        photoCalibCatalogs : `generator` [(`int`, `lsst.afw.table.ExposureCatalog`)]
            Generator that returns (visit, exposureCatalog) tuples.
        """
        # Select visit/ccds where we have a calibration
        # This includes ccds where we were able to interpolate from neighboring
        # ccds.
        cannot_compute = fgcm.fgcmUtilities.zpFlagDict[
            'CANNOT_COMPUTE_ZEROPOINT']
        selected = (((zptCat['fgcmFlag'] & cannot_compute) == 0)
                    & (zptCat['fgcmZptVar'] > 0.0)
                    & (zptCat['fgcmZpt'] > FGCM_ILLEGAL_VALUE))

        # Log warnings for any visit which has no valid zeropoints
        badVisits = np.unique(zptCat['visit'][~selected])
        goodVisits = np.unique(zptCat['visit'][selected])
        allBadVisits = badVisits[~np.isin(badVisits, goodVisits)]
        for allBadVisit in allBadVisits:
            self.log.warning(f'No suitable photoCalib for visit {allBadVisit}')

        # Get a mapping from filtername to the offsets
        offsetMapping = {}
        for f in physicalFilterMap:
            # Not every filter in the map will necesarily have a band.
            if physicalFilterMap[f] in bands:
                offsetMapping[f] = offsets[bands.index(physicalFilterMap[f])]

        # Get a mapping from "ccd" to the ccd index used for the scaling
        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']

        if self.config.doComposeWcsJacobian:
            approxPixelAreaFields = computeApproxPixelAreaFields(camera)

        # The zptCat is sorted by visit, which is useful
        lastVisit = -1
        zptVisitCatalog = None

        metadata = dafBase.PropertyList()
        metadata.add("COMMENT", "Catalog id is detector id, sorted.")
        metadata.add("COMMENT", "Only detectors with data have entries.")

        for rec in zptCat[selected]:
            # Retrieve overall scaling
            scaling = scalingMapping[rec['visit']][ccdMapping[rec['detector']]]

            # The postCalibrationOffset describe any zeropoint offsets
            # to apply after the fgcm calibration.  The first part comes
            # from the reference catalog match (used in testing).  The
            # second part comes from the mean chromatic correction
            # (if configured).
            postCalibrationOffset = offsetMapping[rec['filtername']]
            if self.config.doApplyMeanChromaticCorrection:
                postCalibrationOffset += rec['fgcmDeltaChrom']

            fgcmSuperStarField = self._getChebyshevBoundedField(
                rec['fgcmfZptSstarCheb'], rec['fgcmfZptChebXyMax'])
            # Convert from FGCM AB to nJy
            fgcmZptField = self._getChebyshevBoundedField(
                (rec['fgcmfZptCheb'] * units.AB).to_value(units.nJy),
                rec['fgcmfZptChebXyMax'],
                offset=postCalibrationOffset,
                scaling=scaling)

            if self.config.doComposeWcsJacobian:

                fgcmField = afwMath.ProductBoundedField([
                    approxPixelAreaFields[rec['detector']], fgcmSuperStarField,
                    fgcmZptField
                ])
            else:
                # The photoCalib is just the product of the fgcmSuperStarField and the
                # fgcmZptField
                fgcmField = afwMath.ProductBoundedField(
                    [fgcmSuperStarField, fgcmZptField])

            # The "mean" calibration will be set to the center of the ccd for reference
            calibCenter = fgcmField.evaluate(fgcmField.getBBox().getCenter())
            calibErr = (np.log(10.0) / 2.5) * calibCenter * np.sqrt(
                rec['fgcmZptVar'])
            photoCalib = afwImage.PhotoCalib(calibrationMean=calibCenter,
                                             calibrationErr=calibErr,
                                             calibration=fgcmField,
                                             isConstant=False)

            # Return full per-visit exposure catalogs
            if rec['visit'] != lastVisit:
                # This is a new visit.  If the last visit was not -1, yield
                # the ExposureCatalog
                if lastVisit > -1:
                    # ensure that the detectors are in sorted order, for fast lookups
                    zptVisitCatalog.sort()
                    yield (int(lastVisit), zptVisitCatalog)
                else:
                    # We need to create a new schema
                    zptExpCatSchema = afwTable.ExposureTable.makeMinimalSchema(
                    )
                    zptExpCatSchema.addField('visit',
                                             type='L',
                                             doc='Visit number')

                # And start a new one
                zptVisitCatalog = afwTable.ExposureCatalog(zptExpCatSchema)
                zptVisitCatalog.setMetadata(metadata)

                lastVisit = int(rec['visit'])

            catRecord = zptVisitCatalog.addNew()
            catRecord['id'] = int(rec['detector'])
            catRecord['visit'] = rec['visit']
            catRecord.setPhotoCalib(photoCalib)

        # Final output of last exposure catalog
        # ensure that the detectors are in sorted order, for fast lookups
        zptVisitCatalog.sort()
        yield (int(lastVisit), zptVisitCatalog)
Пример #23
0
def makeMockVisitSummary(visit,
                         ra_center=0.0,
                         dec_center=-45.0,
                         physical_filter='TEST-I',
                         band='i',
                         mjd=59234.7083333334,
                         psf_sigma=3.0,
                         zenith_distance=45.0,
                         zero_point=30.0,
                         sky_background=100.0,
                         sky_noise=10.0,
                         mean_var=100.0,
                         exposure_time=100.0,
                         detector_size=200,
                         pixel_scale=0.2):
    """Make a mock visit summary catalog.

    This will contain two square detectors with the same metadata,
    with a small (20 pixel) gap between the detectors.  There is no
    rotation, as each detector is simply offset in RA from the
    specified boresight.

    Parameters
    ----------
    visit : `int`
        Visit number.
    ra_center : `float`
        Right ascension of the center of the "camera" boresight (degrees).
    dec_center : `float`
        Declination of the center of the "camera" boresight (degrees).
    physical_filter : `str`
        Arbitrary name for the physical filter.
    band : `str`
        Name of the associated band.
    mjd : `float`
        Modified Julian Date.
    psf_sigma : `float`
        Sigma width of Gaussian psf.
    zenith_distance : `float`
        Distance from zenith of the visit (degrees).
    zero_point : `float`
        Constant zero point for the visit (magnitudes).
    sky_background : `float`
        Background level for the visit (counts).
    sky_noise : `float`
        Noise level for the background of the visit (counts).
    mean_var : `float`
        Mean of the variance plane of the visit (counts).
    exposure_time : `float`
        Exposure time of the visit (seconds).
    detector_size : `int`
        Size of each square detector in the visit (pixels).
    pixel_scale : `float`
        Size of the pixel in arcseconds per pixel.

    Returns
    -------
    visit_summary : `lsst.afw.table.ExposureCatalog`
    """
    # We are making a 2 detector "camera"
    n_detector = 2

    schema = ConsolidateVisitSummaryTask()._makeVisitSummarySchema()
    visit_summary = afwTable.ExposureCatalog(schema)
    visit_summary.resize(n_detector)

    bbox = geom.Box2I(x=geom.IntervalI(min=0, max=detector_size - 1),
                      y=geom.IntervalI(min=0, max=detector_size - 1))

    for detector_id in range(n_detector):
        row = visit_summary[detector_id]

        row['id'] = detector_id
        row.setBBox(bbox)
        row['visit'] = visit
        row['physical_filter'] = physical_filter
        row['band'] = band
        row['zenithDistance'] = zenith_distance
        row['zeroPoint'] = zero_point
        row['skyBg'] = sky_background
        row['skyNoise'] = sky_noise
        row['meanVar'] = mean_var

        # Generate a photocalib
        instFluxMag0 = 10.**(zero_point / 2.5)
        row.setPhotoCalib(
            afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0))

        # Generate a WCS and set values accordingly
        crpix = geom.Point2D(detector_size / 2., detector_size / 2.)
        # Create a 20 pixel gap between the two detectors (each offset 10 pixels).
        if detector_id == 0:
            delta_ra = -1.0 * ((detector_size + 10) * pixel_scale /
                               3600.) / np.cos(np.deg2rad(dec_center))
            delta_dec = 0.0
        elif detector_id == 1:
            delta_ra = ((detector_size + 10) * pixel_scale / 3600.) / np.cos(
                np.deg2rad(dec_center))
            delta_dec = 0.0
        crval = geom.SpherePoint(ra_center + delta_ra, dec_center + delta_dec,
                                 geom.degrees)
        cd_matrix = afwGeom.makeCdMatrix(scale=pixel_scale * geom.arcseconds,
                                         orientation=0.0 * geom.degrees)
        wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd_matrix)
        row.setWcs(wcs)

        sph_pts = wcs.pixelToSky(geom.Box2D(bbox).getCorners())
        row['raCorners'] = np.array(
            [float(sph.getRa().asDegrees()) for sph in sph_pts])
        row['decCorners'] = np.array(
            [float(sph.getDec().asDegrees()) for sph in sph_pts])
        sph_pt = wcs.pixelToSky(bbox.getCenter())
        row['ra'] = sph_pt.getRa().asDegrees()
        row['decl'] = sph_pt.getDec().asDegrees()

        # Generate a visitInfo.
        # This does not need to be consistent with the zenith angle in the table,
        # it just needs to be valid and have sufficient information to compute
        # exposure time and parallactic angle.
        date = DateTime(date=mjd, system=DateTime.DateSystem.MJD)
        visit_info = afwImage.VisitInfo(
            exposureId=visit,
            exposureTime=exposure_time,
            date=date,
            darkTime=0.0,
            boresightRaDec=geom.SpherePoint(ra_center, dec_center,
                                            geom.degrees),
            era=45.1 * geom.degrees,
            observatory=Observatory(11.1 * geom.degrees, 0.0 * geom.degrees,
                                    0.333),
            boresightRotAngle=0.0 * geom.degrees,
            rotType=afwImage.RotType.SKY)
        row.setVisitInfo(visit_info)

        # Generate a PSF and set values accordingly
        psf = GaussianPsf(15, 15, psf_sigma)
        row.setPsf(psf)
        psfAvgPos = psf.getAveragePosition()
        shape = psf.computeShape(psfAvgPos)
        row['psfSigma'] = psf.getSigma()
        row['psfIxx'] = shape.getIxx()
        row['psfIyy'] = shape.getIyy()
        row['psfIxy'] = shape.getIxy()
        row['psfArea'] = shape.getArea()

    return visit_summary
Пример #24
0
    def _combineExposureMetadata(self, visit, dataRefs, isGen3=True):
        """Make a combined exposure catalog from a list of dataRefs.

        Parameters
        ----------
        visit : `int`
            Visit identification number
        dataRefs : `list`
            List of calexp dataRefs in visit.  May be list of
            `lsst.daf.persistence.ButlerDataRef` (Gen2) or
            `lsst.daf.butler.DeferredDatasetHandle` (Gen3).
        isGen3 : `bool`, optional
            Specifies if this is a Gen3 list of datarefs.

        Returns
        -------
        visitSummary : `lsst.afw.table.ExposureCatalog`
            Exposure catalog with per-detector summary information.
        """
        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField('visit', type='I', doc='Visit number')
        schema.addField('physical_filter', type='String', size=32, doc='Physical filter')
        schema.addField('band', type='String', size=32, doc='Name of band')
        schema.addField('psfSigma', type='F',
                        doc='PSF model second-moments determinant radius (center of chip) (pixel)')
        schema.addField('psfArea', type='F',
                        doc='PSF model effective area (center of chip) (pixel**2)')
        schema.addField('psfIxx', type='F',
                        doc='PSF model Ixx (center of chip) (pixel**2)')
        schema.addField('psfIyy', type='F',
                        doc='PSF model Iyy (center of chip) (pixel**2)')
        schema.addField('psfIxy', type='F',
                        doc='PSF model Ixy (center of chip) (pixel**2)')
        schema.addField('raCorners', type='ArrayD', size=4,
                        doc='Right Ascension of bounding box corners (degrees)')
        schema.addField('decCorners', type='ArrayD', size=4,
                        doc='Declination of bounding box corners (degrees)')

        cat = afwTable.ExposureCatalog(schema)
        cat.resize(len(dataRefs))

        cat['visit'] = visit

        for i, dataRef in enumerate(dataRefs):
            if isGen3:
                visitInfo = dataRef.get(component='visitInfo')
                filterLabel = dataRef.get(component='filterLabel')
                psf = dataRef.get(component='psf')
                wcs = dataRef.get(component='wcs')
                photoCalib = dataRef.get(component='photoCalib')
                detector = dataRef.get(component='detector')
                bbox = dataRef.get(component='bbox')
                validPolygon = dataRef.get(component='validPolygon')
            else:
                # Note that we need to read the calexp because there is
                # no magic access to the psf except through the exposure.
                gen2_read_bbox = lsst.geom.BoxI(lsst.geom.PointI(0, 0), lsst.geom.PointI(1, 1))
                exp = dataRef.get(datasetType='calexp_sub', bbox=gen2_read_bbox)
                visitInfo = exp.getInfo().getVisitInfo()
                filterLabel = dataRef.get("calexp_filterLabel")
                psf = exp.getPsf()
                wcs = exp.getWcs()
                photoCalib = exp.getPhotoCalib()
                detector = exp.getDetector()
                bbox = dataRef.get(datasetType='calexp_bbox')
                validPolygon = exp.getInfo().getValidPolygon()

            rec = cat[i]
            rec.setBBox(bbox)
            rec.setVisitInfo(visitInfo)
            rec.setWcs(wcs)
            rec.setPhotoCalib(photoCalib)
            rec.setValidPolygon(validPolygon)

            rec['physical_filter'] = filterLabel.physicalLabel if filterLabel.hasPhysicalLabel() else ""
            rec['band'] = filterLabel.bandLabel if filterLabel.hasBandLabel() else ""
            rec.setId(detector.getId())
            shape = psf.computeShape(bbox.getCenter())
            rec['psfSigma'] = shape.getDeterminantRadius()
            rec['psfIxx'] = shape.getIxx()
            rec['psfIyy'] = shape.getIyy()
            rec['psfIxy'] = shape.getIxy()
            im = psf.computeKernelImage(bbox.getCenter())
            # The calculation of effective psf area is taken from
            # meas_base/src/PsfFlux.cc#L112. See
            # https://github.com/lsst/meas_base/blob/
            # 750bffe6620e565bda731add1509507f5c40c8bb/src/PsfFlux.cc#L112
            rec['psfArea'] = np.sum(im.array)/np.sum(im.array**2.)

            sph_pts = wcs.pixelToSky(lsst.geom.Box2D(bbox).getCorners())
            rec['raCorners'][:] = [sph.getRa().asDegrees() for sph in sph_pts]
            rec['decCorners'][:] = [sph.getDec().asDegrees() for sph in sph_pts]

        metadata = dafBase.PropertyList()
        metadata.add("COMMENT", "Catalog id is detector id, sorted.")
        # We are looping over existing datarefs, so the following is true
        metadata.add("COMMENT", "Only detectors with data have entries.")
        cat.setMetadata(metadata)

        cat.sort()
        return cat
Пример #25
0
    def testSimpleGaussian(self):
        """Check that we can measure a single Gaussian's attributes"""
        print "SimpleGaussianTest"
        sigma0 = 5
        # set the peak of the outer guassian to 0 so this is really a single gaussian.

        psf = measAlg.DoubleGaussianPsf(60, 60, 1.5 * sigma0, 1, 0.0)

        # this is the coadd Wcs we want
        cd11 = 5.55555555e-05
        cd12 = 0.0
        cd21 = 0.0
        cd22 = 5.55555555e-05
        crval1 = 0.0
        crval2 = 0.0
        crpix = afwGeom.PointD(1000, 1000)
        crval = afwCoord.Coord(afwGeom.Point2D(crval1, crval2))
        wcsref = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

        schema = afwTable.ExposureTable.makeMinimalSchema()
        schema.addField("weight", type="D", doc="Coadd weight")
        mycatalog = afwTable.ExposureCatalog(schema)

        sigma = [5, 6, 7, 8]  # 5 pixels is the same as a sigma of 1 arcsec.

        # lay down a simple pattern of four ccds, set in a pattern of 1000 pixels around the center
        offsets = [(1999, 1999), (1999, 0), (0, 0), (0, 1999)]

        #       Imagine a ccd in each of positions +-1000 pixels from the center
        for i in range(4):
            record = mycatalog.getTable().makeRecord()
            psf = measAlg.DoubleGaussianPsf(100, 100, sigma[i], 1.00, 1.0)
            record.setPsf(psf)
            crpix = afwGeom.PointD(offsets[i][0], offsets[i][1])
            wcs = afwImage.makeWcs(crval, crpix, cd11, cd12, cd21, cd22)

            # print out the coorinates of this supposed 2000x2000 ccd in wcsref coordinates
            beginCoord = wcs.pixelToSky(0, 0)
            endCoord = wcs.pixelToSky(2000, 2000)
            wcsref.skyToPixel(beginCoord)
            wcsref.skyToPixel(endCoord)
            record.setWcs(wcs)
            record['weight'] = 1.0
            record['id'] = i
            bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                 afwGeom.Extent2I(2000, 2000))
            record.setBBox(bbox)
            mycatalog.append(record)
            #img = psf.computeImage(afwGeom.Point2D(1000,1000), afwGeom.Extent2I(100,100), False, False)
            #img.writeFits("img%d.fits"%i)

        mypsf = measAlg.CoaddPsf(mycatalog, wcsref)  #, 'weight')
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(1000, 1000))

        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(1000, 1000))
        self.assertAlmostEqual(m1, m1coadd, delta=.01)

        m1, m2 = getPsfSecondMoments(mypsf, afwGeom.Point2D(1000, 1001))
        m1coadd, m2coadd = getCoaddSecondMoments(mypsf,
                                                 afwGeom.Point2D(1000, 1001))
        self.assertAlmostEqual(m1, m1coadd, delta=0.01)
Пример #26
0
    def run(self, exposure, sensorRef, templateIdList=None):
        """Retrieve and mosaic a template coadd that overlaps the exposure where
        the template spans multiple tracts.

        The resulting template image will be an average of all the input templates from
        the separate tracts.

        The PSF on the template is created by combining the CoaddPsf on each template image
        into a meta-CoaddPsf.

        Parameters
        ----------
        exposure: `lsst.afw.image.Exposure`
            an exposure for which to generate an overlapping template
        sensorRef : TYPE
            a Butler data reference that can be used to obtain coadd data
        templateIdList : TYPE, optional
            list of data ids (unused)
        Returns
        -------
        result : `struct`
            return a pipeBase.Struct:
            - ``exposure`` : a template coadd exposure assembled out of patches
            - ``sources`` :  None for this subtask
        """

        # Table for CoaddPSF
        tractsSchema = afwTable.ExposureTable.makeMinimalSchema()
        tractKey = tractsSchema.addField('tract',
                                         type=np.int32,
                                         doc='Which tract')
        patchKey = tractsSchema.addField('patch',
                                         type=np.int32,
                                         doc='Which patch')
        weightKey = tractsSchema.addField(
            'weight', type=float, doc='Weight for each tract, should be 1')
        tractsCatalog = afwTable.ExposureCatalog(tractsSchema)

        skyMap = sensorRef.get(datasetType=self.config.coaddName +
                               "Coadd_skyMap")
        expWcs = exposure.getWcs()
        expBoxD = geom.Box2D(exposure.getBBox())
        expBoxD.grow(self.config.templateBorderSize)
        ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())

        centralTractInfo = skyMap.findTract(ctrSkyPos)
        if not centralTractInfo:
            raise RuntimeError("No suitable tract found for central point")

        self.log.info("Central skyMap tract %s" % (centralTractInfo.getId(), ))

        skyCorners = [
            expWcs.pixelToSky(pixPos) for pixPos in expBoxD.getCorners()
        ]
        tractPatchList = skyMap.findTractPatchList(skyCorners)
        if not tractPatchList:
            raise RuntimeError("No suitable tract found")

        self.log.info("All overlapping skyMap tracts %s" %
                      ([a[0].getId() for a in tractPatchList]))

        # Move central tract to front of the list and use as the reference
        tracts = [tract[0].getId() for tract in tractPatchList]
        centralIndex = tracts.index(centralTractInfo.getId())
        tracts.insert(0, tracts.pop(centralIndex))
        tractPatchList.insert(0, tractPatchList.pop(centralIndex))

        coaddPsf = None
        coaddFilter = None
        nPatchesFound = 0

        maskedImageList = []
        weightList = []

        for itract, tract in enumerate(tracts):
            tractInfo = tractPatchList[itract][0]

            coaddWcs = tractInfo.getWcs()
            coaddBBox = geom.Box2D()
            for skyPos in skyCorners:
                coaddBBox.include(coaddWcs.skyToPixel(skyPos))
            coaddBBox = geom.Box2I(coaddBBox)

            if itract == 0:
                # Define final wcs and bounding box from the reference tract
                finalWcs = coaddWcs
                finalBBox = coaddBBox

            patchList = tractPatchList[itract][1]
            for patchInfo in patchList:
                self.log.info('Adding patch %s from tract %s' %
                              (patchInfo.getIndex(), tract))

                # Local patch information
                patchSubBBox = geom.Box2I(patchInfo.getInnerBBox())
                patchSubBBox.clip(coaddBBox)
                patchInt = int(
                    f"{patchInfo.getIndex()[0]}{patchInfo.getIndex()[1]}")
                innerBBox = geom.Box2I(tractInfo._minimumBoundingBox(finalWcs))

                if itract == 0:
                    # clip to image and tract boundaries
                    patchSubBBox.clip(finalBBox)
                    patchSubBBox.clip(innerBBox)
                    if patchSubBBox.getArea() == 0:
                        self.log.debug("No ovlerap for patch %s" % patchInfo)
                        continue

                    patchArgDict = dict(
                        datasetType="deepCoadd_sub",
                        bbox=patchSubBBox,
                        tract=tractInfo.getId(),
                        patch="%s,%s" %
                        (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
                        filter=exposure.getFilter().getName())
                    coaddPatch = sensorRef.get(**patchArgDict)
                    if coaddFilter is None:
                        coaddFilter = coaddPatch.getFilter()

                    # create full image from final bounding box
                    exp = afwImage.ExposureF(finalBBox, finalWcs)
                    exp.maskedImage.set(
                        np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"),
                        np.nan)
                    exp.maskedImage.assign(coaddPatch.maskedImage,
                                           patchSubBBox)

                    maskedImageList.append(exp.maskedImage)
                    weightList.append(1)

                    record = tractsCatalog.addNew()
                    record.setPsf(coaddPatch.getPsf())
                    record.setWcs(coaddPatch.getWcs())
                    record.setPhotoCalib(coaddPatch.getPhotoCalib())
                    record.setBBox(patchSubBBox)
                    record.set(tractKey, tract)
                    record.set(patchKey, patchInt)
                    record.set(weightKey, 1.)
                    nPatchesFound += 1
                else:
                    # compute the exposure bounding box in a tract that is not the reference tract
                    localBox = geom.Box2I()
                    for skyPos in skyCorners:
                        localBox.include(
                            geom.Point2I(
                                tractInfo.getWcs().skyToPixel(skyPos)))

                    # clip to patch bounding box
                    localBox.clip(patchSubBBox)

                    # grow border to deal with warping at edges
                    localBox.grow(self.config.templateBorderSize)

                    # clip to tract inner bounding box
                    localInnerBBox = geom.Box2I(
                        tractInfo._minimumBoundingBox(tractInfo.getWcs()))
                    localBox.clip(localInnerBBox)

                    patchArgDict = dict(
                        datasetType="deepCoadd_sub",
                        bbox=localBox,
                        tract=tractInfo.getId(),
                        patch="%s,%s" %
                        (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
                        filter=exposure.getFilter().getName())
                    coaddPatch = sensorRef.get(**patchArgDict)

                    # warp to reference tract wcs
                    xyTransform = afwGeom.makeWcsPairTransform(
                        coaddPatch.getWcs(), finalWcs)
                    psfWarped = WarpedPsf(coaddPatch.getPsf(), xyTransform)
                    warped = self.warper.warpExposure(finalWcs,
                                                      coaddPatch,
                                                      maxBBox=finalBBox)

                    # check if warpped image is viable
                    if warped.getBBox().getArea() == 0:
                        self.log.info(
                            "No ovlerap for warped patch %s. Skipping" %
                            patchInfo)
                        continue

                    warped.setPsf(psfWarped)

                    exp = afwImage.ExposureF(finalBBox, finalWcs)
                    exp.maskedImage.set(
                        np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"),
                        np.nan)
                    exp.maskedImage.assign(warped.maskedImage,
                                           warped.getBBox())

                    maskedImageList.append(exp.maskedImage)
                    weightList.append(1)
                    record = tractsCatalog.addNew()
                    record.setPsf(psfWarped)
                    record.setWcs(finalWcs)
                    record.setPhotoCalib(coaddPatch.getPhotoCalib())
                    record.setBBox(warped.getBBox())
                    record.set(tractKey, tract)
                    record.set(patchKey, patchInt)
                    record.set(weightKey, 1.)
                    nPatchesFound += 1

        if nPatchesFound == 0:
            raise RuntimeError("No patches found!")

        # Combine images from individual patches together

        # Do not mask any values
        statsFlags = afwMath.stringToStatisticsProperty(self.config.statistic)
        maskMap = []
        statsCtrl = afwMath.StatisticsControl()
        statsCtrl.setNanSafe(True)
        statsCtrl.setWeighted(True)
        statsCtrl.setCalcErrorFromInputVariance(True)

        coaddExposure = afwImage.ExposureF(finalBBox, finalWcs)
        coaddExposure.maskedImage.set(np.nan,
                                      afwImage.Mask.getPlaneBitMask("NO_DATA"),
                                      np.nan)
        xy0 = coaddExposure.getXY0()
        coaddExposure.maskedImage = afwMath.statisticsStack(
            maskedImageList, statsFlags, statsCtrl, weightList, 0, maskMap)
        coaddExposure.maskedImage.setXY0(xy0)

        coaddPsf = CoaddPsf(tractsCatalog, finalWcs,
                            self.config.coaddPsf.makeControl())
        if coaddPsf is None:
            raise RuntimeError("No coadd Psf found!")

        coaddExposure.setPsf(coaddPsf)
        coaddExposure.setFilter(coaddFilter)
        return pipeBase.Struct(exposure=coaddExposure, sources=None)
Пример #27
0
    def run(self, coaddExposures, bbox, wcs, dataIds, **kwargs):
        """Warp coadds from multiple tracts to form a template for image diff.

        Where the tracts overlap, the resulting template image is averaged.
        The PSF on the template is created by combining the CoaddPsf on each
        template image into a meta-CoaddPsf.

        Parameters
        ----------
        coaddExposures : `list` of `lsst.afw.image.Exposure`
            Coadds to be mosaicked
        bbox : `lsst.geom.Box2I`
            Template Bounding box of the detector geometry onto which to
            resample the coaddExposures
        wcs : `lsst.afw.geom.SkyWcs`
            Template WCS onto which to resample the coaddExposures
        dataIds : `list` of `lsst.daf.butler.DataCoordinate`
            Record of the tract and patch of each coaddExposure.
        **kwargs
            Any additional keyword parameters.

        Returns
        -------
        result : `lsst.pipe.base.Struct` containing
            - ``outputExposure`` : a template coadd exposure assembled out of patches
        """
        # Table for CoaddPSF
        tractsSchema = afwTable.ExposureTable.makeMinimalSchema()
        tractKey = tractsSchema.addField('tract',
                                         type=np.int32,
                                         doc='Which tract')
        patchKey = tractsSchema.addField('patch',
                                         type=np.int32,
                                         doc='Which patch')
        weightKey = tractsSchema.addField(
            'weight', type=float, doc='Weight for each tract, should be 1')
        tractsCatalog = afwTable.ExposureCatalog(tractsSchema)

        finalWcs = wcs
        bbox.grow(self.config.templateBorderSize)
        finalBBox = bbox

        nPatchesFound = 0
        maskedImageList = []
        weightList = []

        for coaddExposure, dataId in zip(coaddExposures, dataIds):

            # warp to detector WCS
            warped = self.warper.warpExposure(finalWcs,
                                              coaddExposure,
                                              maxBBox=finalBBox)

            # Check if warped image is viable
            if not np.any(np.isfinite(warped.image.array)):
                self.log.info("No overlap for warped %s. Skipping" % dataId)
                continue

            exp = afwImage.ExposureF(finalBBox, finalWcs)
            exp.maskedImage.set(np.nan,
                                afwImage.Mask.getPlaneBitMask("NO_DATA"),
                                np.nan)
            exp.maskedImage.assign(warped.maskedImage, warped.getBBox())

            maskedImageList.append(exp.maskedImage)
            weightList.append(1)
            record = tractsCatalog.addNew()
            record.setPsf(coaddExposure.getPsf())
            record.setWcs(coaddExposure.getWcs())
            record.setPhotoCalib(coaddExposure.getPhotoCalib())
            record.setBBox(coaddExposure.getBBox())
            record.setValidPolygon(
                afwGeom.Polygon(
                    geom.Box2D(coaddExposure.getBBox()).getCorners()))
            record.set(tractKey, dataId['tract'])
            record.set(patchKey, dataId['patch'])
            record.set(weightKey, 1.)
            nPatchesFound += 1

        if nPatchesFound == 0:
            raise pipeBase.NoWorkFound("No patches found to overlap detector")

        # Combine images from individual patches together
        statsFlags = afwMath.stringToStatisticsProperty('MEAN')
        statsCtrl = afwMath.StatisticsControl()
        statsCtrl.setNanSafe(True)
        statsCtrl.setWeighted(True)
        statsCtrl.setCalcErrorFromInputVariance(True)

        templateExposure = afwImage.ExposureF(finalBBox, finalWcs)
        templateExposure.maskedImage.set(
            np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"), np.nan)
        xy0 = templateExposure.getXY0()
        # Do not mask any values
        templateExposure.maskedImage = afwMath.statisticsStack(maskedImageList,
                                                               statsFlags,
                                                               statsCtrl,
                                                               weightList,
                                                               clipped=0,
                                                               maskMap=[])
        templateExposure.maskedImage.setXY0(xy0)

        # CoaddPsf centroid not only must overlap image, but must overlap the part of
        # image with data. Use centroid of region with data
        boolmask = templateExposure.mask.array & templateExposure.mask.getPlaneBitMask(
            'NO_DATA') == 0
        maskx = afwImage.makeMaskFromArray(boolmask.astype(afwImage.MaskPixel))
        centerCoord = afwGeom.SpanSet.fromMask(maskx, 1).computeCentroid()

        ctrl = self.config.coaddPsf.makeControl()
        coaddPsf = CoaddPsf(tractsCatalog, finalWcs, centerCoord,
                            ctrl.warpingKernelName, ctrl.cacheSize)
        if coaddPsf is None:
            raise RuntimeError("CoaddPsf could not be constructed")

        templateExposure.setPsf(coaddPsf)
        templateExposure.setFilter(coaddExposure.getFilter())
        templateExposure.setPhotoCalib(coaddExposure.getPhotoCalib())
        return pipeBase.Struct(outputExposure=templateExposure)
Пример #28
0
    def run(self, visit, band, isolated_star_cat_dict, isolated_star_source_dict, src_dict, calexp_dict):
        """
        Run the FinalizeCharacterizationTask.

        Parameters
        ----------
        visit : `int`
            Visit number.  Used in the output catalogs.
        band : `str`
            Band name.  Used to select reserved stars.
        isolated_star_cat_dict : `dict`
            Per-tract dict of isolated star catalog handles.
        isolated_star_source_dict : `dict`
            Per-tract dict of isolated star source catalog handles.
        src_dict : `dict`
            Per-detector dict of src catalog handles.
        calexp_dict : `dict`
            Per-detector dict of calibrated exposure handles.

        Returns
        -------
        struct : `lsst.pipe.base.struct`
            Struct with outputs for persistence.
        """
        # We do not need the isolated star table in this task.
        # However, it is used in tests to confirm consistency of indexes.
        _, isolated_source_table = self.concat_isolated_star_cats(
            band,
            isolated_star_cat_dict,
            isolated_star_source_dict
        )

        exposure_cat_schema = afwTable.ExposureTable.makeMinimalSchema()
        exposure_cat_schema.addField('visit', type='L', doc='Visit number')

        metadata = dafBase.PropertyList()
        metadata.add("COMMENT", "Catalog id is detector id, sorted.")
        metadata.add("COMMENT", "Only detectors with data have entries.")

        psf_ap_corr_cat = afwTable.ExposureCatalog(exposure_cat_schema)
        psf_ap_corr_cat.setMetadata(metadata)

        measured_src_tables = []

        for detector in src_dict:
            src = src_dict[detector].get()
            exposure = calexp_dict[detector].get()

            psf, ap_corr_map, measured_src = self.compute_psf_and_ap_corr_map(
                visit,
                detector,
                exposure,
                src,
                isolated_source_table
            )

            # And now we package it together...
            record = psf_ap_corr_cat.addNew()
            record['id'] = int(detector)
            record['visit'] = visit
            if psf is not None:
                record.setPsf(psf)
            if ap_corr_map is not None:
                record.setApCorrMap(ap_corr_map)

            measured_src['visit'][:] = visit
            measured_src['detector'][:] = detector

            measured_src_tables.append(measured_src.asAstropy().as_array())

        measured_src_table = np.concatenate(measured_src_tables)

        return pipeBase.Struct(psf_ap_corr_cat=psf_ap_corr_cat,
                               output_table=measured_src_table)