Exemplo n.º 1
0
    def testGainAndReadnoise(self):

        isrTask = IsrTask()

        detector = DetectorWrapper().detector
        raw = afwImage.ExposureF(detector.getBBox())

        level = 10
        readNoise = 1.5
        raw.image.set(level)

        amp = detector[0]

        for gain in [-1, 0, 0.1, 1, np.NaN]:
            # Because amplifiers are immutable, we can't change the gain or
            # read noise in-place. Instead, we clone, and update the clone.
            testAmp = Amplifier.Builder()
            testAmp.assign(amp)
            testAmp.setReadNoise(readNoise)
            testAmp.setGain(gain)
            testAmp.finish()

            isrTask.updateVariance(raw, testAmp)
            if gain <= 0:  # behave the same way as amp.setGain
                gain = 1
            if math.isnan(gain):
                gain = 1
            self.assertEqual(raw.variance[0, 0, afwImage.LOCAL],
                             level / gain + readNoise**2)
Exemplo n.º 2
0
 def setUp(self):
     self.data = SimpleNamespace(
         name="Amp1",
         gain=1.2345,
         saturation=65535,
         readNoise=-0.523,
         linearityCoeffs=np.array([1.1, 2.2, 3.3, 4.4], dtype=float),
         linearityType="Polynomial",
         bbox=lsst.geom.Box2I(lsst.geom.Point2I(3, -2),
                              lsst.geom.Extent2I(231, 320)),
         rawFlipX=True,
         rawFlipY=False,
         readoutCorner=ReadoutCorner.UL,
         rawBBox=lsst.geom.Box2I(lsst.geom.Point2I(-25, 2),
                                 lsst.geom.Extent2I(550, 629)),
         rawXYOffset=lsst.geom.Extent2I(-97, 253),
         rawDataBBox=lsst.geom.Box2I(lsst.geom.Point2I(-2, 29),
                                     lsst.geom.Extent2I(123, 307)),
         rawHorizontalOverscanBBox=lsst.geom.Box2I(
             lsst.geom.Point2I(150, 29),
             lsst.geom.Extent2I(25, 307),
         ),
         rawVerticalOverscanBBox=lsst.geom.Box2I(
             lsst.geom.Point2I(-2, 201),
             lsst.geom.Extent2I(123, 6),
         ),
         rawPrescanBBox=lsst.geom.Box2I(
             lsst.geom.Point2I(-20, 2),
             lsst.geom.Extent2I(5, 307),
         ),
     )
     builder = Amplifier.Builder()
     builder.setBBox(self.data.bbox)
     builder.setName(self.data.name)
     builder.setGain(self.data.gain)
     builder.setSaturation(self.data.saturation)
     builder.setReadNoise(self.data.readNoise)
     builder.setReadoutCorner(self.data.readoutCorner)
     builder.setLinearityCoeffs(self.data.linearityCoeffs)
     builder.setLinearityType(self.data.linearityType)
     builder.setRawFlipX(self.data.rawFlipX)
     builder.setRawFlipY(self.data.rawFlipY)
     builder.setRawBBox(self.data.rawBBox)
     builder.setRawXYOffset(self.data.rawXYOffset)
     builder.setRawDataBBox(self.data.rawDataBBox)
     builder.setRawHorizontalOverscanBBox(
         self.data.rawHorizontalOverscanBBox)
     builder.setRawVerticalOverscanBBox(self.data.rawVerticalOverscanBBox)
     builder.setRawPrescanBBox(self.data.rawPrescanBBox)
     self.amplifier = builder.finish()
Exemplo n.º 3
0
    def _makeAmpBuilder(self):
        """Construct a trivial amplifier builder.

        The CBP code does not care about the details of the amplifier, so this
        builder is as simple as possible: one amplifier that covers the whole
        CCD, with no overscan, and semi-plausible valus for everything else.

        Returns
        -------
        ampBuilder : `lsst.afw.cameraGeom.Amplifier.Builder`
            Amplifier builder.
        """
        ampExtent = lsst.geom.Extent2I(self.detectorWidthPix,
                                       self.detectorHeightPix)
        ampBBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), ampExtent)

        ampBuilder = Amplifier.Builder()
        ampBuilder.setName("TestAmp")
        ampBuilder.setBBox(ampBBox)
        ampBuilder.setGain(1.8)
        ampBuilder.setReadNoise(3.9)
        ampBuilder.setReadoutCorner(ReadoutCorner.LL)

        return ampBuilder
