def testNoPsf(self):
     """Test InstallGaussianPsfTask when the input exposure has no PSF."""
     for width in (21, 25):
         for fwhm in (2.8, 7.1):
             config = InstallGaussianPsfTask.ConfigClass()
             config.width = width
             config.fwhm = fwhm
             task = InstallGaussianPsfTask(config=config)
             exposure = ExposureF(100, 100)
             task.run(exposure=exposure)
             self.assertTrue(exposure.hasPsf())
             psf = exposure.getPsf()
             psfIm = psf.computeImage()
             self.assertEqual(psfIm.getWidth(), width)
             self.assertEqual(psfIm.getHeight(), width)
             measFwhm = psf.computeShape().getDeterminantRadius()*FwhmPerSigma
             self.assertAlmostEqual(measFwhm, fwhm, delta=1e-3)
    def testMatchSingleGaussianPsf(self):
        """Test InstallGaussianPsfTask when the input exposure has a single Gaussian PSF."""
        config = InstallGaussianPsfTask.ConfigClass()
        task = InstallGaussianPsfTask(config=config)

        for desWidth, desHeight, desSigma in (
            (21, 23, 1.2),
            (23, 25, 3.5),
        ):
            exposure = ExposureF(100, 100)
            inPsf = SingleGaussianPsf(desWidth, desHeight, desSigma)
            exposure.setPsf(inPsf)
            task.run(exposure=exposure)
            self.assertTrue(exposure.hasPsf())
            psf = exposure.getPsf()
            psfIm = psf.computeImage()
            self.assertEqual(psfIm.getWidth(), desWidth)
            self.assertEqual(psfIm.getHeight(), desHeight)
            self.assertAlmostEqual(psf.computeShape().getDeterminantRadius(), desSigma, delta=1e-3)
    def testMatchDoubleGaussianPsf(self):
        """Test InstallGaussianPsfTask when the input exposure has a DoubleGaussian PSF."""
        config = InstallGaussianPsfTask.ConfigClass()
        task = InstallGaussianPsfTask(config=config)

        for doubleGaussParms in (
            # width, height, inner sigma, outer sigma, outer/inner peak amplitude
            (21, 23, 1.2, 3.5, 0.02),
            (23, 25, 3.5, 9.0, 0.02),
        ):
            exposure = ExposureF(100, 100)
            inPsf = DoubleGaussianPsf(*doubleGaussParms)
            exposure.setPsf(inPsf)
            desWidth, desHeight, innerSigma = doubleGaussParms[0:3]
            task.run(exposure=exposure)
            self.assertTrue(exposure.hasPsf())
            psf = exposure.getPsf()
            psfIm = psf.computeImage()
            self.assertEqual(psfIm.getWidth(), desWidth)
            self.assertEqual(psfIm.getHeight(), desHeight)
            self.assertAlmostEqual(psf.computeShape().getDeterminantRadius(), innerSigma, delta=0.1)
Esempio n. 4
0
from lsst.afw.image import ExposureF
from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask, FwhmPerSigma

exposure = ExposureF(100, 100)
task = InstallGaussianPsfTask()
task.run(exposure=exposure)

