Esempio n. 1
0
    def test_overscanCorrection_isNotInt(self):
        """Expect smaller median/smaller std after.
        Expect exception if overscan fit type isn't known.
        """
        inputExp = isrMock.RawMock().run()

        amp = inputExp.getDetector()[0]
        ampI = inputExp.maskedImage[amp.getRawDataBBox()]
        overscanI = inputExp.maskedImage[amp.getRawHorizontalOverscanBBox()]

        for fitType in ('MEAN', 'MEDIAN', 'MEANCLIP', 'POLY', 'CHEB',
                        'NATURAL_SPLINE', 'CUBIC_SPLINE', 'UNKNOWN'):
            if fitType in ('NATURAL_SPLINE', 'CUBIC_SPLINE'):
                order = 3
            else:
                order = 1

            if fitType == 'UNKNOWN':
                with self.assertRaises(pexExcept.Exception,
                                       msg=f"overscanCorrection overscanIsNotInt fitType: {fitType}"):
                    ipIsr.overscanCorrection(ampI, overscanI, fitType=fitType,
                                             order=order, collapseRej=3.0,
                                             statControl=None, overscanIsInt=False)
            else:
                response = ipIsr.overscanCorrection(ampI, overscanI, fitType=fitType,
                                                    order=order, collapseRej=3.0,
                                                    statControl=None, overscanIsInt=False)
            self.assertIsInstance(response, pipeBase.Struct,
                                  msg=f"overscanCorrection overscanIsNotInt Bad response: {fitType}")
            self.assertIsNotNone(response.imageFit,
                                 msg=f"overscanCorrection overscanIsNotInt Bad imageFit: {fitType}")
            self.assertIsNotNone(response.overscanFit,
                                 msg=f"overscanCorrection overscanIsNotInt Bad overscanFit: {fitType}")
            self.assertIsInstance(response.overscanImage, afwImage.MaskedImageF,
                                  msg=f"overscanCorrection overscanIsNotInt Bad overscanImage: {fitType}")
    def checkPolyOverscanCorrectionY(self, **kwargs):
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                             afwGeom.Point2I(9, 12))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        dataBox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(10, 10))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)

        # these should be functionally equivalent
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 10),
                             afwGeom.Point2I(9, 12))
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)
        for i in range(bbox.getDimensions()[0]):
            for j, off in enumerate([-0.5, 0.0, 0.5]):
                overscan.image[i, j, afwImage.LOCAL] = 2+i+off

        ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs)

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if j == 10:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], -0.5)
                elif j == 11:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0)
                elif j == 12:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0.5)
                else:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 10 - 2 - i)
    def testOverscanCorrectionX(self, **kwargs):
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(12, 9))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        dataBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                afwGeom.Extent2I(10, 10))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)

        # these should be functionally equivalent
        bbox = afwGeom.Box2I(afwGeom.Point2I(10, 0), afwGeom.Point2I(12, 9))
        biassec = '[11:13,1:10]'
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)

        exposure = afwImage.ExposureF(maskedImage, None)
        metadata = exposure.getMetadata()
        metadata.setString(self.overscanKeyword, biassec)

        ipIsr.overscanCorrection(dataImage,
                                 overscan.getImage(),
                                 fitType="MEDIAN")

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if i >= 10:
                    self.assertEqual(maskedImage.getImage().get(i, j), 0)
                else:
                    self.assertEqual(maskedImage.getImage().get(i, j), 8)
    def checkPolyOverscanCorrectionX(self, **kwargs):
        bbox = afwGeom.Box2I(afwGeom.Point2I(0,0),
                            afwGeom.Point2I(12,9))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        # these should be functionally equivalent
        bbox     = afwGeom.Box2I(afwGeom.Point2I(10,0),
                                 afwGeom.Point2I(12,9))
        biassec  = '[11:13,1:10]'
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)
        for i in range(bbox.getDimensions()[1]):
            for j,off in enumerate([-0.5, 0.0, 0.5]):
                overscan.getImage().set(j,i,2+i+off)

        exposure = afwImage.ExposureF(maskedImage, None)

        ipIsr.overscanCorrection(maskedImage, overscan.getImage(), **kwargs)

        height        = maskedImage.getHeight()
        width         = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if i == 10:
                    self.assertEqual(maskedImage.getImage().get(i,j), -0.5)
                elif i == 11:
                    self.assertEqual(maskedImage.getImage().get(i,j), 0)
                elif i == 12:
                    self.assertEqual(maskedImage.getImage().get(i,j), 0.5)
                else:
                    self.assertEqual(maskedImage.getImage().get(i,j), 10 - 2 - j)
    def checkPolyOverscanCorrectionY(self, **kwargs):
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Point2I(9, 12))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        dataBox = afwGeom.Box2I(afwGeom.Point2I(0, 0),
                                afwGeom.Extent2I(10, 10))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)

        # these should be functionally equivalent
        bbox = afwGeom.Box2I(afwGeom.Point2I(0, 10), afwGeom.Point2I(9, 12))
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)
        for i in range(bbox.getDimensions()[0]):
            for j, off in enumerate([-0.5, 0.0, 0.5]):
                overscan.getImage().set(i, j, 2 + i + off)

        ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs)

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if j == 10:
                    self.assertEqual(maskedImage.getImage().get(i, j), -0.5)
                elif j == 11:
                    self.assertEqual(maskedImage.getImage().get(i, j), 0)
                elif j == 12:
                    self.assertEqual(maskedImage.getImage().get(i, j), 0.5)
                else:
                    self.assertEqual(maskedImage.getImage().get(i, j),
                                     10 - 2 - i)
