Coverage for tests/test_testPipeline.py: 18%

196 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-18 12:21 +0000

1# 

2# This file is part of ap_verify. 

3# 

4# Developed for the LSST Data Management System. 

5# This product includes software developed by the LSST Project 

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

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

8# for details of code ownership. 

9# 

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

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

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

13# (at your option) any later version. 

14# 

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

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

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

18# GNU General Public License for more details. 

19# 

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

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

22# 

23 

24import shutil 

25import tempfile 

26import unittest 

27 

28import pandas 

29 

30import lsst.utils.tests 

31import lsst.geom 

32import lsst.afw.image as afwImage 

33import lsst.afw.math as afwMath 

34import lsst.afw.table as afwTable 

35import lsst.skymap 

36import lsst.daf.butler.tests as butlerTests 

37import lsst.pipe.base.testUtils as pipelineTests 

38from lsst.ap.verify.testPipeline import MockIsrTask, MockCharacterizeImageTask, \ 

39 MockCalibrateTask, MockGetTemplateTask, \ 

40 MockAlardLuptonSubtractTask, MockDetectAndMeasureTask, MockTransformDiaSourceCatalogTask, \ 

41 MockRBTransiNetTask, MockDiaPipelineTask, MockFilterDiaSourceCatalogTask, \ 

42 MockSpatiallySampledMetricsTask 

43 

44 

45class MockTaskTestSuite(unittest.TestCase): 

46 """Test that mock tasks have the correct inputs and outputs for the task 

47 they are replacing. 

48 

49 These tests assume that the mock tasks use real config and connection 

50 classes, and therefore out-of-date mocks won't match their connections. 

51 """ 

52 

53 @classmethod 

54 def setUpClass(cls): 

55 super().setUpClass() 

56 

57 repoDir = tempfile.mkdtemp() 

58 cls.addClassCleanup(shutil.rmtree, repoDir, ignore_errors=True) 

59 cls.repo = butlerTests.makeTestRepo(repoDir) 

60 

61 INSTRUMENT = "DummyCam" 

62 VISIT = 42 

63 CCD = 101 

64 HTM = 42 

65 SKYMAP = "TreasureMap" 

66 TRACT = 28 

67 PATCH = 4 

68 BAND = 'k' 

69 PHYSICAL = 'k2022' 

70 SUB_FILTER = 9 

71 # Mock instrument by hand, because some tasks care about parameters 

72 instrumentRecord = cls.repo.dimensions["instrument"].RecordClass( 

73 name=INSTRUMENT, visit_max=256, exposure_max=256, detector_max=128, 

74 class_name="lsst.obs.base.instrument_tests.DummyCam", 

75 ) 

76 cls.repo.registry.syncDimensionData("instrument", instrumentRecord) 

77 butlerTests.addDataIdValue(cls.repo, "physical_filter", PHYSICAL, band=BAND) 

78 butlerTests.addDataIdValue(cls.repo, "subfilter", SUB_FILTER) 

79 butlerTests.addDataIdValue(cls.repo, "exposure", VISIT) 

80 butlerTests.addDataIdValue(cls.repo, "visit", VISIT) 

81 butlerTests.addDataIdValue(cls.repo, "detector", CCD) 

82 butlerTests.addDataIdValue(cls.repo, "skymap", SKYMAP) 

83 butlerTests.addDataIdValue(cls.repo, "tract", TRACT) 

84 butlerTests.addDataIdValue(cls.repo, "patch", PATCH) 

85 

86 cls.emptyId = cls.repo.registry.expandDataId({}) 

87 cls.exposureId = cls.repo.registry.expandDataId( 

88 {"instrument": INSTRUMENT, "exposure": VISIT, "detector": CCD}) 

89 cls.visitId = cls.repo.registry.expandDataId( 

90 {"instrument": INSTRUMENT, "visit": VISIT, "detector": CCD}) 

91 cls.visitOnlyId = cls.repo.registry.expandDataId( 

92 {"instrument": INSTRUMENT, "visit": VISIT}) 

