Exemplo n.º 1
0
 def testValid(self):
     test_data = {
         "[1:1084,1:1024]":
         geom.BoxI(geom.PointI(0, 0), geom.PointI(1083, 1023)),
         "[0:0,0:0]":
         geom.BoxI(geom.PointI(-1, -1), geom.PointI(-1, -1))
     }
     for val, result in test_data.items():
         self.assertEqual(obsBase.bboxFromIraf(val), result)
Exemplo n.º 2
0
def assemble_raw(dataId, componentInfo, cls):
    """Called by the butler to construct the composite type "raw".

    Note that we still need to define "_raw" and copy various fields over.

    Parameters
    ----------
    dataId : `lsst.daf.persistence.dataId.DataId`
        The data ID.
    componentInfo : `dict`
        dict containing the components, as defined by the composite definition
        in the mapper policy.
    cls : 'object'
        Unused.

    Returns
    -------
    exposure : `lsst.afw.image.Exposure`
        The assembled exposure.
    """
    from lsst.ip.isr import AssembleCcdTask

    config = AssembleCcdTask.ConfigClass()
    config.doTrim = False

    assembleTask = AssembleCcdTask(config=config)

    ampExps = componentInfo['raw_amp'].obj
    if len(ampExps) == 0:
        raise RuntimeError("Unable to read raw_amps for %s" % dataId)

    ccd = ampExps[0].getDetector()      # the same (full, CCD-level) Detector is attached to all ampExps
    #
    # Check that the geometry in the metadata matches cameraGeom
    #
    logger = lsst.log.Log.getLogger("LsstCamMapper")
    warned = False
    for i, (amp, ampExp) in enumerate(zip(ccd, ampExps)):
        ampMd = ampExp.getMetadata().toDict()

        if amp.getRawBBox() != ampExp.getBBox():  # Oh dear. cameraGeom is wrong -- probably overscan
            if amp.getRawDataBBox().getDimensions() != amp.getBBox().getDimensions():
                raise RuntimeError("Active area is the wrong size: %s v. %s" %
                                   (amp.getRawDataBBox().getDimensions(), amp.getBBox().getDimensions()))
            if not warned:
                logger.warn("amp.getRawBBox() != data.getBBox(); patching. (%s v. %s)",
                            amp.getRawBBox(), ampExp.getBBox())
                warned = True

            w, h = ampExp.getBBox().getDimensions()
            ow, oh = amp.getRawBBox().getDimensions()  # "old" (cameraGeom) dimensions
            #
            # We could trust the BIASSEC keyword, or we can just assume that
            # they've changed the number of overscan pixels (serial and/or
            # parallel).  As Jim Chiang points out, the latter is safer
            #
            bbox = amp.getRawHorizontalOverscanBBox()
            hOverscanBBox = geom.BoxI(bbox.getBegin(),
                                      geom.ExtentI(w - bbox.getBeginX(), bbox.getHeight()))
            bbox = amp.getRawVerticalOverscanBBox()
            vOverscanBBox = geom.BoxI(bbox.getBegin(),
                                      geom.ExtentI(bbox.getWidth(), h - bbox.getBeginY()))

            amp.setRawBBox(ampExp.getBBox())
            amp.setRawHorizontalOverscanBBox(hOverscanBBox)
            amp.setRawVerticalOverscanBBox(vOverscanBBox)
            #
            # This gets all the geometry right for the amplifier, but the size
            # of the untrimmed image will be wrong and we'll put the amp
            # sections in the wrong places, i.e.
            #   amp.getRawXYOffset()
            # will be wrong.  So we need to recalculate the offsets.
            #
            xRawExtent, yRawExtent = amp.getRawBBox().getDimensions()

            x0, y0 = amp.getRawXYOffset()
            ix, iy = x0//ow, y0/oh
            x0, y0 = ix*xRawExtent, iy*yRawExtent
            amp.setRawXYOffset(geom.ExtentI(ix*xRawExtent, iy*yRawExtent))
        #
        # Check the "IRAF" keywords, but don't abort if they're wrong
        #
        # Only warn about the first amp, use debug for the others
        #
        detsec = bboxFromIraf(ampMd["DETSEC"]) if "DETSEC" in ampMd else None
        datasec = bboxFromIraf(ampMd["DATASEC"]) if "DATASEC" in ampMd else None
        biassec = bboxFromIraf(ampMd["BIASSEC"]) if "BIASSEC" in ampMd else None

        logCmd = logger.warn if i == 0 else logger.debug
        if detsec and amp.getBBox() != detsec:
            logCmd("DETSEC doesn't match for %s (%s != %s)", dataId, amp.getBBox(), detsec)
        if datasec and amp.getRawDataBBox() != datasec:
            logCmd("DATASEC doesn't match for %s (%s != %s)", dataId, amp.getRawDataBBox(), detsec)
        if biassec and amp.getRawHorizontalOverscanBBox() != biassec:
            logCmd("BIASSEC doesn't match for %s (%s != %s)",
                   dataId, amp.getRawHorizontalOverscanBBox(), detsec)

    ampDict = {}
    for amp, ampExp in zip(ccd, ampExps):
        ampDict[amp.getName()] = ampExp

    exposure = assembleTask.assembleCcd(ampDict)

    md = componentInfo['raw_hdu'].obj
    fix_header(md)  # No mapper so cannot specify the translator class
    exposure.setMetadata(md)
    visitInfo = LsstCamMakeRawVisitInfo(logger)(md)
    exposure.getInfo().setVisitInfo(visitInfo)

    boresight = visitInfo.getBoresightRaDec()
    rotangle = visitInfo.getBoresightRotAngle()

    if boresight.isFinite():
        exposure.setWcs(getWcsFromDetector(exposure.getDetector(), boresight,
                                           90*geom.degrees - rotangle))
    else:
        # Should only warn for science observations but VisitInfo does not know
        logger.warn("Unable to set WCS for %s from header as RA/Dec/Angle are unavailable" %
                    (dataId,))

    return exposure