Esempio n. 6
0
    def testOverscanCorrectionY(self, **kwargs):
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Point2I(9, 12))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(10, 10))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)

        # these should be functionally equivalent
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 10),
                               lsst.geom.Point2I(9, 12))
        biassec = '[1:10,11:13]'
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)

        exposure = afwImage.ExposureF(maskedImage, None)
        metadata = exposure.getMetadata()
        metadata.setString(self.overscanKeyword, biassec)

        ipIsr.overscanCorrection(dataImage, overscan.getImage(), fitType="MEDIAN")

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if j >= 10:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 0)
                else:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL], 8)
    def testOverscanCorrectionX(self, **kwargs):
        bbox = afwGeom.Box2I(afwGeom.Point2I(0,0),
                            afwGeom.Point2I(12,9))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        # these should be functionally equivalent
        bbox     = afwGeom.Box2I(afwGeom.Point2I(10,0),
                                 afwGeom.Point2I(12,9))
        biassec  = '[11:13,1:10]'
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)
        
        exposure = afwImage.ExposureF(maskedImage, None)
        metadata = exposure.getMetadata()
        metadata.setString(self.overscanKeyword, biassec)

        ipIsr.overscanCorrection(maskedImage, overscan.getImage(), fitType = "MEDIAN")

        height        = maskedImage.getHeight()
        width         = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if i >= 10:
                    self.assertEqual(maskedImage.getImage().get(i,j), 0)
                else:
                    self.assertEqual(maskedImage.getImage().get(i,j), 8)
