Example #1
0
    def __init__(self, schema, refObjLoader=None, **kwds):
        r"""!Create the astrometric calibration task.  Most arguments are simply passed onto pipe.base.Task.

        \param schema An lsst::afw::table::Schema used to create the output lsst.afw.table.SourceCatalog
        \param refObjLoader The AstrometryTask constructor requires a refObjLoader.  In order to make this
        task retargettable for AstrometryTask it needs to take the same arguments.  This argument will be
        ignored since it uses its own internal loader.
        \param **kwds keyword arguments to be passed to the lsst.pipe.base.task.Task constructor

        A centroid field "centroid.distorted" (used internally during the Task's operation)
        will be added to the schema.
        """
        pipeBase.Task.__init__(self, **kwds)
        self.distortedName = "astrom_distorted"
        self.centroidXKey = schema.addField(self.distortedName + "_x", type="D",
                                            doc="centroid distorted for astrometry solver")
        self.centroidYKey = schema.addField(self.distortedName + "_y", type="D",
                                            doc="centroid distorted for astrometry solver")
        self.centroidXErrKey = schema.addField(self.distortedName + "_xErr", type="F",
                                               doc="centroid distorted err for astrometry solver")
        self.centroidYErrKey = schema.addField(self.distortedName + "_yErr", type="F",
                                               doc="centroid distorted err for astrometry solver")
        self.centroidFlagKey = schema.addField(self.distortedName + "_flag", type="Flag",
                                               doc="centroid distorted flag astrometry solver")
        self.centroidKey = Point2DKey(self.centroidXKey, self.centroidYKey)
        self.centroidErrKey = CovarianceMatrix2fKey((self.centroidXErrKey, self.centroidYErrKey))
        # postpone making the solver subtask because it may not be needed and is expensive to create
        self.solver = None
Example #2
0
    def setUp(self):
        # Set up a Coadd with CoaddInputs tables that have blank filter
        # columns to be filled in by later test code.
        self.coadd = ExposureF(30, 90)
        # WCS is arbitrary, since it'll be the same for all images
        wcs = makeSkyWcs(crpix=Point2D(0, 0),
                         crval=SpherePoint(45.0, 45.0, degrees),
                         cdMatrix=makeCdMatrix(scale=0.17 * degrees))
        self.coadd.setWcs(wcs)
        schema = ExposureCatalog.Table.makeMinimalSchema()
        self.filterKey = schema.addField("filter", type=str, doc="", size=16)
        weightKey = schema.addField("weight", type=float, doc="")
        # First input image covers the first 2/3, second covers the last 2/3,
        # so they overlap in the middle 1/3.
        inputs = ExposureCatalog(schema)
        self.input1 = inputs.addNew()
        self.input1.setId(1)
        self.input1.setBBox(Box2I(Point2I(0, 0), Point2I(29, 59)))
        self.input1.setWcs(wcs)
        self.input1.set(weightKey, 2.0)
        self.input2 = inputs.addNew()
        self.input2.setId(2)
        self.input2.setBBox(Box2I(Point2I(0, 30), Point2I(29, 89)))
        self.input2.setWcs(wcs)
        self.input2.set(weightKey, 3.0)
        # Use the same catalog for visits and CCDs since the algorithm we're
        # testing only cares about CCDs.
        self.coadd.getInfo().setCoaddInputs(CoaddInputs(inputs, inputs))

        # Set up a catalog with centroids and a FilterFraction plugin.
        # We have one record in each region (first input only, both inputs,
        # second input only)
        schema = SourceCatalog.Table.makeMinimalSchema()
        centroidKey = Point2DKey.addFields(schema,
                                           "centroid",
                                           doc="position",
                                           unit="pixel")
        schema.getAliasMap().set("slot_Centroid", "centroid")
        self.plugin = FilterFractionPlugin(
            config=FilterFractionPlugin.ConfigClass(),
            schema=schema,
            name="subaru_FilterFraction",
            metadata=PropertyList())
        catalog = SourceCatalog(schema)
        self.record1 = catalog.addNew()
        self.record1.set(centroidKey, Point2D(14.0, 14.0))
        self.record12 = catalog.addNew()
        self.record12.set(centroidKey, Point2D(14.0, 44.0))
        self.record2 = catalog.addNew()
        self.record2.set(centroidKey, Point2D(14.0, 74.0))