93 cls.skymapId = cls.repo.registry.expandDataId({"skymap": SKYMAP}) 

94 cls.skymapVisitId = cls.repo.registry.expandDataId( 

95 {"instrument": INSTRUMENT, "visit": VISIT, "detector": CCD, "skymap": SKYMAP}) 

96 cls.patchId = cls.repo.registry.expandDataId( 

97 {"skymap": SKYMAP, "tract": TRACT, "patch": PATCH, "band": BAND}) 

98 cls.subfilterId = cls.repo.registry.expandDataId( 

99 {"skymap": SKYMAP, "tract": TRACT, "patch": PATCH, "band": BAND, "subfilter": SUB_FILTER}) 

100 cls.htmId = cls.repo.registry.expandDataId({"htm7": HTM}) 

101 

102 butlerTests.addDatasetType(cls.repo, "postISRCCD", cls.exposureId.dimensions, "Exposure") 

103 butlerTests.addDatasetType(cls.repo, "icExp", cls.visitId.dimensions, "ExposureF") 

104 butlerTests.addDatasetType(cls.repo, "icSrc", cls.visitId.dimensions, "SourceCatalog") 

105 butlerTests.addDatasetType(cls.repo, "icExpBackground", cls.visitId.dimensions, "Background") 

106 butlerTests.addDatasetType(cls.repo, "gaia_dr3_20230707", cls.htmId.dimensions, "SimpleCatalog") 

107 butlerTests.addDatasetType(cls.repo, "ps1_pv3_3pi_20170110", cls.htmId.dimensions, "SimpleCatalog") 

108 butlerTests.addDatasetType(cls.repo, "calexp", cls.visitId.dimensions, "ExposureF") 

109 butlerTests.addDatasetType(cls.repo, "src", cls.visitId.dimensions, "SourceCatalog") 

110 butlerTests.addDatasetType(cls.repo, "calexpBackground", cls.visitId.dimensions, "Background") 

111 butlerTests.addDatasetType(cls.repo, "srcMatch", cls.visitId.dimensions, "Catalog") 

112 butlerTests.addDatasetType(cls.repo, "srcMatchFull", cls.visitId.dimensions, "Catalog") 

113 butlerTests.addDatasetType(cls.repo, lsst.skymap.BaseSkyMap.SKYMAP_DATASET_TYPE_NAME, 

114 cls.skymapId.dimensions, "SkyMap") 

115 butlerTests.addDatasetType(cls.repo, "goodSeeingCoadd", cls.patchId.dimensions, "ExposureF") 

116 butlerTests.addDatasetType(cls.repo, "deepDiff_differenceExp", cls.visitId.dimensions, "ExposureF") 

117 butlerTests.addDatasetType(cls.repo, "deepDiff_differenceTempExp", cls.visitId.dimensions, 

118 "ExposureF") 

119 butlerTests.addDatasetType(cls.repo, "deepDiff_templateExp", cls.visitId.dimensions, "ExposureF") 

120 butlerTests.addDatasetType(cls.repo, "goodSeeingDiff_templateExp", cls.visitId.dimensions, 

121 "ExposureF") 

122 butlerTests.addDatasetType(cls.repo, "deepDiff_psfMatchKernel", cls.visitId.dimensions, 

123 "MatchingKernel") 

124 butlerTests.addDatasetType(cls.repo, "deepDiff_matchedExp", cls.visitId.dimensions, "ExposureF") 

125 butlerTests.addDatasetType(cls.repo, "deepDiff_diaSrc", cls.visitId.dimensions, "SourceCatalog") 

126 butlerTests.addDatasetType(cls.repo, "deepDiff_diaSrcTable", cls.visitId.dimensions, "DataFrame") 

127 butlerTests.addDatasetType(cls.repo, "deepDiff_spatiallySampledMetrics", cls.visitId.dimensions, 

128 "ArrowAstropy") 

129 butlerTests.addDatasetType(cls.repo, "deepDiff_candidateDiaSrc", cls.visitId.dimensions, 

130 "SourceCatalog") 