Esempio n. 8
0
    def overscanCorrection(self, exposure, amp):
        """Apply overscan correction in place

        If the input exposure is on the readout backplanes listed in
        config.overscanBiasJumpBKP, cut the amplifier in two vertically
        and correct each piece separately.

        @param[in,out] exposure: exposure to process; must include both
                                 DataSec and BiasSec pixels
        @param[in] amp: amplifier device data
        """
        if not (
            exposure.getMetadata().exists("FPA")
            and exposure.getMetadata().get("FPA") in self.config.overscanBiasJumpBKP
        ):
            IsrTask.overscanCorrection(self, exposure, amp)
            return

        dataBox = amp.getRawDataBBox()
        overscanBox = amp.getRawHorizontalOverscanBBox()

        if amp.getReadoutCorner() in (afwTable.LL, afwTable.LR):
            yLower = self.config.overscanBiasJumpLocation
            yUpper = dataBox.getHeight() - yLower
        else:
            yUpper = self.config.overscanBiasJumpLocation
            yLower = dataBox.getHeight() - yUpper

        lowerDataBBox = afwGeom.Box2I(dataBox.getBegin(), afwGeom.Extent2I(dataBox.getWidth(), yLower))
        upperDataBBox = afwGeom.Box2I(
            dataBox.getBegin() + afwGeom.Extent2I(0, yLower), afwGeom.Extent2I(dataBox.getWidth(), yUpper)
        )
        lowerOverscanBBox = afwGeom.Box2I(overscanBox.getBegin(), afwGeom.Extent2I(overscanBox.getWidth(), yLower))
        upperOverscanBBox = afwGeom.Box2I(
            overscanBox.getBegin() + afwGeom.Extent2I(0, yLower), afwGeom.Extent2I(overscanBox.getWidth(), yUpper)
        )

        maskedImage = exposure.getMaskedImage()
        lowerDataView = maskedImage.Factory(maskedImage, lowerDataBBox)
        upperDataView = maskedImage.Factory(maskedImage, upperDataBBox)

        expImage = exposure.getMaskedImage().getImage()
        lowerOverscanImage = expImage.Factory(expImage, lowerOverscanBBox)
        upperOverscanImage = expImage.Factory(expImage, upperOverscanBBox)

        overscanCorrection(
            ampMaskedImage=lowerDataView,
            overscanImage=lowerOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )
        overscanCorrection(
            ampMaskedImage=upperDataView,
            overscanImage=upperOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )
    def test_overscanCorrection_isNotInt(self):
        """Expect smaller median/smaller std after.
        Expect exception if overscan fit type isn't known.
        """
        inputExp = isrMock.RawMock().run()

        amp = inputExp.getDetector()[0]
        ampI = inputExp.maskedImage[amp.getRawDataBBox()]
        overscanI = inputExp.maskedImage[amp.getRawHorizontalOverscanBBox()]

        for fitType in ('MEAN', 'MEDIAN', 'MEANCLIP', 'POLY', 'CHEB',
                        'NATURAL_SPLINE', 'CUBIC_SPLINE', 'UNKNOWN'):
            if fitType in ('NATURAL_SPLINE', 'CUBIC_SPLINE'):
                order = 3
            else:
                order = 1

            if fitType == 'UNKNOWN':
                with self.assertRaises(
                        pexExcept.Exception,
                        msg=
                        f"overscanCorrection overscanIsNotInt fitType: {fitType}"
                ):
                    ipIsr.overscanCorrection(ampI,
                                             overscanI,
                                             fitType=fitType,
                                             order=order,
                                             collapseRej=3.0,
                                             statControl=None,
                                             overscanIsInt=False)
            else:
                response = ipIsr.overscanCorrection(ampI,
                                                    overscanI,
                                                    fitType=fitType,
                                                    order=order,
                                                    collapseRej=3.0,
                                                    statControl=None,
                                                    overscanIsInt=False)
            self.assertIsInstance(
                response,
                pipeBase.Struct,
                msg=
                f"overscanCorrection overscanIsNotInt Bad response: {fitType}")
            self.assertIsNotNone(
                response.imageFit,
                msg=
                f"overscanCorrection overscanIsNotInt Bad imageFit: {fitType}")
            self.assertIsNotNone(
                response.overscanFit,
                msg=
                f"overscanCorrection overscanIsNotInt Bad overscanFit: {fitType}"
            )
            self.assertIsInstance(
                response.overscanImage,
                afwImage.MaskedImageF,
                msg=
                f"overscanCorrection overscanIsNotInt Bad overscanImage: {fitType}"
            )