Exemplo n.º 4
0
    def testBasics(self):
        name = "Amp1"
        gain = 1.2345
        saturation = 65535
        readNoise = -0.523
        linearityCoeffs = np.array([1.1, 2.2, 3.3, 4.4], dtype=float)
        linearityType = "Polynomial"
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(3, -2),
                               lsst.geom.Extent2I(231, 320))
        rawFlipX = True
        rawFlipY = False
        readoutCorner = ReadoutCorner.UL
        rawBBox = lsst.geom.Box2I(lsst.geom.Point2I(-25, 2),
                                  lsst.geom.Extent2I(550, 629))
        rawXYOffset = lsst.geom.Extent2I(-97, 253)
        rawDataBBox = lsst.geom.Box2I(lsst.geom.Point2I(-2, 29),
                                      lsst.geom.Extent2I(123, 307))
        rawHorizontalOverscanBBox = lsst.geom.Box2I(
            lsst.geom.Point2I(150, 29), lsst.geom.Extent2I(25, 307))
        rawVerticalOverscanBBox = lsst.geom.Box2I(lsst.geom.Point2I(-2, 201),
                                                  lsst.geom.Extent2I(123, 6))
        rawPrescanBBox = lsst.geom.Box2I(lsst.geom.Point2I(-20, 2),
                                         lsst.geom.Extent2I(5, 307))

        builder = Amplifier.Builder()
        builder.setBBox(bbox)
        builder.setName(name)
        builder.setGain(gain)
        builder.setSaturation(saturation)
        builder.setReadNoise(readNoise)
        builder.setReadoutCorner(readoutCorner)
        builder.setLinearityCoeffs(linearityCoeffs)
        builder.setLinearityType(linearityType)
        builder.setRawFlipX(rawFlipX)
        builder.setRawFlipY(rawFlipY)
        builder.setRawBBox(rawBBox)
        builder.setRawXYOffset(rawXYOffset)
        builder.setRawDataBBox(rawDataBBox)
        builder.setRawHorizontalOverscanBBox(rawHorizontalOverscanBBox)
        builder.setRawVerticalOverscanBBox(rawVerticalOverscanBBox)
        builder.setRawPrescanBBox(rawPrescanBBox)
        amplifier = builder.finish()

        self.assertEqual(name, amplifier.getName())
        self.assertEqual(gain, amplifier.getGain())
        self.assertEqual(saturation, amplifier.getSaturation())
        self.assertEqual(readNoise, amplifier.getReadNoise())
        self.assertEqual(readoutCorner, amplifier.getReadoutCorner())
        self.assertEqual(list(linearityCoeffs),
                         list(amplifier.getLinearityCoeffs()))
        self.assertEqual(linearityType, amplifier.getLinearityType())
        self.assertEqual(bbox, amplifier.getBBox())
        self.assertEqual(rawBBox, amplifier.getRawBBox())
        self.assertEqual(rawDataBBox, amplifier.getRawDataBBox())
        self.assertEqual(rawHorizontalOverscanBBox,
                         amplifier.getRawHorizontalOverscanBBox())
        self.assertEqual(rawVerticalOverscanBBox,
                         amplifier.getRawVerticalOverscanBBox())
        self.assertEqual(rawPrescanBBox, amplifier.getRawPrescanBBox())
        self.assertEqual(rawHorizontalOverscanBBox,
                         amplifier.getRawSerialOverscanBBox())
        self.assertEqual(rawVerticalOverscanBBox,
                         amplifier.getRawParallelOverscanBBox())
        self.assertEqual(rawPrescanBBox, amplifier.getRawSerialPrescanBBox())
        self.assertEqual(rawPrescanBBox,
                         amplifier.getRawHorizontalPrescanBBox())
        self.assertEqual(rawFlipX, amplifier.getRawFlipX())
        self.assertEqual(rawFlipY, amplifier.getRawFlipY())
        self.assertEqual(rawXYOffset, amplifier.getRawXYOffset())

        # Test get/set methods for overscan/prescan alias names.
        # Change slightly, don't care about contiguity, make smaller.
        newHorizontalOverscanBBox = lsst.geom.Box2I(
            lsst.geom.Point2I(150, 29), lsst.geom.Extent2I(25, 306))
        newVerticalOverscanBBox = lsst.geom.Box2I(lsst.geom.Point2I(-2, 201),
                                                  lsst.geom.Extent2I(123, 5))
        newPrescanBBox = lsst.geom.Box2I(lsst.geom.Point2I(-20, 2),
                                         lsst.geom.Extent2I(4, 306))

        builder.setRawSerialOverscanBBox(newHorizontalOverscanBBox)
        builder.setRawParallelOverscanBBox(newVerticalOverscanBBox)
        builder.setRawSerialPrescanBBox(newPrescanBBox)
        amplifier = builder.finish()

        self.assertEqual(newHorizontalOverscanBBox,
                         amplifier.getRawHorizontalOverscanBBox())
        self.assertEqual(newVerticalOverscanBBox,
                         amplifier.getRawVerticalOverscanBBox())
        self.assertEqual(newPrescanBBox, amplifier.getRawPrescanBBox())

        newPrescanBBox2 = lsst.geom.Box2I(lsst.geom.Point2I(-20, 2),
                                          lsst.geom.Extent2I(5, 306))
        builder.setRawHorizontalPrescanBBox(newPrescanBBox2)
        amplifier = builder.finish()
        self.assertEqual(newPrescanBBox2, amplifier.getRawPrescanBBox())