131 butlerTests.addDatasetType(cls.repo, "visitSsObjects", cls.visitOnlyId.dimensions, "DataFrame") 

132 butlerTests.addDatasetType(cls.repo, "apdb_marker", cls.visitId.dimensions, "Config") 

133 butlerTests.addDatasetType(cls.repo, "deepDiff_assocDiaSrc", cls.visitId.dimensions, "DataFrame") 

134 butlerTests.addDatasetType(cls.repo, "deepDiff_longTrailedSrc", cls.visitId.dimensions, 

135 "ArrowAstropy") 

136 butlerTests.addDatasetType(cls.repo, "deepRealBogusSources", cls.visitId.dimensions, "Catalog") 

137 butlerTests.addDatasetType(cls.repo, "deepDiff_diaForcedSrc", cls.visitId.dimensions, "DataFrame") 

138 butlerTests.addDatasetType(cls.repo, "deepDiff_diaObject", cls.visitId.dimensions, "DataFrame") 

139 

140 def setUp(self): 

141 super().setUp() 

142 self.butler = butlerTests.makeTestCollection(self.repo, uniqueId=self.id()) 

143 

144 def testMockIsr(self): 

145 # Testing MockIsrTask is tricky because the real ISR has an unstable 

146 # interface with dozens of potential inputs, too many to pass through 

147 # runTestQuantum. I don't see a good way to test the inputs; 

148 # fortunately, this is unlikely to matter for the overall goal of 

149 # testing ap_verify's interaction with the AP pipeline. 

150 task = MockIsrTask() 

151 pipelineTests.assertValidInitOutput(task) 

152 result = task.run(afwImage.ExposureF()) 

153 pipelineTests.assertValidOutput(task, result) 

154 # Skip runTestQuantum 

155 

156 def testMockCharacterizeImageTask(self): 

157 task = MockCharacterizeImageTask() 

158 pipelineTests.assertValidInitOutput(task) 

159 result = task.run(afwImage.ExposureF()) 

160 pipelineTests.assertValidOutput(task, result) 

161 

162 self.butler.put(afwImage.ExposureF(), "postISRCCD", self.exposureId) 

163 quantum = pipelineTests.makeQuantum( 

164 task, self.butler, self.visitId, 

165 {"exposure": self.exposureId, 

166 "characterized": self.visitId, 

167 "sourceCat": self.visitId, 

168 "backgroundModel": self.visitId, 

169 }) 

170 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

171 

172 def testMockCalibrateTask(self): 

173 task = MockCalibrateTask() 

174 pipelineTests.assertValidInitOutput(task) 

175 # Even the real CalibrateTask won't pass assertValidOutput, because for 

176 # some reason the outputs are injected in runQuantum rather than run. 

177 

178 self.butler.put(afwImage.ExposureF(), "icExp", self.visitId) 

179 self.butler.put(afwMath.BackgroundList(), "icExpBackground", self.visitId) 

180 self.butler.put(afwTable.SourceCatalog(), "icSrc", self.visitId) 

181 self.butler.put(afwTable.SimpleCatalog(), "gaia_dr3_20230707", self.htmId) 

182 self.butler.put(afwTable.SimpleCatalog(), "ps1_pv3_3pi_20170110", self.htmId) 

183 quantum = pipelineTests.makeQuantum( 

184 task, self.butler, self.visitId, 

185 {"exposure": self.visitId, 

186 "background": self.visitId, 

187 "icSourceCat": self.visitId, 

188 "astromRefCat": [self.htmId], 

189 "photoRefCat": [self.htmId], 

190 "outputExposure": self.visitId, 

191 "outputCat": self.visitId, 

192 "outputBackground": self.visitId, 

193 "matches": self.visitId, 

194 "matchesDenormalized": self.visitId, 

195 }) 

196 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

197 

198 def testMockGetTemplateTask(self): 

199 task = MockGetTemplateTask() 