Esempio n. 10
0
    def checkOverscanCorrectionSineWave(self, **kwargs):
        """vertical sine wave along long direction"""

        # Full image: (500,100)
        longAxis = 500
        shortAxis = 100
        overscanWidth = 30

        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Point2I(shortAxis - 1, longAxis - 1))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(50.0, 0x0, 1)

        # vertical sine wave along long direction
        x = np.linspace(0, 2 * 3.14159, longAxis)
        a, w = 15, 50 * 3.14159
        sineWave = 20 + a * np.sin(w * x)
        sineWave = sineWave.astype(int)

        fullImage = np.repeat(sineWave, shortAxis).reshape(
            (longAxis, shortAxis))
        maskedImage.image.array += fullImage

        # data part of the full image: (500,70)
        dataBox = lsst.geom.Box2I(
            lsst.geom.Point2I(0, 0),
            lsst.geom.Extent2I(shortAxis - overscanWidth, longAxis))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)
        # these should be functionally equivalent
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(shortAxis - overscanWidth, 0),
                               lsst.geom.Point2I(shortAxis - 1, longAxis - 1))
        biassec = '[1:500,71:100]'
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.image.array -= 50.0  # subtract initial pedestal

        exposure = afwImage.ExposureF(maskedImage, None)
        metadata = exposure.getMetadata()
        metadata.setString(self.overscanKeyword, biassec)

        ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs)

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()

        for j in range(height):
            for i in range(width):
                if i >= 70:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     0.0)
                else:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     50.0)
    def process(self, clipboard):
        """
        """
        self.log.log(Log.INFO, "Doing overscan subtraction.")
        
        #grab exposure and overscan bbox from clipboard
        exposure = clipboard.get(self.policy.getString("inputKeys.exposure"))
	fittype = self.policy.getString("parameters.overscanFitType")
	amp = cameraGeom.cast_Amp(exposure.getDetector())
        overscanBbox = amp.getDiskBiasSec()
        dataBbox = amp.getDiskDataSec()
        #It just so happens that this is an o.k. place to put the SDQA
        #calculation because the ratings requested at the moment can all be
        #calculated here.  If, for example, an Amp rating an the flat fielded
        #amp were requested, it would have to be calculated separately.
        ipIsr.calculateSdqaAmpRatings(exposure, overscanBbox, dataBbox)
        ipIsr.overscanCorrection(exposure, overscanBbox, fittype)
        #TODO optionally trim
        #output products
        clipboard.put(self.policy.get("outputKeys.overscanCorrectedExposure"), exposure)
    def process(self, clipboard):
        """
        """
        self.log.log(Log.INFO, "Doing overscan subtraction.")

        #grab exposure and overscan bbox from clipboard
        exposure = clipboard.get(self.policy.getString("inputKeys.exposure"))
        fittype = self.policy.getString("parameters.overscanFitType")
        amp = cameraGeom.cast_Amp(exposure.getDetector())
        overscanBbox = amp.getDiskBiasSec()
        dataBbox = amp.getDiskDataSec()
        #It just so happens that this is an o.k. place to put the SDQA
        #calculation because the ratings requested at the moment can all be
        #calculated here.  If, for example, an Amp rating an the flat fielded
        #amp were requested, it would have to be calculated separately.
        ipIsr.calculateSdqaAmpRatings(exposure, overscanBbox, dataBbox)
        ipIsr.overscanCorrection(exposure, overscanBbox, fittype)
        #TODO optionally trim
        #output products
        clipboard.put(self.policy.get("outputKeys.overscanCorrectedExposure"),
                      exposure)
    def checkPolyOverscanCorrectionX(self, **kwargs):
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                               lsst.geom.Point2I(12, 9))
        maskedImage = afwImage.MaskedImageF(bbox)
        maskedImage.set(10, 0x0, 1)

        dataBox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
                                  lsst.geom.Extent2I(10, 10))
        dataImage = afwImage.MaskedImageF(maskedImage, dataBox)

        # these should be functionally equivalent
        bbox = lsst.geom.Box2I(lsst.geom.Point2I(10, 0),
                               lsst.geom.Point2I(12, 9))
        overscan = afwImage.MaskedImageF(maskedImage, bbox)
        overscan.set(2, 0x0, 1)
        for i in range(bbox.getDimensions()[1]):
            for j, off in enumerate([-0.5, 0.0, 0.5]):
                overscan.image[j, i, afwImage.LOCAL] = 2 + i + off

        ipIsr.overscanCorrection(dataImage, overscan.getImage(), **kwargs)

        height = maskedImage.getHeight()
        width = maskedImage.getWidth()
        for j in range(height):
            for i in range(width):
                if i == 10:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     -0.5)
                elif i == 11:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     0)
                elif i == 12:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     0.5)
                else:
                    self.assertEqual(maskedImage.image[i, j, afwImage.LOCAL],
                                     10 - 2 - j)
