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# 

2# LSST Data Management System 

3# Copyright 2008-2016 AURA/LSST. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

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

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

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

11# (at your option) any later version. 

12# 

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

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

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

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22import lsst.pex.config as pexConfig 

23import lsst.pipe.base as pipeBase 

24from lsstDebug import getDebugFrame 

25from lsst.afw.display import getDisplay 

26from lsst.ip.isr import IsrTask 

27from lsst.pipe.tasks.snapCombine import SnapCombineTask 

28import numpy 

29 

30__all__ = ["LsstSimIsrTask"] 

31 

32 

33class LsstSimIsrConfig(IsrTask.ConfigClass): 

34 doWriteSnaps = pexConfig.Field( 

35 dtype=bool, 

36 doc="Persist snapExp for each snap?", 

37 default=True, 

38 ) 

39 doSnapCombine = pexConfig.Field( 

40 dtype=bool, 

41 doc="Combine Snaps? If False then use snap 0 as output exposure.", 

42 default=True, 

43 ) 

44 snapCombine = pexConfig.ConfigurableField( 

45 target=SnapCombineTask, 

46 doc="Combine snaps task", 

47 ) 

48 

49 def setDefaults(self): 

50 IsrTask.ConfigClass.setDefaults(self) 

51 self.doDark = False # LSSTSims do not include darks at this time 

52 self.snapCombine.averageKeys = ("TAI", "MJD-OBS", "AIRMASS", "AZIMUTH", "ZENITH", 

53 "ROTANG", "SPIDANG", "ROTRATE") 

54 self.snapCombine.sumKeys = ("EXPTIME", "CREXPTM", "DARKTIME") 

55 

56 

57class LsstSimIsrTask(IsrTask): 

58 

59 r""" 

60 \section obs_lsstSim_isr_Debug Debug variables 

61 

62 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a 

63 flag \c --debug, \c -d to import \b debug.py from your \c PYTHONPATH; see <a 

64 href="http://lsst-web.ncsa.illinois.edu/~buildbot/doxygen/x_masterDoxyDoc/base_debug.html"> 

65 Using lsstDebug to control debugging output</a> for more about \b debug.py files. 

66 

67 The available variables in LsstSimIsrTask are: 

68 <DL> 

69 <DT> \c display 

70 <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are: 

71 <DL> 

72 <DT> snapExp0 

73 <DD> Display ISR-corrected snap 0 

74 <DT> snapExp1 

75 <DD> Display ISR-corrected snap 1 

76 <DT> postISRCCD 

77 <DD> Display final exposure 

78 </DL> 

79 </DL> 

80 """ 

81 ConfigClass = LsstSimIsrConfig 

82 

83 def __init__(self, **kwargs): 

84 IsrTask.__init__(self, **kwargs) 

85 self.makeSubtask("snapCombine") 

86 

87 def unmaskSatHotPixels(self, exposure): 

88 mi = exposure.getMaskedImage() 

89 mask = mi.getMask() 

90 maskarr = mask.getArray() 

91 badBitmask = numpy.array(mask.getPlaneBitMask("BAD"), dtype=maskarr.dtype) 

92 satBitmask = numpy.array(mask.getPlaneBitMask("SAT"), dtype=maskarr.dtype) 

93 orBitmask = badBitmask | satBitmask 

94 andMask = ~satBitmask 

95 idx = numpy.where((maskarr & orBitmask) == orBitmask) 

96 maskarr[idx] &= andMask 

97 

98 def saturationInterpolation(self, ccdExposure): 

99 r"""!Unmask hot pixels and interpolate over saturated pixels, in place 

100 

101 \param[in,out] ccdExposure exposure to process 

102 

103 \warning: 

104 - Call saturationDetection first, so that saturated pixels have been identified in the "SAT" mask. 

105 - Call this after CCD assembly, since saturated regions may cross amplifier boundaries 

106 """ 

107 self.unmaskSatHotPixels(ccdExposure) 

108 super(LsstSimIsrTask, self).saturationInterpolation(ccdExposure) 

109 

110 @pipeBase.timeMethod 

111 def runDataRef(self, sensorRef): 

112 """Do instrument signature removal on an exposure 

113 

114 Correct for saturation, bias, overscan, dark, flat..., perform CCD assembly, 

115 optionally combine snaps, and interpolate over defects and saturated pixels. 

116 

117 If config.doSnapCombine true then combine the two ISR-corrected snaps to produce the final exposure. 

118 If config.doSnapCombine false then uses ISR-corrected snap 0 as the final exposure. 

119 In either case, the final exposure is persisted as "postISRCCD" if config.doWriteSpans is True, 

120 and the two snaps are persisted as "snapExp" if config.doWriteSnaps is True. 

121 

122 @param sensorRef daf.persistence.butlerSubset.ButlerDataRef of the data to be processed 

123 @return a pipeBase.Struct with fields: 

124 - exposure: the exposure after application of ISR 

125 """ 

126 self.log.info("Performing ISR on sensor %s", sensorRef.dataId) 

127 camera = sensorRef.get("camera") 

128 snapDict = dict() 

129 for snapRef in sensorRef.subItems(level="snap"): 

130 snapId = snapRef.dataId['snap'] 

131 if snapId not in (0, 1): 

132 raise RuntimeError("Unrecognized snapId=%s" % (snapId,)) 

133 

134 self.log.info("Performing ISR on snap %s", snapRef.dataId) 

135 ccdExposure = snapRef.get('raw') 

136 isrData = self.readIsrData(snapRef, ccdExposure) 

137 ccdExposure = self.run(ccdExposure, camera=camera, **isrData.getDict()).exposure 

138 snapDict[snapId] = ccdExposure 

139 

140 if self.config.doWriteSnaps: 

141 sensorRef.put(ccdExposure, "snapExp", snap=snapId) 

142 

143 frame = getDebugFrame(self._display, "snapExp%d" % (snapId,)) 

144 if frame: 

145 getDisplay(frame).mtv(ccdExposure) 

146 

147 if self.config.doSnapCombine: 

148 loadSnapDict(snapDict, snapIdList=(0, 1), sensorRef=sensorRef) 

149 postIsrExposure = self.snapCombine.run(snapDict[0], snapDict[1]).exposure 

150 else: 

151 self.log.warn("doSnapCombine false; using snap 0 as the result") 

152 loadSnapDict(snapDict, snapIdList=(0,), sensorRef=sensorRef) 

153 postIsrExposure = snapDict[0] 

154 

155 if self.config.doWrite: 

156 sensorRef.put(postIsrExposure, "postISRCCD") 

157 

158 frame = getDebugFrame(self._display, "postISRCCD") 

159 if frame: 

160 getDisplay(frame).mtv(postIsrExposure) 

161 

162 return pipeBase.Struct( 

163 exposure=postIsrExposure, 

164 ) 

165 

166 

167def loadSnapDict(snapDict, snapIdList, sensorRef): 

168 """Load missing snaps from disk. 

169 

170 @paramp[in,out] snapDict: a dictionary of snapId: snap exposure ("snapExp") 

171 @param[in] snapIdList: a list of snap IDs 

172 @param[in] sensorRef: sensor reference for snap, excluding the snap ID. 

173 """ 

174 for snapId in snapIdList: 

175 if snapId not in snapDict: 

176 snapExposure = sensorRef.get("snapExp", snap=snapId) 

177 if snapExposure is None: 

178 raise RuntimeError("Could not find snapExp for snap=%s; id=%s" % (snapId, sensorRef.dataId)) 

179 snapDict[snapId] = snapExposure