Exemplo n.º 3
0
def fixAmpGeometry(inAmp, bbox, metadata, logCmd=None):
    """Make sure a camera geometry amplifier matches an on-disk bounding box.

    Bounding box differences that are consistent with differences in overscan
    regions are assumed to be overscan regions, which gives us enough
    information to correct the camera geometry.

    Parameters
    ----------
    inAmp : `lsst.afw.cameraGeom.Amplifier`
        Amplifier description from camera geometry.
    bbox : `lsst.geom.Box2I`
        The on-disk bounding box of the amplifer image.
    metadata : `lsst.daf.base.PropertyList`
        FITS header metadata from the amplifier HDU.
    logCmd : `function`, optional
        Call back to use to issue log messages.  Arguments to this function
        should match arguments to be accepted by normal logging functions.

    Return
    ------
    outAmp : `~lsst.afw.cameraGeom.Amplifier.Builder`
    modified : `bool`
        `True` if ``amp`` was modified; `False` otherwise.

    Raises
    ------
    RuntimeError
        Raised if the bounding boxes differ in a way that is not consistent
        with just a change in overscan.
    """
    if logCmd is None:
        # Define a null log command
        def logCmd(*args):
            return

    modified = False

    outAmp = inAmp.rebuild()
    if outAmp.getRawBBox(
    ) != bbox:  # Oh dear. cameraGeom is wrong -- probably overscan
        if outAmp.getRawDataBBox().getDimensions() != outAmp.getBBox(
        ).getDimensions():
            raise RuntimeError("Active area is the wrong size: %s v. %s" %
                               (outAmp.getRawDataBBox().getDimensions(),
                                outAmp.getBBox().getDimensions()))

        logCmd("outAmp.getRawBBox() != data.getBBox(); patching. (%s v. %s)",
               outAmp.getRawBBox(), bbox)

        w, h = bbox.getDimensions()
        ow, oh = outAmp.getRawBBox().getDimensions(
        )  # "old" (cameraGeom) dimensions
        #
        # We could trust the BIASSEC keyword, or we can just assume that
        # they've changed the number of overscan pixels (serial and/or
        # parallel).  As Jim Chiang points out, the latter is safer
        #
        fromCamGeom = outAmp.getRawHorizontalOverscanBBox()
        hOverscanBBox = Box2I(
            fromCamGeom.getBegin(),
            Extent2I(w - fromCamGeom.getBeginX(), fromCamGeom.getHeight()))
        fromCamGeom = outAmp.getRawVerticalOverscanBBox()
        vOverscanBBox = Box2I(
            fromCamGeom.getBegin(),
            Extent2I(fromCamGeom.getWidth(), h - fromCamGeom.getBeginY()))
        outAmp.setRawBBox(bbox)
        outAmp.setRawHorizontalOverscanBBox(hOverscanBBox)
        outAmp.setRawVerticalOverscanBBox(vOverscanBBox)
        #
        # This gets all the geometry right for the amplifier, but the size
        # of the untrimmed image will be wrong and we'll put the amp sections
        # in the wrong places, i.e.
        #   outAmp.getRawXYOffset()
        # will be wrong.  So we need to recalculate the offsets.
        #
        xRawExtent, yRawExtent = outAmp.getRawBBox().getDimensions()

        x0, y0 = outAmp.getRawXYOffset()
        ix, iy = x0 // ow, y0 / oh
        x0, y0 = ix * xRawExtent, iy * yRawExtent
        outAmp.setRawXYOffset(Extent2I(ix * xRawExtent, iy * yRawExtent))

        modified = True

    #
    # Check the "IRAF" keywords, but don't abort if they're wrong
    #
    # Only warn about the first amp, use debug for the others
    #
    d = metadata.toDict()
    detsec = bboxFromIraf(d["DETSEC"]) if "DETSEC" in d else None
    datasec = bboxFromIraf(d["DATASEC"]) if "DATASEC" in d else None
    biassec = bboxFromIraf(d["BIASSEC"]) if "BIASSEC" in d else None

    if detsec and outAmp.getBBox() != detsec:
        logCmd("DETSEC doesn't match (%s != %s)", outAmp.getBBox(), detsec)
    if datasec and outAmp.getRawDataBBox() != datasec:
        logCmd("DATASEC doesn't match for (%s != %s)", outAmp.getRawDataBBox(),
               detsec)
    if biassec and outAmp.getRawHorizontalOverscanBBox() != biassec:
        logCmd("BIASSEC doesn't match for (%s != %s)",
               outAmp.getRawHorizontalOverscanBBox(), detsec)

    return outAmp, modified