200 pipelineTests.assertValidInitOutput(task) 

201 result = task.run(coaddExposures=[afwImage.ExposureF()], 

202 bbox=lsst.geom.Box2I(), 

203 wcs=None, # Should not be allowed, but too hard to fake a SkyWcs 

204 dataIds=[], 

205 ) 

206 pipelineTests.assertValidOutput(task, result) 

207 

208 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

209 skymap = lsst.skymap.DiscreteSkyMap(lsst.skymap.DiscreteSkyMapConfig()) 

210 self.butler.put(skymap, lsst.skymap.BaseSkyMap.SKYMAP_DATASET_TYPE_NAME, self.skymapId) 

211 self.butler.put(afwImage.ExposureF(), "goodSeeingCoadd", self.patchId) 

212 quantum = pipelineTests.makeQuantum( 

213 task, self.butler, self.skymapVisitId, 

214 {"bbox": self.visitId, 

215 "wcs": self.visitId, 

216 "skyMap": self.skymapId, 

217 "coaddExposures": [self.patchId], 

218 "template": self.visitId, 

219 }) 

220 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

221 

222 def testMockAlardLuptonSubtractTask(self): 

223 task = MockAlardLuptonSubtractTask() 

224 pipelineTests.assertValidInitOutput(task) 

225 result = task.run(afwImage.ExposureF(), afwImage.ExposureF(), afwTable.SourceCatalog()) 

226 pipelineTests.assertValidOutput(task, result) 

227 

228 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId) 

229 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

230 self.butler.put(afwTable.SourceCatalog(), "src", self.visitId) 

231 quantum = pipelineTests.makeQuantum( 

232 task, self.butler, self.visitId, 

233 {"template": self.visitId, 

234 "science": self.visitId, 

235 "sources": self.visitId, 

236 "difference": self.visitId, 

237 "matchedTemplate": self.visitId, 

238 "psfMatchingKernel": self.visitId, 

239 }) 

240 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

241 

242 def testMockDetectAndMeasureTask(self): 

243 task = MockDetectAndMeasureTask() 

244 pipelineTests.assertValidInitOutput(task) 

245 result = task.run(science=afwImage.ExposureF(), 

246 matchedTemplate=afwImage.ExposureF(), 

247 difference=afwImage.ExposureF(), 

248 ) 

249 pipelineTests.assertValidOutput(task, result) 

250 

251 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

252 self.butler.put(afwImage.ExposureF(), "deepDiff_matchedExp", self.visitId) 

253 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceTempExp", self.visitId) 

254 self.butler.put(afwTable.SourceCatalog(), "src", self.visitId) 

255 quantum = pipelineTests.makeQuantum( 

256 task, self.butler, self.visitId, 

257 {"science": self.visitId, 

258 "matchedTemplate": self.visitId, 

259 "difference": self.visitId, 

260 "diaSources": self.visitId, 

261 "subtractedMeasuredExposure": self.visitId, 

262 }) 

263 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

264 

265 def testMockFilterDiaSourceCatalogTask(self): 

266 visitInfo = afwImage.VisitInfo() 

267 task = MockFilterDiaSourceCatalogTask() 

268 pipelineTests.assertValidInitOutput(task) 

269 result = task.run(afwTable.SourceCatalog(), visitInfo) 

270 pipelineTests.assertValidOutput(task, result) 

271 

272 def testMockSpatiallySampledMetricsTask(self): 

273 task = MockSpatiallySampledMetricsTask() 

274 result = task.run( 

275 afwImage.ExposureF(), 

276 afwImage.ExposureF(), 

277 afwImage.ExposureF(), 

278 afwImage.ExposureF(), 

279 afwTable.SourceCatalog(), 

280 ) 

281 pipelineTests.assertValidOutput(task, result) 

282 

283 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

284 self.butler.put(afwImage.ExposureF(), "deepDiff_matchedExp", self.visitId) 

285 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId) 

286 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId) 

287 self.butler.put(afwTable.SourceCatalog(), "deepDiff_candidateDiaSrc", self.visitId) 

