Coverage for python/lsst/pipe/tasks/coaddBase.py: 54%

57 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-18 20:10 +0000

1# 

2# LSST Data Management System 

3# Copyright 2008-2015 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.afw.image as afwImage 

24import lsst.pipe.base as pipeBase 

25import lsst.meas.algorithms as measAlg 

26 

27from lsst.meas.algorithms import ScaleVarianceTask 

28from .selectImages import PsfWcsSelectImagesTask 

29from .coaddInputRecorder import CoaddInputRecorderTask 

30 

31__all__ = ["CoaddBaseTask", "getSkyInfo", "makeSkyInfo"] 

32 

33 

34class CoaddBaseConfig(pexConfig.Config): 

35 """!Configuration parameters for CoaddBaseTask 

36 

37 @anchor CoaddBaseConfig_ 

38 

39 @brief Configuration parameters shared between MakeCoaddTempExp and AssembleCoadd 

40 """ 

41 coaddName = pexConfig.Field( 

42 doc="Coadd name: typically one of deep or goodSeeing.", 

43 dtype=str, 

44 default="deep", 

45 ) 

46 select = pexConfig.ConfigurableField( 

47 doc="Image selection subtask.", 

48 target=PsfWcsSelectImagesTask, 

49 ) 

50 badMaskPlanes = pexConfig.ListField( 

51 dtype=str, 

52 doc="Mask planes that, if set, the associated pixel should not be included in the coaddTempExp.", 

53 default=("NO_DATA",), 

54 ) 

55 inputRecorder = pexConfig.ConfigurableField( 

56 doc="Subtask that helps fill CoaddInputs catalogs added to the final Exposure", 

57 target=CoaddInputRecorderTask 

58 ) 

59 doPsfMatch = pexConfig.Field( 

60 dtype=bool, 

61 doc="Match to modelPsf? Deprecated. Sets makePsfMatched=True, makeDirect=False", 

62 default=False 

63 ) 

64 modelPsf = measAlg.GaussianPsfFactory.makeField(doc="Model Psf factory") 

65 doApplyExternalPhotoCalib = pexConfig.Field( 

66 dtype=bool, 

67 default=False, 

68 doc=("Whether to apply external photometric calibration via an " 

69 "`lsst.afw.image.PhotoCalib` object. Uses the " 

70 "`externalPhotoCalibName` field to determine which calibration " 

71 "to load.") 

72 ) 

73 useGlobalExternalPhotoCalib = pexConfig.Field( 

74 dtype=bool, 

75 default=True, 

76 doc=("When using doApplyExternalPhotoCalib, use 'global' calibrations " 

77 "that are not run per-tract. When False, use per-tract photometric " 

78 "calibration files.") 

79 ) 

80 externalPhotoCalibName = pexConfig.ChoiceField( 

81 # TODO: Remove this config with the removal of Gen2 in DM-20572. 

82 dtype=str, 

83 doc=("Type of external PhotoCalib if `doApplyExternalPhotoCalib` is True. " 

84 "This field is only used for Gen2 middleware."), 

85 default="jointcal", 

86 allowed={ 

87 "jointcal": "Use jointcal_photoCalib", 

88 "fgcm": "Use fgcm_photoCalib", 

89 "fgcm_tract": "Use fgcm_tract_photoCalib" 

90 }, 

91 deprecated="This configuration is no longer used, and will be removed after v25.0", 

92 ) 

93 doApplyExternalSkyWcs = pexConfig.Field( 

94 dtype=bool, 

95 default=False, 

96 doc=("Whether to apply external astrometric calibration via an " 

97 "`lsst.afw.geom.SkyWcs` object. Uses `externalSkyWcsName` " 

98 "field to determine which calibration to load.") 

99 ) 

100 useGlobalExternalSkyWcs = pexConfig.Field( 

101 dtype=bool, 

102 default=False, 

103 doc=("When using doApplyExternalSkyWcs, use 'global' calibrations " 

104 "that are not run per-tract. When False, use per-tract wcs " 

105 "files.") 

106 ) 

107 externalSkyWcsName = pexConfig.ChoiceField( 

108 # TODO: Remove this config with the removal of Gen2 in DM-20572. 

109 dtype=str, 

110 doc=("Type of external SkyWcs if `doApplyExternalSkyWcs` is True. " 

111 "This field is only used for Gen2 middleware."), 

112 default="jointcal", 

113 allowed={ 

114 "jointcal": "Use jointcal_wcs" 

115 }, 

116 deprecated="This configuration is no longer used, and will be removed after v25.0", 

117 ) 

118 includeCalibVar = pexConfig.Field( 

119 dtype=bool, 

120 doc="Add photometric calibration variance to warp variance plane.", 

121 default=False 

122 ) 

123 matchingKernelSize = pexConfig.Field( 123 ↛ exitline 123 didn't jump to the function exit

124 dtype=int, 

125 doc="Size in pixels of matching kernel. Must be odd.", 

126 default=21, 

127 check=lambda x: x % 2 == 1 

128 ) 

129 

130 

131class CoaddBaseTask(pipeBase.PipelineTask): 

132 """!Base class for coaddition. 

133 

134 Subclasses must specify _DefaultName 

135 """ 

136 ConfigClass = CoaddBaseConfig 

137 

138 def __init__(self, **kwargs): 

139 super().__init__(**kwargs) 

140 self.makeSubtask("select") 

141 self.makeSubtask("inputRecorder") 

