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-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.geom as geom 

24import lsst.afw.geom as afwGeom 

25import lsst.afw.image as afwImage 

26import lsst.pipe.base as pipeBase 

27import lsst.meas.algorithms as measAlg 

28 

29from lsst.afw.fits import FitsError 

30from lsst.coadd.utils import CoaddDataIdContainer 

31from .selectImages import WcsSelectImagesTask, SelectStruct 

32from .coaddInputRecorder import CoaddInputRecorderTask 

33from .scaleVariance import ScaleVarianceTask 

34 

35__all__ = ["CoaddBaseTask", "getSkyInfo", "makeSkyInfo", "makeCoaddSuffix"] 

36 

37 

38class CoaddBaseConfig(pexConfig.Config): 

39 """!Configuration parameters for CoaddBaseTask 

40 

41 @anchor CoaddBaseConfig_ 

42 

43 @brief Configuration parameters shared between MakeCoaddTempExp and AssembleCoadd 

44 """ 

45 coaddName = pexConfig.Field( 

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

47 dtype=str, 

48 default="deep", 

49 ) 

50 select = pexConfig.ConfigurableField( 

51 doc="Image selection subtask.", 

52 target=WcsSelectImagesTask, 

53 ) 

54 badMaskPlanes = pexConfig.ListField( 

55 dtype=str, 

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

57 default=("NO_DATA",), 

58 ) 

59 inputRecorder = pexConfig.ConfigurableField( 

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

61 target=CoaddInputRecorderTask 

62 ) 

63 doPsfMatch = pexConfig.Field( 

64 dtype=bool, 

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

66 default=False 

67 ) 

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

69 doApplyUberCal = pexConfig.Field( 

70 dtype=bool, 

71 doc=("Apply ubercalibrated WCS and PhotoCalib results to input calexps? " 

72 "This field is no longer used, and has been deprecated by DM-21308. " 

73 "It will be removed after v20. Use doApplyExternalPhotoCalib and " 

74 "doApplyExternalSkyWcs instead."), 

75 default=False 

76 ) 

77 doApplyExternalPhotoCalib = pexConfig.Field( 

78 dtype=bool, 

79 default=False, 

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

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

82 "`externalPhotoCalibName` field to determine which calibration " 

83 "to load.") 

84 ) 

85 externalPhotoCalibName = pexConfig.ChoiceField( 

86 dtype=str, 

87 doc="Type of external PhotoCalib if `doApplyExternalPhotoCalib` is True.", 

88 default="jointcal", 

89 allowed={ 

90 "jointcal": "Use jointcal_photoCalib", 

91 "fgcm": "Use fgcm_photoCalib", 

92 "fgcm_tract": "Use fgcm_tract_photoCalib" 

93 } 

94 ) 

95 doApplyExternalSkyWcs = pexConfig.Field( 

96 dtype=bool, 

97 default=False, 

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

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

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

101 ) 

102 externalSkyWcsName = pexConfig.ChoiceField( 

103 dtype=str, 

104 doc="Type of external SkyWcs if `doApplyExternalSkyWcs` is True.", 

105 default="jointcal", 

106 allowed={ 

107 "jointcal": "Use jointcal_wcs" 

108 } 

109 ) 

110 includeCalibVar = pexConfig.Field( 

111 dtype=bool, 

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

113 default=False 

114 ) 

115 matchingKernelSize = pexConfig.Field( 

116 dtype=int, 

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

118 default=21, 

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

120 ) 

121 

122 

123class CoaddTaskRunner(pipeBase.TaskRunner): 

124 

125 @staticmethod 

126 def getTargetList(parsedCmd, **kwargs): 

127 return pipeBase.TaskRunner.getTargetList(parsedCmd, selectDataList=parsedCmd.selectId.dataList, 

128 **kwargs) 

129 

130 

131class CoaddBaseTask(pipeBase.CmdLineTask, pipeBase.PipelineTask): 

132 """!Base class for coaddition. 

133 

134 Subclasses must specify _DefaultName 

135 """ 

136 ConfigClass = CoaddBaseConfig 

137 RunnerClass = CoaddTaskRunner 

138 

139 def __init__(self, **kwargs): 

140 super().__init__(**kwargs) 

141 self.makeSubtask("select") 

142 self.makeSubtask("inputRecorder") 

143 

144 def selectExposures(self, patchRef, skyInfo=None, selectDataList=[]): 

145 """! 

146 @brief Select exposures to coadd 

147 

148 Get the corners of the bbox supplied in skyInfo using @ref geom.Box2D and convert the pixel 

149 positions of the bbox corners to sky coordinates using @ref skyInfo.wcs.pixelToSky. Use the 

150 @ref WcsSelectImagesTask_ "WcsSelectImagesTask" to select exposures that lie inside the patch 

151 indicated by the dataRef. 

152 

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

154 plus the camera-specific filter key (e.g. "filter" or "band") 

155 @param[in] skyInfo geometry for the patch; output from getSkyInfo 

156 @return a list of science exposures to coadd, as butler data references 

157 """ 

158 if skyInfo is None: 158 ↛ 159line 158 didn't jump to line 159, because the condition on line 158 was never true

159 skyInfo = self.getSkyInfo(patchRef) 

160 cornerPosList = geom.Box2D(skyInfo.bbox).getCorners() 

161 coordList = [skyInfo.wcs.pixelToSky(pos) for pos in cornerPosList] 

162 return self.select.runDataRef(patchRef, coordList, selectDataList=selectDataList).dataRefList 

