604 for amp, overscanResults
in zip(ccd, overscans):
605 if ccdExposure.getBBox().contains(amp.getBBox()):
606 self.log.debug(
"Constructing variance map for amplifer %s.", amp.getName())
607 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
611 if self.config.qa
is not None and self.config.qa.saveStats
is True:
612 qaStats = afwMath.makeStatistics(ampExposure.getVariance(),
613 afwMath.MEDIAN | afwMath.STDEVCLIP)
614 self.log.debug(
" Variance stats for amplifer %s: %f +/- %f.",
615 amp.getName(), qaStats.getValue(afwMath.MEDIAN),
616 qaStats.getValue(afwMath.STDEVCLIP))
617 if self.config.maskNegativeVariance:
783 interpExp = ccdExposure.clone()
785 isrFunctions.interpolateFromMask(
786 maskedImage=interpExp.getMaskedImage(),
787 fwhm=self.config.brighterFatterFwhmForInterpolation,
788 growSaturatedFootprints=self.config.growSaturationFootprintSize,
789 maskNameList=list(self.config.brighterFatterMaskListToInterpolate)
791 bfExp = interpExp.clone()
792 self.log.info(
"Applying brighter-fatter correction using kernel type %s / gains %s.",
793 type(bfKernel), type(bfGains))
794 bfResults = isrFunctions.brighterFatterCorrection(bfExp, bfKernel,
795 self.config.brighterFatterMaxIter,
796 self.config.brighterFatterThreshold,
797 self.config.brighterFatterApplyGain,
799 if bfResults[1] == self.config.brighterFatterMaxIter:
800 self.log.warning(
"Brighter-fatter correction did not converge, final difference %f.",
803 self.log.info(
"Finished brighter-fatter correction in %d iterations.",
806 image = ccdExposure.getMaskedImage().getImage()
807 bfCorr = bfExp.getMaskedImage().getImage()
808 bfCorr -= interpExp.getMaskedImage().getImage()
817 self.log.info(
"Ensuring image edges are masked as EDGE to the brighter-fatter kernel size.")
818 self.
maskEdges(ccdExposure, numEdgePixels=numpy.max(bfKernel.shape) // 2,
821 if self.config.brighterFatterMaskGrowSize > 0:
822 self.log.info(
"Growing masks to account for brighter-fatter kernel convolution.")
823 for maskPlane
in self.config.brighterFatterMaskListToInterpolate:
824 isrFunctions.growMasks(ccdExposure.getMask(),
825 radius=self.config.brighterFatterMaskGrowSize,
826 maskNameList=maskPlane,
939 def run(self, *, ccdExposure, dnlLUT=None, bias=None, deferredChargeCalib=None, linearizer=None,
940 ptc=None, crosstalk=None, defects=None, bfKernel=None, bfGains=None, dark=None,
944 detector = ccdExposure.getDetector()
946 if self.config.doHeaderProvenance:
949 exposureMetadata = ccdExposure.getMetadata()
951 if self.config.doDiffNonLinearCorrection:
953 if self.config.doBias:
955 if self.config.doDeferredCharge:
956 exposureMetadata[
"LSST CALIB DATE CTI"] = self.
extractCalibDate(deferredChargeCalib)
958 exposureMetadata[
"LSST CALIB DATE LINEARIZER"] = self.
extractCalibDate(linearizer)
959 if self.config.doCrosstalk:
960 exposureMetadata[
"LSST CALIB DATE CROSSTALK"] = self.
extractCalibDate(crosstalk)
961 if self.config.doDefect:
962 exposureMetadata[
"LSST CALIB DATE DEFECTS"] = self.
extractCalibDate(defects)
963 if self.config.doBrighterFatter:
965 if self.config.doDark:
968 if self.config.doDiffNonLinearCorrection:
971 if self.config.doOverscan:
975 if self.config.doAssembleCcd:
977 self.log.info(
"Assembling CCD from amplifiers.")
978 ccdExposure = self.assembleCcd.assembleCcd(ccdExposure)
980 if self.config.expectWcs
and not ccdExposure.getWcs():
981 self.log.warning(
"No WCS found in input exposure.")
983 if self.config.doBias:
985 self.log.info(
"Applying bias correction.")
986 isrFunctions.biasCorrection(ccdExposure.getMaskedImage(), bias.getMaskedImage())
988 if self.config.doDeferredCharge:
990 self.log.info(
"Applying deferred charge/CTI correction.")
991 self.deferredChargeCorrection.
run(ccdExposure, deferredChargeCalib)
993 if self.config.doLinearize:
995 self.log.info(
"Applying linearizer.")
997 linearizer.applyLinearity(image=ccdExposure.getMaskedImage().getImage(),
998 detector=detector, log=self.log)
1000 if self.config.doGainNormalize:
1006 if self.config.doVariance:
1010 if self.config.doCrosstalk:
1012 self.log.info(
"Applying crosstalk correction.")
1013 self.crosstalk.
run(ccdExposure, crosstalk=crosstalk)
1017 if self.config.doDefect:
1019 self.log.info(
"Applying defects masking.")
1022 if self.config.doNanMasking:
1023 self.log.info(
"Masking non-finite (NAN, inf) value pixels.")
1026 if self.config.doWidenSaturationTrails:
1027 self.log.info(
"Widening saturation trails.")
1028 isrFunctions.widenSaturationTrails(ccdExposure.getMaskedImage().getMask())
1031 if self.config.doSaveInterpPixels:
1032 preInterpExp = ccdExposure.clone()
1034 if self.config.doSetBadRegions:
1035 self.log.info(
'Counting pixels in BAD regions.')
1038 if self.config.doInterpolate:
1039 self.log.info(
"Interpolating masked pixels.")
1040 isrFunctions.interpolateFromMask(
1041 maskedImage=ccdExposure.getMaskedImage(),
1042 fwhm=self.config.brighterFatterFwhmForInterpolation,
1043 growSaturatedFootprints=self.config.growSaturationFootprintSize,
1044 maskNameList=list(self.config.maskListToInterpolate)
1047 if self.config.doBrighterFatter:
1049 self.log.info(
"Applying Bright-Fatter kernels.")
1053 if self.config.doDark:
1055 self.log.info(
"Applying dark subtraction.")
1059 if self.config.doStandardStatistics:
1060 metadata = ccdExposure.getMetadata()
1061 for amp
in detector:
1062 ampExposure = ccdExposure.Factory(ccdExposure, amp.getBBox())
1063 ampName = amp.getName()
1064 metadata[f
"LSST ISR MASK SAT {ampName}"] = isrFunctions.countMaskedPixels(
1065 ampExposure.getMaskedImage(),
1066 [self.config.saturatedMaskName]
1068 metadata[f
"LSST ISR MASK BAD {ampName}"] = isrFunctions.countMaskedPixels(
1069 ampExposure.getMaskedImage(),
1072 qaStats = afwMath.makeStatistics(ampExposure.getImage(),
1073 afwMath.MEAN | afwMath.MEDIAN | afwMath.STDEVCLIP)
1075 metadata[f
"LSST ISR FINAL MEAN {ampName}"] = qaStats.getValue(afwMath.MEAN)
1076 metadata[f
"LSST ISR FINAL MEDIAN {ampName}"] = qaStats.getValue(afwMath.MEDIAN)
1077 metadata[f
"LSST ISR FINAL STDEV {ampName}"] = qaStats.getValue(afwMath.STDEVCLIP)
1079 k1 = f
"LSST ISR FINAL MEDIAN {ampName}"
1080 k2 = f
"LSST ISR OVERSCAN SERIAL MEDIAN {ampName}"
1081 if self.config.doOverscan
and k1
in metadata
and k2
in metadata:
1082 metadata[f
"LSST ISR LEVEL {ampName}"] = metadata[k1] - metadata[k2]
1084 metadata[f
"LSST ISR LEVEL {ampName}"] = numpy.nan
1087 outputStatistics =
None
1088 if self.config.doCalculateStatistics:
1089 outputStatistics = self.isrStats.
run(ccdExposure, overscanResults=overscans,
1093 outputBin1Exposure =
None
1094 outputBin2Exposure =
None
1095 if self.config.doBinnedExposures:
1096 outputBin1Exposure, outputBin2Exposure = self.
makeBinnedImages(ccdExposure)
1098 return pipeBase.Struct(
1099 exposure=ccdExposure,
1101 outputBin1Exposure=outputBin1Exposure,
1102 outputBin2Exposure=outputBin2Exposure,
1104 preInterpExposure=preInterpExp,
1105 outputExposure=ccdExposure,
1106 outputStatistics=outputStatistics,