Esempio n. 14
0
    def overscanCorrection(self, exposure, amp):
        """Apply overscan correction in place

        If the input exposure is on the readout backplanes listed in
        config.overscanBiasJumpBKP, cut the amplifier in two vertically
        and correct each piece separately.

        @param[in,out] exposure: exposure to process; must include both
                                 DataSec and BiasSec pixels
        @param[in] amp: amplifier device data
        """
        if not (exposure.getMetadata().exists('FPA')
                and exposure.getMetadata().get('FPA')
                in self.config.overscanBiasJumpBKP):
            IsrTask.overscanCorrection(self, exposure, amp)
            return

        dataBox = amp.getRawDataBBox()
        overscanBox = amp.getRawHorizontalOverscanBBox()

        if amp.getReadoutCorner() in (afwTable.LL, afwTable.LR):
            yLower = self.config.overscanBiasJumpLocation
            yUpper = dataBox.getHeight() - yLower
        else:
            yUpper = self.config.overscanBiasJumpLocation
            yLower = dataBox.getHeight() - yUpper

        lowerDataBBox = afwGeom.Box2I(
            dataBox.getBegin(), afwGeom.Extent2I(dataBox.getWidth(), yLower))
        upperDataBBox = afwGeom.Box2I(
            dataBox.getBegin() + afwGeom.Extent2I(0, yLower),
            afwGeom.Extent2I(dataBox.getWidth(), yUpper))
        lowerOverscanBBox = afwGeom.Box2I(
            overscanBox.getBegin(),
            afwGeom.Extent2I(overscanBox.getWidth(), yLower))
        upperOverscanBBox = afwGeom.Box2I(
            overscanBox.getBegin() + afwGeom.Extent2I(0, yLower),
            afwGeom.Extent2I(overscanBox.getWidth(), yUpper))

        maskedImage = exposure.getMaskedImage()
        lowerDataView = maskedImage.Factory(maskedImage, lowerDataBBox)
        upperDataView = maskedImage.Factory(maskedImage, upperDataBBox)

        expImage = exposure.getMaskedImage().getImage()
        lowerOverscanImage = expImage.Factory(expImage, lowerOverscanBBox)
        upperOverscanImage = expImage.Factory(expImage, upperOverscanBBox)

        overscanCorrection(
            ampMaskedImage=lowerDataView,
            overscanImage=lowerOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )
        overscanCorrection(
            ampMaskedImage=upperDataView,
            overscanImage=upperOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )
def draw_bias_sequence(exposures, amp_num=None, overscan_correct=False, \
                save_fig=False, same_scale=True, run_num=None, lsst_num=None, \
                raft=None, detector_name=None, plot_medians=False):

    figdims = (10, 8)
    if amp_num is None:
        figdims = (15, 5)

    fig, axes = plt.subplots(nrows=1, ncols=len(exposures), figsize=figdims)
    clow, chigh = None, None
    if run_num is None:
        run_num = exposures[0].getInfo().getMetadata()['RUNNUM']
    if lsst_num is None:
        lsst_num = exposures[0].getInfo().getMetadata()['LSST_NUM']
    if raft is None: raft = exposures[0].getInfo().getMetadata()['RAFTBAY']
    if detector_name is None:
        detector_name = exposures[0].getInfo().getMetadata()['CCDSLOT']

    arrays = []
    medians = []
    ampnames = []

    for i in range(len(exposures))[::-1]:

        raw = exposures[i]
        detector = raw.getDetector()

        array = None

        if amp_num is not None:
            amp = detector[amp_num]
            im = raw.getMaskedImage()[amp.getRawBBox()].clone()
            if overscan_correct:
                isr.overscanCorrection(im[amp.getRawDataBBox()],
                                       im[amp.getRawHorizontalOverscanBBox()],
                                       fitType='MEDIAN_PER_ROW')
            array = im[amp.getRawDataBBox()].getImage().getArray().copy()

            if plot_medians:
                medians.append(np.median(array))
            del im
        else:
            raw_clone = raw.clone()

            median_by_amp = []

            if plot_medians:
                for amp in detector:
                    median = afwMath.makeStatistics(
                        raw.getMaskedImage()[amp.getRawDataBBox()],
                        afwMath.MEDIAN).getValue()
                    median_by_amp.append(median)
                    if not len(ampnames) == 16:
                        ampnames.append(amp.getName())

            #print(median_by_amp)
            medians.append(median_by_amp)

            task = isr.isrTask.IsrTask()
            task.config.doAssembleCcd = True
            task.assembleCcd.config.doTrim = True
            task.config.overscanFitType = 'MEDIAN_PER_ROW'
            task.config.doOverscan = overscan_correct
            task.config.doBias = False
            task.config.doLinearize = False
            task.config.doDark = False
            task.config.doFlat = False
            task.config.doDefect = False

            assembled = task.run(raw_clone).exposure
            array = assembled.getImage().getArray().copy()
            del assembled, raw_clone

        if not same_scale:
            implot = axes[i].imshow(array, cmap='gist_heat')
            axes[i].set_axis_off()
            divider = make_axes_locatable(axes[i])
            cax = divider.new_vertical(size="5%", pad=0.1, pack_start=True)
            fig.add_axes(cax)
            cbar = fig.colorbar(implot, cax=cax, orientation="horizontal")
            cbar.set_label('Raw ADU'.format(' (Median Row Overscan Corrected)'
                                            if overscan_correct else ''))
            continue

        arrays.append(array)

        this_clow = np.amin(array)
        this_chigh = np.amax(array)
        if clow is None:
            clow = this_clow
        elif this_clow < clow:
            clow = this_clow
        if chigh is None:
            chigh = this_chigh
        elif this_chigh > chigh:
            chigh = this_chigh

    fig.patch.set_facecolor('white')
    fig.suptitle('Consecutive biases in run {}, {} {} {} : {}'.format(
        run_num, raft, detector_name, '' if
        (amp_num is None) else 'Amp {}'.format(amp_num), lsst_num))

    if same_scale:
        for i in range(len(exposures))[::-1]:
            array = arrays[::-1][i]
            im = axes[i].imshow(array, clim=(clow, chigh), cmap='gist_heat')
            axes[i].set_axis_off()
        if amp_num is None: fig.tight_layout(rect=[0, 0, 1, 1.1])
        else: fig.tight_layout(rect=[0, 0, 1, 0.95])
        cbar = fig.colorbar(im, ax=axes.ravel().tolist(), shrink=.7)
        cbar.set_label('Raw ADU{}'.format(
            ' (Median Row Overscan Corrected)' if overscan_correct else ''))
    else:
        fig.tight_layout(rect=[0, 0, 1, .95])

    if save_fig:
        im_path = '{}/{}/{}'.format(run_num, raft, detector_name)
        Path(im_path).mkdir(parents=True, exist_ok=True)
        plt.savefig('{}/biases_{}_{}_{}_Amp{:02d}'.format(
            im_path, run_num, raft, detector_name, amp_num))

    plt.show()

    if plot_medians:
        fig = plt.figure()
        plt.plot([str(x) for x in range(1, len(exposures) + 1)], medians[::-1])
        fig.patch.set_facecolor('white')
        plt.xlabel('Exposure')
        plt.ylabel('Median Pixel Value (ADU)')
        plt.legend(ampnames, bbox_to_anchor=(1.25, 1))
        plt.show()
    plt.close()
    return np.array(medians)