163 

164 def getSkyInfo(self, patchRef): 

165 """! 

166 @brief Use @ref getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox 

167 of the patch. 

168 

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

170 

171 @return pipe_base Struct containing: 

172 - skyMap: sky map 

173 - tractInfo: information for chosen tract of sky map 

174 - patchInfo: information about chosen patch of tract 

175 - wcs: WCS of tract 

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

177 """ 

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

179 

180 def getCoaddDatasetName(self, warpType="direct"): 

181 """Return coadd name for given warpType and task config 

182 

183 Parameters 

184 ---------- 

185 warpType : string 

186 Either 'direct' or 'psfMatched' 

187 

188 Returns 

189 ------- 

190 CoaddDatasetName : `string` 

191 """ 

192 return self.config.coaddName + "Coadd" + makeCoaddSuffix(warpType) 

193 

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

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

196 

197 Parameters 

198 ---------- 

199 warpType : string 

200 Either 'direct' or 'psfMatched' 

201 

202 Returns 

203 ------- 

204 WarpDatasetName : `string` 

205 """ 

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

207 

208 @classmethod 

209 def _makeArgumentParser(cls): 

210 """Create an argument parser 

211 """ 

212 parser = pipeBase.ArgumentParser(name=cls._DefaultName) 

213 parser.add_id_argument("--id", "deepCoadd", help="data ID, e.g. --id tract=12345 patch=1,2", 

214 ContainerClass=CoaddDataIdContainer) 

215 parser.add_id_argument("--selectId", "calexp", help="data ID, e.g. --selectId visit=6789 ccd=0..9", 

216 ContainerClass=SelectDataIdContainer) 

217 return parser 

218 

219 def _getConfigName(self): 

220 """Return the name of the config dataset 

221 """ 

222 return "%s_%s_config" % (self.config.coaddName, self._DefaultName) 

223 

224 def _getMetadataName(self): 

225 """Return the name of the metadata dataset 

226 """ 

227 return "%s_%s_metadata" % (self.config.coaddName, self._DefaultName) 

228 

229 def getBadPixelMask(self): 

230 """! 

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

232 """ 

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

234 

235 

236class SelectDataIdContainer(pipeBase.DataIdContainer): 

237 """! 

238 @brief A dataId container for inputs to be selected. 

239 

240 Read the header (including the size and Wcs) for all specified 

241 inputs and pass those along, ultimately for the SelectImagesTask. 

242 This is most useful when used with multiprocessing, as input headers are 

243 only read once. 

244 """ 

245 

246 def makeDataRefList(self, namespace): 

247 """Add a dataList containing useful information for selecting images""" 

248 super(SelectDataIdContainer, self).makeDataRefList(namespace) 

249 self.dataList = [] 

250 for ref in self.refList: 

251 try: 

252 md = ref.get("calexp_md", immediate=True) 

253 wcs = afwGeom.makeSkyWcs(md) 

254 data = SelectStruct(dataRef=ref, wcs=wcs, bbox=afwImage.bboxFromMetadata(md)) 

255 except FitsError: 

256 namespace.log.warn("Unable to construct Wcs from %s" % (ref.dataId)) 

257 continue 

258 self.dataList.append(data) 

259 

260 

261def getSkyInfo(coaddName, patchRef): 

262 """! 

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

264 

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

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

267 

268 @return pipe_base Struct containing: 

269 - skyMap: sky map 

270 - tractInfo: information for chosen tract of sky map 

271 - patchInfo: information about chosen patch of tract 

272 - wcs: WCS of tract 

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

274 """ 

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

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

277 

278 

279def makeSkyInfo(skyMap, tractId, patchId): 

280 """Return SkyInfo Struct 

281 

282 Constructs SkyInfo used by coaddition tasks for multiple 

283 patchId formats. 

284 

285 Parameters 

286 ---------- 

287 skyMap : `lsst.skyMap.SkyMap` 

288 tractId : int 

289 patchId : str or int or tuple of int 

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

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

292 """ 

293 tractInfo = skyMap[tractId] 

294 

295 if isinstance(patchId, str) and ',' in patchId: 295 ↛ 299line 295 didn't jump to line 299, because the condition on line 295 was never false

296 # patch format is "xIndex,yIndex" 

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

298 else: 

299 patchIndex = patchId 

300 

301 patchInfo = tractInfo.getPatchInfo(patchIndex) 

302 

303 return pipeBase.Struct( 

304 skyMap=skyMap, 

305 tractInfo=tractInfo, 

306 patchInfo=patchInfo, 

307 wcs=tractInfo.getWcs(), 

308 bbox=patchInfo.getOuterBBox(), 

309 ) 

310 

311 

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

313 """! 

314 @brief Scale the variance in a maskedImage 

315 

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

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

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

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

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

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

322 

323 @deprecated Use the ScaleVarianceTask instead. 

324 

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

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

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

328 @return renormalisation factor 

329 """ 

330 config = ScaleVarianceTask.ConfigClass() 

331 config.maskPlanes = maskPlanes 

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

333 return task.run(maskedImage) 

334 

335 

336def makeCoaddSuffix(warpType="direct"): 

337 """Return coadd suffix for warpType 

338 

339 Parameters 

340 ---------- 

341 warpType : string 

342 Either 'direct' or 'psfMatched' 

343 

344 Returns 

345 ------- 

346 CoaddSuffix : `string` 

347 """ 

348 suffix = "" if warpType == "direct" else warpType[0].upper() + warpType[1:] 

349 return suffix