Exemplo n.º 5
0
def makeAmplifierList(ccd):
    """Construct a list of AmplifierBuilder objects
    """
    # Much of this will need to be filled in when we know it.
    assert len(ccd) > 0
    amp = list(ccd['amplifiers'].values())[0]

    rawBBox = makeBBoxFromList(amp['rawBBox'])  # total in file
    xRawExtent, yRawExtent = rawBBox.getDimensions()

    readCorners = {"LL": ReadoutCorner.LL,
                   "LR": ReadoutCorner.LR,
                   "UL": ReadoutCorner.UL,
                   "UR": ReadoutCorner.UR}

    amplifierList = []
    for name, amp in sorted(ccd['amplifiers'].items(), key=lambda x: x[1]['hdu']):
        amplifier = Amplifier.Builder()
        amplifier.setName(name)

        ix, iy = amp['ixy']
        perAmpData = amp['perAmpData']
        if perAmpData:
            x0, y0 = 0, 0           # origin of data within each amp image
        else:
            x0, y0 = ix*xRawExtent, iy*yRawExtent

        rawDataBBox = makeBBoxFromList(amp['rawDataBBox'])  # Photosensitive area
        xDataExtent, yDataExtent = rawDataBBox.getDimensions()
        amplifier.setBBox(geom.BoxI(
            geom.PointI(ix*xDataExtent, iy*yDataExtent), rawDataBBox.getDimensions()))

        rawBBox = makeBBoxFromList(amp['rawBBox'])
        rawBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawBBox(rawBBox)

        rawDataBBox = makeBBoxFromList(amp['rawDataBBox'])
        rawDataBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawDataBBox(rawDataBBox)

        rawSerialOverscanBBox = makeBBoxFromList(amp['rawSerialOverscanBBox'])
        rawSerialOverscanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawHorizontalOverscanBBox(rawSerialOverscanBBox)

        rawParallelOverscanBBox = makeBBoxFromList(amp['rawParallelOverscanBBox'])
        rawParallelOverscanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawVerticalOverscanBBox(rawParallelOverscanBBox)

        rawSerialPrescanBBox = makeBBoxFromList(amp['rawSerialPrescanBBox'])
        rawSerialPrescanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawPrescanBBox(rawSerialPrescanBBox)

        if perAmpData:
            amplifier.setRawXYOffset(geom.Extent2I(ix*xRawExtent, iy*yRawExtent))
        else:
            amplifier.setRawXYOffset(geom.Extent2I(0, 0))

        amplifier.setReadoutCorner(readCorners[amp['readCorner']])
        amplifier.setGain(amp['gain'])
        amplifier.setReadNoise(amp['readNoise'])
        amplifier.setSaturation(amp['saturation'])
        amplifier.setSuspectLevel(amp.get('suspect', np.nan))

        # flip data when assembling if needs be (e.g. data from the serial at the top of a CCD)
        flipX, flipY = amp.get("flipXY")

        amplifier.setRawFlipX(flipX)
        amplifier.setRawFlipY(flipY)
        # linearity placeholder stuff
        amplifier.setLinearityCoeffs([float(val) for val in amp['linearityCoeffs']])
        amplifier.setLinearityType(amp['linearityType'])
        amplifier.setLinearityThreshold(float(amp['linearityThreshold']))
        amplifier.setLinearityMaximum(float(amp['linearityMax']))
        amplifier.setLinearityUnits("DN")
        amplifierList.append(amplifier)
    return amplifierList