288 quantum = pipelineTests.makeQuantum( 

289 task, self.butler, self.visitId, 

290 {"science": self.visitId, 

291 "matchedTemplate": self.visitId, 

292 "template": self.visitId, 

293 "difference": self.visitId, 

294 "diaSources": self.visitId, 

295 "spatiallySampledMetrics": self.visitId, 

296 }) 

297 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

298 

299 def testMockRBTransiNetTask(self): 

300 task = MockRBTransiNetTask() 

301 pipelineTests.assertValidInitOutput(task) 

302 result = task.run(template=afwImage.ExposureF(), 

303 science=afwImage.ExposureF(), 

304 difference=afwImage.ExposureF(), 

305 diaSources=afwTable.SourceCatalog(), 

306 ) 

307 pipelineTests.assertValidOutput(task, result) 

308 

309 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

310 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId) 

311 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId) 

312 self.butler.put(afwTable.SourceCatalog(), "deepDiff_candidateDiaSrc", self.visitId) 

313 quantum = pipelineTests.makeQuantum( 

314 task, self.butler, self.visitId, 

315 {"template": self.visitId, 

316 "science": self.visitId, 

317 "difference": self.visitId, 

318 "diaSources": self.visitId, 

319 "pretrainedModel": self.emptyId, 

320 "classifications": self.visitId, 

321 }) 

322 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

323 

324 def testMockTransformDiaSourceCatalogTask(self): 

325 task = MockTransformDiaSourceCatalogTask(initInputs=afwTable.SourceCatalog()) 

326 pipelineTests.assertValidInitOutput(task) 

327 result = task.run(afwTable.SourceCatalog(), afwImage.ExposureF(), 'k', 42, 2) 

328 pipelineTests.assertValidOutput(task, result) 

329 

330 self.butler.put(afwTable.SourceCatalog(), "deepDiff_candidateDiaSrc", self.visitId) 

331 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId) 

332 quantum = pipelineTests.makeQuantum( 

333 task, self.butler, self.visitId, 

334 {"diaSourceCat": self.visitId, 

335 "diffIm": self.visitId, 

336 "diaSourceTable": self.visitId, 

337 }) 

338 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

339 

340 def testMockDiaPipelineTask(self): 

341 config = MockDiaPipelineTask.ConfigClass() 

342 config.doConfigureApdb = False 

343 config.apdb_config_url = "testing_only" 

344 task = MockDiaPipelineTask(config=config) 

345 pipelineTests.assertValidInitOutput(task) 

346 result = task.run(pandas.DataFrame(), pandas.DataFrame(), afwImage.ExposureF(), 

347 afwImage.ExposureF(), afwImage.ExposureF(), 42, 'k') 

348 pipelineTests.assertValidOutput(task, result) 

349 

350 self.butler.put(pandas.DataFrame(), "deepDiff_diaSrcTable", self.visitId) 

351 self.butler.put(pandas.DataFrame(), "visitSsObjects", self.visitId) 

352 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId) 

353 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId) 

354 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId) 

355 quantum = pipelineTests.makeQuantum( 

356 task, self.butler, self.visitId, 

357 {"diaSourceTable": self.visitId, 

358 "solarSystemObjectTable": self.visitId, 

359 "diffIm": self.visitId, 

360 "exposure": self.visitId, 

361 "template": self.visitId, 

362 "apdbMarker": self.visitId, 

363 "associatedDiaSources": self.visitId, 

364 "diaForcedSources": self.visitId, 

365 "diaObjects": self.visitId, 

366 }) 

367 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False) 

368 

369 

370class MemoryTester(lsst.utils.tests.MemoryTestCase): 

371 pass 

372 

373 

374def setup_module(module): 

375 lsst.utils.tests.init() 

376 

377 

378if __name__ == "__main__": 378 ↛ 379line 378 didn't jump to line 379, because the condition on line 378 was never true

379 lsst.utils.tests.init() 

380 unittest.main()