Example #3
0
    def plotStars(self, refCat, bbox=None):
        """Plot the centroids of reference objects, and the bounding box (if specified)
        """
        import matplotlib.pyplot as plt
        if bbox is not None:
            cornerList = list(afwGeom.Box2D(bbox).getCorners())
            cornerList.append(cornerList[0])  # show 4 sides of the box by going back to the beginning
            xc, yc = list(zip(*cornerList))
            plt.plot(xc, yc, '-')

        centroidKey = Point2DKey(refCat.schema["centroid"])
        centroidList = [rec.get(centroidKey) for rec in refCat]
        xp, yp = list(zip(*centroidList))
        plt.plot(xp, yp, '.')
        plt.show()
Example #4
0
    def assertObjInBBox(self, refCat, bbox, wcs):
        """Assert that all reference objects are inside the specified pixel bounding box plus a margin

        @param[in] refCat  reference object catalog, an lsst.afw.table.SimpleCatalog or compatible;
            the only fields read are "centroid_x/y" and "coord_ra/dec"
        @param[in] bbox  pixel bounding box coordinates, an lsst.afw.geom.Box2I or Box2D;
            the supplied box is grown by self.config.pixelMargin before testing the stars
        @param[in] wcs  WCS, an lsst.afw.image.Wcs
        """
        bbox = afwGeom.Box2D(bbox)
        bbox.grow(self.config.pixelMargin)
        centroidKey = Point2DKey(refCat.schema["centroid"])
        coordKey = CoordKey(refCat.schema["coord"])
        for refObj in refCat:
            point = refObj.get(centroidKey)
            if not bbox.contains(point):
                coord = refObj.get(coordKey)
                self.fail("refObj at RA, Dec %0.3f, %0.3f point %s is not in bbox %s" %
                          (coord[0].asDegrees(), coord[1].asDegrees(), point, bbox))
Example #5
0
def displayAstrometry(refCat=None,
                      sourceCat=None,
                      distortedCentroidKey=None,
                      bbox=None,
                      exposure=None,
                      matches=None,
                      frame=1,
                      title="",
                      pause=True):
    """Show an astrometry debug image.

    Parameters
    ----------
    refCat : `lsst.afw.table.SimpleCatalog`
        reference object catalog; must have fields "centroid_x" an
        "centroid_y"
    sourceCat : `lsst.afw.table.SourceCatalg`
        source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
    distortedCentroidKey : `lsst.afw.table.Key`
        key for sourceCat with field to use for distorted positions
    exposure : `lsst.afw.image.Exposure`
        exposure to display
    bbox : `lsst.geom.Box2I`
        bounding box of exposure; Used if the exposure is `None`
    matches : `list` of `lsst.afw.table.ReferenceMatch`
        List of matched objects
    frame : `int`
        frame number for display
    title : `str`
        title for display
    pause : `bool`
        pause for inspection of display? This is done by dropping into pdb.

    Notes
    -----

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - distorted sources in sourceCat (position given by distortedCentroidKey)
      are shown as green o
    - matches are shown as a yellow circle around the source and a yellow line
      connecting the reference object and source
    - if both exposure and bbox are `None`, no image is displayed

    """
    disp = afwDisplay.getDisplay(frame=frame)

    if exposure is not None:
        disp.mtv(exposure, title=title)
    elif bbox is not None:
        disp.mtv(exposure=ExposureF(bbox), title=title)

    with disp.Buffering():
        if refCat is not None:
            refCentroidKey = Point2DKey(refCat.schema["centroid"])
            for refObj in refCat:
                rx, ry = refObj.get(refCentroidKey)
                disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)

        if sourceCat is not None:
            sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
            for source in sourceCat:
                sx, sy = source.get(sourceCentroidKey)
                disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
                if distortedCentroidKey is not None:
                    dx, dy = source.get(distortedCentroidKey)
                    disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
                    disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)

        if matches is not None:
            refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
            sourceCentroidKey = Point2DKey(
                matches[0].second.schema["slot_Centroid"])
            radArr = np.ndarray(len(matches))

            for i, m in enumerate(matches):
                refCentroid = m.first.get(refCentroidKey)
                sourceCentroid = m.second.get(sourceCentroidKey)
                radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
                sx, sy = sourceCentroid
                disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
                disp.line([refCentroid, sourceCentroid],
                          ctype=afwDisplay.YELLOW)

            print("<match radius> = %.4g +- %.4g [%d matches]" %
                  (radArr.mean(), radArr.std(), len(matches)))

    if pause:
        print(
            "Dropping into debugger to allow inspection of display. Type 'continue' when done."
        )
        import pdb
        pdb.set_trace()