def bias_sequence(exposures, amp_num=None, overscan_correct=False, \
                save_fig=False, same_scale=True, run_num=None, lsst_num=None, \
                raft=None, detector_name=None, plot_medians=True, outfile=None):

    if run_num is None:
        run_num = exposures[0].getInfo().getMetadata()['RUNNUM']
    if lsst_num is None:
        lsst_num = exposures[0].getInfo().getMetadata()['LSST_NUM']
    if raft is None: raft = exposures[0].getInfo().getMetadata()['RAFTBAY']
    if detector_name is None:
        detector_name = exposures[0].getInfo().getMetadata()['CCDSLOT']

    arrays = []
    medians = []
    higherrs = []
    lowerrs = []
    ampnames = []

    for i in range(len(exposures)):

        raw = exposures[i]
        detector = raw.getDetector()

        array = None

        if amp_num is not None:
            amp = detector[amp_num]
            im = raw.getMaskedImage()[amp.getRawBBox()].clone()
            if overscan_correct:
                isr.overscanCorrection(im[amp.getRawDataBBox()],
                                       im[amp.getRawHorizontalOverscanBBox()],
                                       fitType='MEDIAN_PER_ROW')
            array = im[amp.getRawDataBBox()].getImage().getArray().copy()
            median = np.median(array)
            higherr = np.percentile(array, 84)
            lowerr = np.percentile(array, 16)

            medians.append(median)
            higherrs.append(higherr)
            lowerrs.append(lowerr)

            del im
        else:

            median_by_amp = []
            higherr_by_amp = []
            lowerr_by_amp = []

            if plot_medians:
                for amp in detector:

                    im = raw.getMaskedImage()[amp.getRawDataBBox()]
                    array = im.getImage().getArray().copy()
                    median = np.median(array)
                    higherr = np.percentile(array, 84) - median
                    lowerr = np.percentile(array, 16) - median

                    median_by_amp.append(median)
                    higherr_by_amp.append(higherr)
                    lowerr_by_amp.append(lowerr)

                    if not len(ampnames) == 16:
                        ampnames.append(amp.getName())

            medians.append(median_by_amp)
            higherrs.append(higherr_by_amp)
            lowerrs.append(lowerr_by_amp)

    medians_arr = np.array(medians)
    higherrs_arr = np.array(higherrs)
    lowerrs_arr = np.array(lowerrs)

    if plot_medians:
        fig = plt.figure()
        for i in range(len(ampnames)):
            plt.errorbar([str(x) for x in range(1,
                                                len(exposures) + 1)],
                         medians_arr[:, i],
                         yerr=[lowerrs_arr[:, i], higherrs_arr[:, i]])
        fig.patch.set_facecolor('white')
        plt.xlabel('Exposure')
        plt.ylabel('Median Pixel Value (ADU)')
        plt.legend([
            '{}: std = {:.1f} ADU'.format(ampnames[i],
                                          np.std(medians_arr[1:, i]))
            for i in range(len(ampnames))
        ],
                   bbox_to_anchor=(1.25, 1))
        fig.suptitle('Consecutive biases in run {}, {} {} {} : {}'.format(
            run_num, raft, detector_name, '' if
            (amp_num is None) else 'Amp {}'.format(amp_num), lsst_num))
        plt.show()
    plt.close()

    if not outfile is None:
        filename = 'bias_seqs/{}/bias_seqs_{}_{}_{}_{}.csv'.format(
            lsst_num, run_num, raft, detector_name, lsst_num)
        if not outfile == True:
            filename = outfile
        else:
            outdir = 'bias_seqs/{}'.format(lsst_num)
            os.makedirs(outdir, exist_ok=True)

        out = csv.writer(open(filename, 'w'))
        header = [
            'Amp', 'Exposure Number', 'Median Bias (ADU)', 'High Error (ADU)',
            'Low Error (ADU)'
        ]
        out.writerow(header)
        for ampnum in range(len(ampnames)):
            for expnum in range(len(exposures)):
                row = [
                    ampnames[ampnum], expnum, medians_arr[expnum, ampnum],
                    higherrs_arr[expnum, ampnum], lowerrs_arr[expnum, ampnum]
                ]
                out.writerow(row)
    return medians_arr, higherrs_arr, lowerrs_arr