142 

143 def getSkyInfo(self, patchRef): 

144 """! 

145 @brief Use @ref coaddBase::getSkyInfo "getSkyInfo" to return the skyMap, 

146 tract and patch information, wcs and the outer bbox 

147 of the patch. 

148 

149 @param[in] patchRef data reference for sky map. Must include keys "tract" and "patch" 

150 

151 @return pipe_base Struct containing: 

152 - skyMap: sky map 

153 - tractInfo: information for chosen tract of sky map 

154 - patchInfo: information about chosen patch of tract 

155 - wcs: WCS of tract 

156 - bbox: outer bbox of patch, as an geom Box2I 

157 """ 

158 return getSkyInfo(coaddName=self.config.coaddName, patchRef=patchRef) 

159 

160 def getTempExpDatasetName(self, warpType="direct"): 

161 """Return warp name for given warpType and task config 

162 

163 Parameters 

164 ---------- 

165 warpType : string 

166 Either 'direct' or 'psfMatched' 

167 

168 Returns 

169 ------- 

170 WarpDatasetName : `string` 

171 """ 

172 return self.config.coaddName + "Coadd_" + warpType + "Warp" 

173 

174 def getBadPixelMask(self): 

175 """! 

176 @brief Convenience method to provide the bitmask from the mask plane names 

177 """ 

178 return afwImage.Mask.getPlaneBitMask(self.config.badMaskPlanes) 

179 

180 

181def getSkyInfo(coaddName, patchRef): 

182 """! 

183 @brief Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded. 

184 

185 @param[in] coaddName coadd name; typically one of deep or goodSeeing 

186 @param[in] patchRef data reference for sky map. Must include keys "tract" and "patch" 

187 

188 @return pipe_base Struct containing: 

189 - skyMap: sky map 

190 - tractInfo: information for chosen tract of sky map 

191 - patchInfo: information about chosen patch of tract 

192 - wcs: WCS of tract 

193 - bbox: outer bbox of patch, as an geom Box2I 

194 """ 

195 skyMap = patchRef.get(coaddName + "Coadd_skyMap") 

196 return makeSkyInfo(skyMap, patchRef.dataId["tract"], patchRef.dataId["patch"]) 

197 

198 

199def makeSkyInfo(skyMap, tractId, patchId): 

200 """Return SkyInfo Struct 

201 

202 Constructs SkyInfo used by coaddition tasks for multiple 

203 patchId formats. 

204 

205 Parameters 

206 ---------- 

207 skyMap : `lsst.skyMap.SkyMap` 

208 tractId : int 

209 patchId : str or int or tuple of int 

210 Either Gen2-style comma delimited string (e.g. '4,5'), 

211 tuple of integers (e.g (4, 5), Gen3-style integer. 

212 """ 

213 tractInfo = skyMap[tractId] 

214 

215 if isinstance(patchId, str) and ',' in patchId: 

216 # patch format is "xIndex,yIndex" 

217 patchIndex = tuple(int(i) for i in patchId.split(",")) 

218 else: 

219 patchIndex = patchId 

220 

221 patchInfo = tractInfo.getPatchInfo(patchIndex) 

222 

223 return pipeBase.Struct( 

224 skyMap=skyMap, 

225 tractInfo=tractInfo, 

226 patchInfo=patchInfo, 

227 wcs=tractInfo.getWcs(), 

228 bbox=patchInfo.getOuterBBox(), 

229 ) 

230 

231 

232def scaleVariance(maskedImage, maskPlanes, log=None): 

233 """! 

234 @brief Scale the variance in a maskedImage 

235 

236 The variance plane in a convolved or warped image (or a coadd derived 

237 from warped images) does not accurately reflect the noise properties of 

238 the image because variance has been lost to covariance. This function 

239 attempts to correct for this by scaling the variance plane to match 

240 the observed variance in the image. This is not perfect (because we're 

241 not tracking the covariance) but it's simple and is often good enough. 

242 

243 @deprecated Use the ScaleVarianceTask instead. 

244 

245 @param maskedImage MaskedImage to operate on; variance will be scaled 

246 @param maskPlanes List of mask planes for pixels to reject 

247 @param log Log for reporting the renormalization factor; or None 

248 @return renormalisation factor 

249 """ 

250 config = ScaleVarianceTask.ConfigClass() 

251 config.maskPlanes = maskPlanes 

252 task = ScaleVarianceTask(config=config, name="scaleVariance", log=log) 

253 return task.run(maskedImage) 

254 

255 

256def reorderAndPadList(inputList, inputKeys, outputKeys, padWith=None): 

257 """Match the order of one list to another, padding if necessary 

258 

259 Parameters 

260 ---------- 

261 inputList : list 

262 List to be reordered and padded. Elements can be any type. 

263 inputKeys : iterable 

264 Iterable of values to be compared with outputKeys. 

265 Length must match `inputList` 

266 outputKeys : iterable 

267 Iterable of values to be compared with inputKeys. 

268 padWith : 

269 Any value to be inserted where inputKey not in outputKeys 

270 

271 Returns 

272 ------- 

273 list 

274 Copy of inputList reordered per outputKeys and padded with `padWith` 

275 so that the length matches length of outputKeys. 

276 """ 

277 outputList = [] 

278 for d in outputKeys: 

279 if d in inputKeys: 

280 outputList.append(inputList[inputKeys.index(d)]) 

281 else: 

282 outputList.append(padWith) 

283 return outputList