Example #6
0
def plotAstrometry(matches,
                   refCat=None,
                   sourceCat=None,
                   refMarker="x",
                   refColor="r",
                   sourceMarker="+",
                   sourceColor="g",
                   matchColor="y"):
    """Plot reference objects, sources and matches

    Parameters
    ----------
    matches : `list` of `lsst.afw.table.ReferenceMatch`
        list of matches
    refCat : `lsst.afw.table.SimpleCatalog`
        reference object catalog, or None to not plot reference objects
    sourceCat : `lsst.afw.table.SourceCatalog`
        source catalog, or None to not plot sources
    refMarker : `str`
        pyplot marker for reference objects
    refColor : `str`
        pyplot color for reference objects
    sourceMarker : `str`
        pyplot marker for sources
    sourceColor : `str`
        pyplot color for sources
    matchColor : `str`
        color for matches; can be a constant
        or a function taking one match and returning a string

    Notes
    -----
    By default:

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - matches are shown as a yellow circle around the source and a line
      connecting the reference object to the source
    """
    # delay importing plt to give users a chance to set the backend before calling this function
    import matplotlib.pyplot as plt
    refSchema = matches[0][0].schema
    refCentroidKey = Point2DKey(refSchema["centroid"])
    srcSchema = matches[0][1].schema
    srcCentroidKey = Point2DKey(srcSchema["slot_Centroid"])

    if refCat is not None:
        refXArr, refYArr = list(
            zip(*[ref.get(refCentroidKey) for ref in refCat]))
        plt.plot(refXArr,
                 refYArr,
                 marker=refMarker,
                 color=refColor,
                 linestyle="")

    if sourceCat is not None:
        srcXArr, srcYArr = list(
            zip(*[src.get(srcCentroidKey) for src in sourceCat]))
        plt.plot(srcXArr,
                 srcYArr,
                 marker=sourceMarker,
                 color=sourceColor,
                 linestyle="")

    def makeLineSegmentData(refXYArr, srcXYArr, colorArr):
        """Make a list of line segement data

        This is used to draw line segements between ref and src positions in the specified color

        Notes
        -----
        The returned data has the format:
         [(refX0, srcX0), (refY0, srcY0), color0, (refX1, srcX1), (refY1, srcY1), color1,...]
        """
        if len(refXYArr) != len(srcXYArr):
            raise RuntimeError("len(refXYArr) = %d != %d = len(srcXYArr)" %
                               (len(refXYArr), len(srcXYArr)))
        if len(refXYArr) != len(colorArr):
            raise RuntimeError("len(refXYArr) = %d != %d = len(colorArr)" %
                               (len(refXYArr), len(colorArr)))

        refXArr, refYArr = list(zip(*refXYArr))
        srcXArr, srcYArr = list(zip(*srcXYArr))
        refSrcXArr = list(zip(refXArr, srcXArr))
        refSrcYArr = list(zip(refYArr, srcYArr))
        dataList = []
        for xycolor in zip(refSrcXArr, refSrcYArr, colorArr):
            for val in xycolor:
                dataList.append(val)
        return dataList

    refXYArr, srcXYArr = \
        list(zip(*[(match[0].get(refCentroidKey), match[1].get(srcCentroidKey)) for match in matches]))

    def plotSourceCircles(matches, color):
        srcXYArr = [match[1].get(srcCentroidKey) for match in matches]
        srcXArr, srcYArr = list(zip(*srcXYArr))
        plt.plot(
            srcXArr,
            srcYArr,
            "o",
            mec=color,
            mfc="none",
            ms=10,
        )

    if callable(matchColor):
        # different matches have different colors
        matchColorArr = [matchColor(match) for match in matches]

        # plot circles for each color separately
        matchColorSet = set(matchColorArr)
        for color in matchColorSet:
            subMatches = [
                match for match in matches if matchColor(match) == color
            ]
            plotSourceCircles(subMatches, color=color)
    else:
        matchColorArr = [matchColor] * len(refXYArr)
        plotSourceCircles(matches, color=matchColor)

    lineSegData = makeLineSegmentData(refXYArr, srcXYArr, matchColorArr)
    plt.plot(*lineSegData)

    plt.show()