Exemplo n.º 4
0
    def std_raw(self, item, dataId):
        """Method for performing any necessary manipulation of the raw files.

        @param[in,out] item afwImage exposure object with associated metadata and detector info
        @param[in] dataId
        """
        md = item.getMetadata()

        # Note that setting these must be done before the call to super below
        md.set('CTYPE1', 'RA---TAN')  # add missing keywords
        md.set('CTYPE2', 'DEC--TAN')  # add missing keywords
        md.set('CRVAL2',
               decStrToDeg(md.get('DEC')))  # translate RA/DEC from header
        md.set('CRVAL1', raStrToDeg(md.get('RA')))
        md.set('CRPIX1', 210.216)  # set reference pixels
        md.set('CRPIX2', 344.751)
        md.set('CD1_1', -0.000111557869436)  # set nominal CD matrix
        md.set('CD1_2', 1.09444409144E-07)
        md.set('CD2_1', 6.26180926869E-09)
        md.set('CD2_2', -0.000111259259893)

        item = super(Ctio0m9Mapper, self).std_raw(item, dataId)
        #
        # We may need to hack up the cameraGeom
        #
        # There doesn't seem to be a way to get the extended register, so I don't update it.
        # We could do this by detecting extra overscan and adjusting things cleverly; probably
        # we need to so so.
        #
        ccd = item.getDetector()
        rawBBoxFromMetadata = bboxFromIraf(md.get("ASEC11"))
        rawBBox = ccd[0].getRawBBox()

        if rawBBoxFromMetadata != rawBBox:
            extraSerialOverscan = rawBBoxFromMetadata.getWidth(
            ) - rawBBox.getWidth()  # extra overscan pixels
            extraParallelOverscan = rawBBoxFromMetadata.getHeight(
            ) - rawBBox.getHeight()  # vertical

            ccd = cameraGeom.copyDetector(
                ccd, ampInfoCatalog=ccd.getAmpInfoCatalog().copy(deep=True))
            item.setDetector(ccd)

            for a in ccd:
                ix, iy = [int(_) for _ in a.getName()]
                irafName = "%d%d" % (iy, ix)
                a.setRawBBox(bboxFromIraf(md.get("ASEC%s" % irafName)))
                a.setRawDataBBox(bboxFromIraf(md.get("TSEC%s" % irafName)))

                if extraSerialOverscan != 0 or extraParallelOverscan != 0:
                    #
                    # the number of overscan pixels has been changed from camera.yaml
                    #
                    # First adjust the overscan
                    #
                    rawHorizontalOverscanBBox = a.getRawHorizontalOverscanBBox(
                    )

                    rawHorizontalOverscanBBox.shift(
                        afwGeom.ExtentI((ix - 1) * extraSerialOverscan,
                                        (iy - 1) * extraParallelOverscan))

                    xy0 = rawHorizontalOverscanBBox.getMin()
                    xy1 = rawHorizontalOverscanBBox.getMax()

                    xy1.shift(
                        afwGeom.ExtentI(extraSerialOverscan,
                                        extraParallelOverscan))

                    a.setRawHorizontalOverscanBBox(afwGeom.BoxI(xy0, xy1))
                    #
                    # And now move the extended register to allow for the extra overscan pixels
                    #
                    rawPrescanBBox = a.getRawPrescanBBox()
                    rawPrescanBBox.shift(
                        afwGeom.ExtentI(2 * (ix - 1) * extraSerialOverscan,
                                        (iy - 1) * extraParallelOverscan))

                    xy0 = rawPrescanBBox.getMin()
                    xy1 = rawPrescanBBox.getMax()

                    xy1.shift(afwGeom.ExtentI(0, extraParallelOverscan))
                    a.setRawPrescanBBox(afwGeom.BoxI(xy0, xy1))

        return item