745 ):
746 """Apply intra-detector crosstalk correction
747
748 Parameters
749 ----------
750 exposure : `lsst.afw.image.Exposure`
751 Exposure for which to remove crosstalk.
752 crosstalkCalib : `lsst.ip.isr.CrosstalkCalib`, optional
753 External crosstalk calibration to apply. Constructed from
754 detector if not found.
755 crosstalkSources : `defaultdict`, optional
756 Image data for other detectors that are sources of
757 crosstalk in exposure. The keys are expected to be names
758 of the other detectors, with the values containing
759 `lsst.afw.image.Exposure` at the same level of processing
760 as ``exposure``.
761 The default for intra-detector crosstalk here is None.
762 isTrimmed : `bool`, optional
763 The image is already trimmed.
764 This should no longer be needed once DM-15409 is resolved.
765 camera : `lsst.afw.cameraGeom.Camera`, optional
766 Camera associated with this exposure. Only used for
767 inter-chip matching.
768 parallelOverscanRegion : `bool`, optional
769 Do subtraction in parallel overscan region (only)?
770 detectorConfig : `lsst.ip.isr.OverscanDetectorConfig`, optional
771 Per-amplifier configs used when parallelOverscanRegion=True.
772
773 Raises
774 ------
775 RuntimeError
776 Raised if called for a detector that does not have a
777 crosstalk correction. Also raised if the crosstalkSource
778 is not an expected type.
779 """
780 if not crosstalk:
781 crosstalk = CrosstalkCalib(log=self.log)
782 crosstalk = crosstalk.fromDetector(exposure.getDetector(),
783 coeffVector=self.config.crosstalkValues)
784 if not crosstalk.log:
785 crosstalk.log = self.log
786 if not crosstalk.hasCrosstalk:
787 raise RuntimeError("Attempted to correct crosstalk without crosstalk coefficients.")
788 elif parallelOverscanRegion:
789 self.log.info("Applying crosstalk correction to parallel overscan region.")
790 crosstalk.subtractCrosstalkParallelOverscanRegion(
791 exposure,
792 crosstalkCoeffs=crosstalk.coeffs,
793 detectorConfig=detectorConfig,
794 )
795 else:
796 self.log.info("Applying crosstalk correction.")
797 crosstalk.subtractCrosstalk(exposure, crosstalkCoeffs=crosstalk.coeffs,
798 minPixelToMask=self.config.minPixelToMask,
799 crosstalkStr=self.config.crosstalkMaskPlane, isTrimmed=isTrimmed,
800 backgroundMethod=self.config.crosstalkBackgroundMethod)
801
802 if crosstalk.interChip:
803 if crosstalkSources:
804
805
807
808 sourceNames = [exp.getDetector().getName() for exp in crosstalkSources]
809 elif isinstance(crosstalkSources[0], lsst.daf.butler.DeferredDatasetHandle):
810
811 detectorList = [source.dataId['detector'] for source in crosstalkSources]
812 sourceNames = [camera[detector].getName() for detector in detectorList]
813 else:
814 raise RuntimeError("Unknown object passed as crosstalk sources.",
815 type(crosstalkSources[0]))
816
817 for detName in crosstalk.interChip:
818 if detName not in sourceNames:
819 self.log.warning("Crosstalk lists %s, not found in sources: %s",
820 detName, sourceNames)
821 continue
822
823 interChipCoeffs = crosstalk.interChip[detName]
824
825 sourceExposure = crosstalkSources[sourceNames.index(detName)]
826 if isinstance(sourceExposure, lsst.daf.butler.DeferredDatasetHandle):
827
828 sourceExposure = sourceExposure.get()
830 raise RuntimeError("Unknown object passed as crosstalk sources.",
831 type(sourceExposure))
832
833 self.log.info("Correcting detector %s with ctSource %s",
834 exposure.getDetector().getName(),
835 sourceExposure.getDetector().getName())
836 crosstalk.subtractCrosstalk(exposure, sourceExposure=sourceExposure,
837 crosstalkCoeffs=interChipCoeffs,
838 minPixelToMask=self.config.minPixelToMask,
839 crosstalkStr=self.config.crosstalkMaskPlane,
840 isTrimmed=isTrimmed,
841 backgroundMethod=self.config.crosstalkBackgroundMethod)
842 else:
843 self.log.warning("Crosstalk contains interChip coefficients, but no sources found!")
844
845
A class to contain the data, WCS, and other information needed to describe an image of the sky.