Example #7
0
def displayAstrometry(refCat=None,
                      sourceCat=None,
                      distortedCentroidKey=None,
                      bbox=None,
                      exposure=None,
                      matches=None,
                      frame=1,
                      title="",
                      pause=True):
    """Show an astrometry debug image

    - reference objects in refCat are shown as red X
    - sources in sourceCat are shown as green +
    - distorted sources in sourceCat (position given by distortedCentroidKey) are shown as green o
    - matches are shown as a yellow circle around the source and a yellow line
        connecting the reference object and source
    - if both exposure and bbox are None, no image is displayed

    @param[in] refCat  reference object catalog; must have fields "centroid_x" and "centroid_y"
    @param[in] sourceCat  source catalog; must have field "slot_Centroid_x" and "slot_Centroid_y"
    @param[in] distortedCentroidKey  key for sourceCat with field to use for distorted positions, or None
    @param[in] exposure  exposure to display, or None for a blank exposure
    @param[in] bbox  bounding box of exposure; used if exposure is None for a blank image
    @param[in] matches  a list of lsst.afw.table.ReferenceMatch, or None
    @param[in] frame  frame number for ds9 display
    @param[in] title  title for ds9 display
    @param[in] pause  pause for inspection of display? This is done by dropping into pdb.
    """
    disp = afwDisplay.getDisplay(frame)

    if exposure is not None:
        disp.mtv(exposure, title=title)
    elif bbox is not None:
        disp.mtv(exposure=ExposureF(bbox), title=title)

    with disp.Buffering():
        if refCat is not None:
            refCentroidKey = Point2DKey(refCat.schema["centroid"])
            for refObj in refCat:
                rx, ry = refObj.get(refCentroidKey)
                disp.dot("x", rx, ry, size=10, ctype=afwDisplay.RED)

        if sourceCat is not None:
            sourceCentroidKey = Point2DKey(sourceCat.schema["slot_Centroid"])
            for source in sourceCat:
                sx, sy = source.get(sourceCentroidKey)
                disp.dot("+", sx, sy, size=10, ctype=afwDisplay.GREEN)
                if distortedCentroidKey is not None:
                    dx, dy = source.get(distortedCentroidKey)
                    disp.dot("o", dx, dy, size=10, ctype=afwDisplay.GREEN)
                    disp.line([(sx, sy), (dx, dy)], ctype=afwDisplay.GREEN)

        if matches is not None:
            refCentroidKey = Point2DKey(matches[0].first.schema["centroid"])
            sourceCentroidKey = Point2DKey(
                matches[0].second.schema["slot_Centroid"])
            radArr = np.ndarray(len(matches))

            for i, m in enumerate(matches):
                refCentroid = m.first.get(refCentroidKey)
                sourceCentroid = m.second.get(sourceCentroidKey)
                radArr[i] = math.hypot(*(refCentroid - sourceCentroid))
                sx, sy = sourceCentroid
                disp.dot("o", sx, sy, size=10, ctype=afwDisplay.YELLOW)
                disp.line([refCentroid, sourceCentroid],
                          ctype=afwDisplay.YELLOW)

            print("<match radius> = %.4g +- %.4g [%d matches]" %
                  (radArr.mean(), radArr.std(), len(matches)))

    if pause:
        print(
            "Dropping into debugger to allow inspection of display. Type 'continue' when done."
        )
        import pdb
        pdb.set_trace()