# This particular exposure had no PSF model to begin with, so the new PSF model
# uses the config's FWHM. However, measured FWHM is based on the truncated
# PSF image, so it does not exactly match the input
measFwhm = exposure.getPsf().computeShape().getDeterminantRadius() * FwhmPerSigma
assert abs(measFwhm - task.config.fwhm) < 1e-3
Esempio n. 5
0
    def run(self,
            ccdExposure,
            *,
            camera=None,
            bias=None,
            dark=None,
            flat=None,
            defects=None,
            linearizer=None,
            crosstalk=None,
            bfKernel=None,
            bfGains=None,
            ptc=None,
            crosstalkSources=None,
            isrBaseConfig=None):
        """Run isr and cosmic ray repair using, doing as much isr as possible.

        Retrieves as many calibration products as are available, and runs isr
        with those settings enabled, but always returns an assembled image at
        a minimum. Then performs cosmic ray repair if configured to.

        Parameters
        ----------
        ccdExposure : `lsst.afw.image.Exposure`
            The raw exposure that is to be run through ISR.  The
            exposure is modified by this method.
        camera : `lsst.afw.cameraGeom.Camera`, optional
            The camera geometry for this exposure. Required if
            one or more of ``ccdExposure``, ``bias``, ``dark``, or
            ``flat`` does not have an associated detector.
        bias : `lsst.afw.image.Exposure`, optional
            Bias calibration frame.
        linearizer : `lsst.ip.isr.linearize.LinearizeBase`, optional
            Functor for linearization.
        crosstalk : `lsst.ip.isr.crosstalk.CrosstalkCalib`, optional
            Calibration for crosstalk.
        crosstalkSources : `list`, optional
            List of possible crosstalk sources.
        dark : `lsst.afw.image.Exposure`, optional
            Dark calibration frame.
        flat : `lsst.afw.image.Exposure`, optional
            Flat calibration frame.
        ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
            Photon transfer curve dataset, with, e.g., gains
            and read noise.
        bfKernel : `numpy.ndarray`, optional
            Brighter-fatter kernel.
        bfGains : `dict` of `float`, optional
            Gains used to override the detector's nominal gains for the
            brighter-fatter correction. A dict keyed by amplifier name for
            the detector in question.
        defects : `lsst.ip.isr.Defects`, optional
            List of defects.
        fringes : `lsst.pipe.base.Struct`, optional
            Struct containing the fringe correction data, with
            elements:
            - ``fringes``: fringe calibration frame (`afw.image.Exposure`)
            - ``seed``: random seed derived from the ccdExposureId for random
                number generator (`uint32`)
        opticsTransmission: `lsst.afw.image.TransmissionCurve`, optional
            A ``TransmissionCurve`` that represents the throughput of the,
            optics, to be evaluated in focal-plane coordinates.
        filterTransmission : `lsst.afw.image.TransmissionCurve`
            A ``TransmissionCurve`` that represents the throughput of the
            filter itself, to be evaluated in focal-plane coordinates.
        sensorTransmission : `lsst.afw.image.TransmissionCurve`
            A ``TransmissionCurve`` that represents the throughput of the
            sensor itself, to be evaluated in post-assembly trimmed detector
            coordinates.
        atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
            A ``TransmissionCurve`` that represents the throughput of the
            atmosphere, assumed to be spatially constant.
        detectorNum : `int`, optional
            The integer number for the detector to process.
        strayLightData : `object`, optional
            Opaque object containing calibration information for stray-light
            correction.  If `None`, no correction will be performed.
        illumMaskedImage : `lsst.afw.image.MaskedImage`, optional
            Illumination correction image.
        isrBaseConfig : `lsst.ip.isr.IsrTaskConfig`, optional
            An isrTask config to act as the base configuration. Options which
            involve applying a calibration product are ignored, but this allows
            for the configuration of e.g. the number of overscan columns.

        Returns
        -------
        result : `lsst.pipe.base.Struct`
            Result struct with component:
            - ``exposure`` : `afw.image.Exposure`
                The ISRed and cosmic-ray-repaired exposure.
        """
        isrConfig = isrBaseConfig if isrBaseConfig else IsrTask.ConfigClass()
        isrConfig.doBias = False
        isrConfig.doDark = False
        isrConfig.doFlat = False
        isrConfig.doFringe = False
        isrConfig.doDefect = False
        isrConfig.doLinearize = False
        isrConfig.doCrosstalk = False
        isrConfig.doBrighterFatter = False
        isrConfig.usePtcGains = False

        if bias:
            isrConfig.doBias = True
            self.log.info("Running with bias correction")

        if dark:
            isrConfig.doDark = True
            self.log.info("Running with dark correction")

        if flat:
            isrConfig.doFlat = True
            self.log.info("Running with flat correction")

        # TODO: deal with fringes here
        if defects:
            isrConfig.doDefect = True
            self.log.info("Running with defect correction")

        if linearizer:
            isrConfig.doLinearize = True
            self.log.info("Running with linearity correction")

        if crosstalk:
            isrConfig.doCrosstalk = True
            self.log.info("Running with crosstalk correction")

        if bfKernel:
            isrConfig.doBrighterFatter = True
            self.log.info("Running with brighter-fatter correction")

        if ptc:
            isrConfig.usePtcGains = True
            self.log.info("Running with ptc correction")

        isrConfig.doWrite = False
        isrTask = IsrTask(config=isrConfig)
        result = isrTask.run(
            ccdExposure,
            camera=camera,
            bias=bias,
            dark=dark,
            flat=flat,
            #  fringes=pipeBase.Struct(fringes=None),
            defects=defects,
            linearizer=linearizer,
            crosstalk=crosstalk,
            bfKernel=bfKernel,
            bfGains=bfGains,
            ptc=ptc,
            crosstalkSources=crosstalkSources,
            isGen3=True,
        )

        postIsr = result.exposure

        if self.config.doRepairCosmics:
            try:  # can fail due to too many CRs detected, and we always want an exposure back
                self.log.info("Repairing cosmics...")
                if postIsr.getPsf() is None:
                    installPsfTask = InstallGaussianPsfTask()
                    installPsfTask.run(postIsr)

                # TODO: try adding a reasonably wide Gaussian as a temp PSF
                # and then just running repairTask on its own without any
                # imChar. It should work, and be faster.
                repairConfig = CharacterizeImageTask.ConfigClass()
                repairConfig.doMeasurePsf = False
                repairConfig.doApCorr = False
                repairConfig.doDeblend = False
                repairConfig.doWrite = False
                repairConfig.repair.cosmicray.nCrPixelMax = 200000
                repairTask = CharacterizeImageTask(config=repairConfig)

                repairTask.repair.run(postIsr)
            except Exception as e:
                self.log.warning(f"During CR repair caught: {e}")

        # exposure is returned for convenience to mimic isrTask's API.
        return pipeBase.Struct(exposure=postIsr, outputExposure=postIsr)