Esempio n. 17
0
    def overscanCorrection(self, exposure, amp):
        """Apply overscan correction in place

        If the input exposure is on the readout backplanes listed in
        config.overscanBiasJumpBKP, cut the amplifier in two vertically
        and correct each piece separately.

        Parameters
        ----------
        exposure: `lsst.afw.image.Exposure`
            exposure to process; must include both DataSec and BiasSec pixels
        amp: `lsst.afw.table.AmpInfoRecord`
            amplifier device data

        Returns
        -------
        exposure: `lsst.afw.image.Exposure`
            exposure corrected in place with updated metadata
        """
        if not (exposure.getMetadata().exists('FPA')
                and exposure.getMetadata().get('FPA')
                in self.config.overscanBiasJumpBKP):
            IsrTask.overscanCorrection(self, exposure, amp)
            return

        dataBox = amp.getRawDataBBox()
        overscanBox = amp.getRawHorizontalOverscanBBox()

        if amp.getReadoutCorner() in (afwTable.LL, afwTable.LR):
            yLower = self.config.overscanBiasJumpLocation
            yUpper = dataBox.getHeight() - yLower
        else:
            yUpper = self.config.overscanBiasJumpLocation
            yLower = dataBox.getHeight() - yUpper

        lowerDataBBox = afwGeom.Box2I(
            dataBox.getBegin(), afwGeom.Extent2I(dataBox.getWidth(), yLower))
        upperDataBBox = afwGeom.Box2I(
            dataBox.getBegin() + afwGeom.Extent2I(0, yLower),
            afwGeom.Extent2I(dataBox.getWidth(), yUpper))
        lowerOverscanBBox = afwGeom.Box2I(
            overscanBox.getBegin(),
            afwGeom.Extent2I(overscanBox.getWidth(), yLower))
        upperOverscanBBox = afwGeom.Box2I(
            overscanBox.getBegin() + afwGeom.Extent2I(0, yLower),
            afwGeom.Extent2I(overscanBox.getWidth(), yUpper))

        maskedImage = exposure.getMaskedImage()
        lowerDataView = maskedImage.Factory(maskedImage, lowerDataBBox)
        upperDataView = maskedImage.Factory(maskedImage, upperDataBBox)

        expImage = exposure.getMaskedImage().getImage()
        lowerOverscanImage = expImage.Factory(expImage, lowerOverscanBBox)
        upperOverscanImage = expImage.Factory(expImage, upperOverscanBBox)

        overscanCorrection(
            ampMaskedImage=lowerDataView,
            overscanImage=lowerOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )
        overscanCorrection(
            ampMaskedImage=upperDataView,
            overscanImage=upperOverscanImage,
            fitType=self.config.overscanFitType,
            order=self.config.overscanOrder,
            collapseRej=self.config.overscanRej,
        )

        # Note that overscan correction has been done in exposure metadata
        metadata = exposure.getMetadata()
        metadata.set(
            'OVERSCAN', 'Overscan corrected on {0}'.format(
                dt.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")))
        exposure.setMetadata(metadata)