Example #8
0
    def run(self, ccdExposure):
        """Mask negative pixels"""
        ccd = ccdExposure.getDetector()
        ccdExposure = self.convertIntToFloat(ccdExposure)

        self.updateVariance(ccdExposure, ccd[0])  # Treating as having only a single amplifier

        image = ccdExposure.getMaskedImage().getImage()
        mask = ccdExposure.getMaskedImage().getMask()
        bad = mask.getPlaneBitMask("BAD")
        if False:
            mask.getArray()[:] = numpy.where(image <= 0, bad, 0)  # XXX this causes bad things to happen

        #from lsst.afw.image.utils import clipImage
        #clipImage(image,0,10)
        #exit()


        """ transfer wcs system to TAN """
        matches = ReferenceMatchVector()
        md  = ccdExposure.getMetadata()
        wcs = ccdExposure.getWcs()

        refSchema = SimpleTable.makeMinimalSchema()
        Point2DKey.addFields(refSchema, "centroid", "centroid position", "pixel")
        refCatalog = SimpleCatalog(refSchema)
        schema = SourceTable.makeMinimalSchema()
        centroidKey = Point2DKey.addFields(schema, "centroid", "centroid position", "pixel")
        imgCatalog = SourceCatalog(schema)
        imgCatalog.defineCentroid("centroid")

#        for i in numpy.linspace(10, md.get("ZNAXIS1")-10, 20):
#            for j in numpy.linspace(10, md.get("ZNAXIS2")-10, 20):
        for i in numpy.linspace(10, 4000, 10):
            for j in numpy.linspace(10, 4000, 10):
                imgcrd = Point2D(i,j)  
                skycrd = wcs.pixelToSky(afwGeom.Point2D(i, j))
                # Create the reference catalog (with coordinates on the sky)
                refSrc = refCatalog.addNew()
                refSrc.setCoord(skycrd)
                # Create the position catalog (with positions on the image)
                imgSrc = imgCatalog.addNew()
                imgSrc.set(centroidKey, imgcrd)
                # matches
                matches.push_back(ReferenceMatch(refSrc, imgSrc, float("NaN")))

        # make initial wcs
        refPix = afwGeom.Point2D(0.5*ccdExposure.getWidth(), 0.5*ccdExposure.getHeight())
        refSky = wcs.pixelToSky(refPix)
        xPixelScale = yPixelScale = (0.2*afwGeom.arcseconds).asDegrees()
        initanWcs = afwImage.makeWcs(refSky, refPix, xPixelScale, 0.0, 0.0, yPixelScale)
        # obtain modified wcs with matched catalogs
        fitter = FitTanSipWcsTask()
        fitRes = fitter.fitWcs(
            matches = matches,
            initWcs = initanWcs,
            refCat = refCatalog,
            sourceCat = imgCatalog,
        )
        ccdExposure.setWcs(fitRes.wcs)


        """ Set zero point, ZP error, exptime """
    	zp = md.get("MAGZPT")
    	ccdExposure.getCalib().setFluxMag0(10.0**(0.4*zp))

        return lsst.pipe.base.Struct(exposure=ccdExposure)