Exemplo n.º 6
0
def makeAmpTables(segmentsFile, gainFile):
    """
    Read the segments file from a PhoSim release and produce the appropriate AmpInfo

    @param segmentsFile (str) full path to the segmentation file.
    @param gainFile (str) full path to the gain/saturation file.

    @return (dict) per amp dictionary of ampCatalogs
    """
    gainDict = {}
    with open(gainFile) as fh:
        for l in fh:
            els = l.rstrip().split()
            gainDict[els[0]] = {
                'gain': float(els[1]),
                'saturation': int(els[2])
            }
    returnDict = {}
    # TODO currently there is no linearity provided, but we should identify
    # how to get this information.
    linearityCoeffs = (0., 1., 0., 0.)
    linearityType = NullLinearityType
    readoutMap = {
        'LL': ReadoutCorner.LL,
        'LR': ReadoutCorner.LR,
        'UR': ReadoutCorner.UR,
        'UL': ReadoutCorner.UL
    }

    ampCatalog = []
    detectorName = [
    ]  # set to a value that is an invalid dict key, to catch bugs
    correctY0 = False
    with open(segmentsFile) as fh:
        for l in fh:
            if l.startswith("#"):
                continue

            els = l.rstrip().split()
            if len(els) == 4:
                if len(ampCatalog) != 0:
                    returnDict[detectorName] = ampCatalog
                detectorName = expandDetectorName(els[0])
                numy = int(els[2])

                ampCatalog = []
                if len(els[0].split('_')) == 3:  # wavefront sensor
                    correctY0 = True
                else:
                    correctY0 = False
                continue
            amplifier = Amplifier.Builder()
            name = els[0].split("_")[-1]
            name = '%s,%s' % (name[1], name[2])
            # Because of the camera coordinate system, we choose an
            # image coordinate system that requires a -90 rotation to get
            # the correct pixel positions from the
            # phosim segments file
            y0 = numy - 1 - int(els[2])
            y1 = numy - 1 - int(els[1])
            # Another quirk of the phosim file is that one of the wavefront sensor
            # chips has an offset of 2000 pix in y.  It's always the 'C1' chip.
            if correctY0:
                if y0 > 0:
                    y1 -= y0
                    y0 = 0
            x0 = int(els[3])
            x1 = int(els[4])
            try:
                saturation = gainDict[els[0]]['saturation']
                gain = gainDict[els[0]]['gain']
            except KeyError:
                # Set default if no gain exists
                saturation = 65535
                gain = float(els[7])
            readnoise = float(els[11])
            bbox = geom.Box2I(geom.Point2I(x0, y0), geom.Point2I(x1, y1))

            if int(els[5]) == -1:
                flipx = False
            else:
                flipx = True
            if int(els[6]) == 1:
                flipy = False
            else:
                flipy = True

            # Since the amps are stored in amp coordinates, the readout is the same
            # for all amps
            readCorner = readoutMap['LL']

            ndatax = x1 - x0 + 1
            ndatay = y1 - y0 + 1
            # Because in versions v3.3.2 and earlier there was no overscan, we use the extended register
            # as the overscan region
            prescan = 1
            hoverscan = 0
            extended = 4
            voverscan = 0
            rawBBox = geom.Box2I(
                geom.Point2I(0, 0),
                geom.Extent2I(extended + ndatax + hoverscan,
                              prescan + ndatay + voverscan))
            rawDataBBox = geom.Box2I(geom.Point2I(extended, prescan),
                                     geom.Extent2I(ndatax, ndatay))
            rawHorizontalOverscanBBox = geom.Box2I(
                geom.Point2I(0, prescan), geom.Extent2I(extended, ndatay))
            rawVerticalOverscanBBox = geom.Box2I(
                geom.Point2I(extended, prescan + ndatay),
                geom.Extent2I(ndatax, voverscan))
            rawPrescanBBox = geom.Box2I(geom.Point2I(extended, 0),
                                        geom.Extent2I(ndatax, prescan))

            extraRawX = extended + hoverscan
            extraRawY = prescan + voverscan
            rawx0 = x0 + extraRawX * (x0 // ndatax)
            rawy0 = y0 + extraRawY * (y0 // ndatay)
            # Set the elements of the amplifier for this amp
            amplifier.setBBox(bbox)
            amplifier.setName(name)
            amplifier.setReadoutCorner(readCorner)
            amplifier.setGain(gain)
            amplifier.setSaturation(saturation)
            amplifier.setSuspectLevel(float("nan"))
            amplifier.setReadNoise(readnoise)
            amplifier.setLinearityCoeffs(linearityCoeffs)
            amplifier.setLinearityType(linearityType)
            #            amplifier.setHasRawInfo(True)
            amplifier.setRawFlipX(flipx)
            amplifier.setRawFlipY(flipy)
            amplifier.setRawBBox(rawBBox)
            amplifier.setRawXYOffset(geom.Extent2I(rawx0, rawy0))
            amplifier.setRawDataBBox(rawDataBBox)
            amplifier.setRawHorizontalOverscanBBox(rawHorizontalOverscanBBox)
            amplifier.setRawVerticalOverscanBBox(rawVerticalOverscanBBox)
            amplifier.setRawPrescanBBox(rawPrescanBBox)
            ampCatalog.append(amplifier)
    returnDict[detectorName] = ampCatalog
    return returnDict