Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of cp_pipe. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21# 

22import lsst.pex.config as pexConfig 

23import lsst.pipe.base as pipeBase 

24from lsst.cp.pipe.utils import arrangeFlatsByExpTime 

25 

26from lsst.pipe.tasks.getRepositoryData import DataRefListRunner 

27from lsst.cp.pipe.ptc.cpExtractPtcTask import PhotonTransferCurveExtractTask 

28from lsst.cp.pipe.ptc.cpSolvePtcTask import PhotonTransferCurveSolveTask 

29from lsst.utils.timer import timeMethod 

30 

31 

32__all__ = ['MeasurePhotonTransferCurveTask', 'MeasurePhotonTransferCurveTaskConfig'] 

33 

34 

35class MeasurePhotonTransferCurveTaskConfig(pexConfig.Config): 

36 extract = pexConfig.ConfigurableField( 

37 target=PhotonTransferCurveExtractTask, 

38 doc="Task to measure covariances from flats.", 

39 ) 

40 solve = pexConfig.ConfigurableField( 

41 target=PhotonTransferCurveSolveTask, 

42 doc="Task to fit models to the measured covariances.", 

43 ) 

44 ccdKey = pexConfig.Field( 

45 dtype=str, 

46 doc="The key by which to pull a detector from a dataId, e.g. 'ccd' or 'detector'.", 

47 default='ccd', 

48 ) 

49 

50 

51class MeasurePhotonTransferCurveTask(pipeBase.CmdLineTask): 

52 """A class to calculate, fit, and plot a PTC from a set of flat pairs. 

53 

54 The Photon Transfer Curve (var(signal) vs mean(signal)) is a standard 

55 tool used in astronomical detectors characterization (e.g., Janesick 2001, 

56 Janesick 2007). If ptcFitType is "EXPAPPROXIMATION" or "POLYNOMIAL", 

57 this task calculates the PTC from a series of pairs of flat-field images; 

58 each pair taken at identical exposure times. The difference image of each 

59 pair is formed to eliminate fixed pattern noise, and then the variance 

60 of the difference image and the mean of the average image 

61 are used to produce the PTC. An n-degree polynomial or the approximation 

62 in Equation 16 of Astier+19 ("The Shape of the Photon Transfer Curve 

63 of CCD sensors", arXiv:1905.08677) can be fitted to the PTC curve. These 

64 models include parameters such as the gain (e/DN) and readout noise. 

65 

66 Linearizers to correct for signal-chain non-linearity are also calculated. 

67 The `Linearizer` class, in general, can support per-amp linearizers, but 

68 in this task this is not supported. 

69 

70 If ptcFitType is "FULLCOVARIANCE", the covariances of the difference 

71 images are calculated via the DFT methods described in Astier+19 and the 

72 variances for the PTC are given by the cov[0,0] elements at each signal 

73 level. The full model in Equation 20 of Astier+19 is fit to the PTC 

74 to get the gain and the noise. 

75 

76 Parameters 

77 ---------- 

78 *args: `list` 

79 Positional arguments passed to the Task constructor. None used 

80 at this time. 

81 

82 **kwargs: `dict` 

83 Keyword arguments passed on to the Task constructor. None used 

84 at this time. 

85 """ 

86 

87 RunnerClass = DataRefListRunner 

88 ConfigClass = MeasurePhotonTransferCurveTaskConfig 

89 _DefaultName = "measurePhotonTransferCurve" 

90 

91 def __init__(self, *args, **kwargs): 

92 super().__init__(**kwargs) 

93 self.makeSubtask("extract") 

94 self.makeSubtask("solve") 

95 

96 @timeMethod 

97 def runDataRef(self, dataRefList): 

98 """Run the Photon Transfer Curve (PTC) measurement task. 

99 

100 For a dataRef (which is each detector here), and given a list 

101 of exposure pairs (postISR) at different exposure times, 

102 measure the PTC. 

103 

104 Parameters 

105 ---------- 

106 dataRefList : `list` [`lsst.daf.peristence.ButlerDataRef`] 

107 Data references for exposures. 

108 """ 

109 if len(dataRefList) < 2: 

110 raise RuntimeError("Insufficient inputs to combine.") 

111 

112 # setup necessary objects 

113 dataRef = dataRefList[0] 

114 camera = dataRef.get('camera') 

115 

116 if len(set([dataRef.dataId[self.config.ccdKey] for dataRef in dataRefList])) > 1: 

117 raise RuntimeError("Too many detectors supplied") 

118 # Get exposure list. 

119 expList = [] 

120 for dataRef in dataRefList: 

121 try: 

122 tempFlat = dataRef.get("postISRCCD") 

123 except RuntimeError: 

124 self.log.warn("postISR exposure could not be retrieved. Ignoring flat.") 

125 continue 

126 expList.append(tempFlat) 

127 expIds = [exp.getInfo().getVisitInfo().getExposureId() for exp in expList] 

128 

129 # Create dictionary of exposures, keyed by exposure time 

130 expDict = arrangeFlatsByExpTime(expList) 

131 # Call the "extract" (measure flat covariances) and "solve" 

132 # (fit covariances) subtasks 

133 resultsExtract = self.extract.run(inputExp=expDict, inputDims=expIds) 

134 resultsSolve = self.solve.run(resultsExtract.outputCovariances, camera=camera) 

135 

136 # Get expIdPairs from one of the amps 

137 expIdsPairsList = [] 

138 ampNames = resultsSolve.outputPtcDataset.ampNames 

139 for ampName in ampNames: 

140 tempAmpName = ampName 

141 if ampName not in resultsSolve.outputPtcDataset.badAmps: 

142 break 

143 for pair in resultsSolve.outputPtcDataset.inputExpIdPairs[tempAmpName]: 

144 first, second = pair[0] 

145 expIdsPairsList.append((first, second)) 

146 

147 self.log.info("Writing PTC data.") 

148 dataRef.put(resultsSolve.outputPtcDataset, datasetType="photonTransferCurveDataset") 

149 

150 return