Coverage for tests/test_testPipeline.py: 18%
182 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 04:12 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 04:12 -0700
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#
24import shutil
25import tempfile
26import unittest
28import pandas
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
44class MockTaskTestSuite(unittest.TestCase):
45 """Test that mock tasks have the correct inputs and outputs for the task
46 they are replacing.
48 These tests assume that the mock tasks use real config and connection
49 classes, and therefore out-of-date mocks won't match their connections.
50 """
52 @classmethod
53 def setUpClass(cls):
54 super().setUpClass()
56 repoDir = tempfile.mkdtemp()
57 cls.addClassCleanup(shutil.rmtree, repoDir, ignore_errors=True)
58 cls.repo = butlerTests.makeTestRepo(repoDir)
60 INSTRUMENT = "DummyCam"
61 VISIT = 42
62 CCD = 101
63 HTM = 42
64 SKYMAP = "TreasureMap"
65 TRACT = 28
66 PATCH = 4
67 BAND = 'k'
68 PHYSICAL = 'k2022'
69 SUB_FILTER = 9
70 # Mock instrument by hand, because some tasks care about parameters
71 instrumentRecord = cls.repo.dimensions["instrument"].RecordClass(
72 name=INSTRUMENT, visit_max=256, exposure_max=256, detector_max=128,
73 class_name="lsst.obs.base.instrument_tests.DummyCam",
74 )
75 cls.repo.registry.syncDimensionData("instrument", instrumentRecord)
76 butlerTests.addDataIdValue(cls.repo, "physical_filter", PHYSICAL, band=BAND)
77 butlerTests.addDataIdValue(cls.repo, "subfilter", SUB_FILTER)
78 butlerTests.addDataIdValue(cls.repo, "exposure", VISIT)
79 butlerTests.addDataIdValue(cls.repo, "visit", VISIT)
80 butlerTests.addDataIdValue(cls.repo, "detector", CCD)
81 butlerTests.addDataIdValue(cls.repo, "skymap", SKYMAP)
82 butlerTests.addDataIdValue(cls.repo, "tract", TRACT)
83 butlerTests.addDataIdValue(cls.repo, "patch", PATCH)
85 cls.emptyId = cls.repo.registry.expandDataId({})
86 cls.exposureId = cls.repo.registry.expandDataId(
87 {"instrument": INSTRUMENT, "exposure": VISIT, "detector": CCD})
88 cls.visitId = cls.repo.registry.expandDataId(
89 {"instrument": INSTRUMENT, "visit": VISIT, "detector": CCD})
90 cls.visitOnlyId = cls.repo.registry.expandDataId(
91 {"instrument": INSTRUMENT, "visit": VISIT})
92 cls.skymapId = cls.repo.registry.expandDataId({"skymap": SKYMAP})
93 cls.skymapVisitId = cls.repo.registry.expandDataId(
94 {"instrument": INSTRUMENT, "visit": VISIT, "detector": CCD, "skymap": SKYMAP})
95 cls.patchId = cls.repo.registry.expandDataId(
96 {"skymap": SKYMAP, "tract": TRACT, "patch": PATCH, "band": BAND})
97 cls.subfilterId = cls.repo.registry.expandDataId(
98 {"skymap": SKYMAP, "tract": TRACT, "patch": PATCH, "band": BAND, "subfilter": SUB_FILTER})
99 cls.htmId = cls.repo.registry.expandDataId({"htm7": HTM})
101 butlerTests.addDatasetType(cls.repo, "postISRCCD", cls.exposureId.dimensions, "Exposure")
102 butlerTests.addDatasetType(cls.repo, "icExp", cls.visitId.dimensions, "ExposureF")
103 butlerTests.addDatasetType(cls.repo, "icSrc", cls.visitId.dimensions, "SourceCatalog")
104 butlerTests.addDatasetType(cls.repo, "icExpBackground", cls.visitId.dimensions, "Background")
105 butlerTests.addDatasetType(cls.repo, "gaia_dr3_20230707", cls.htmId.dimensions, "SimpleCatalog")
106 butlerTests.addDatasetType(cls.repo, "ps1_pv3_3pi_20170110", cls.htmId.dimensions, "SimpleCatalog")
107 butlerTests.addDatasetType(cls.repo, "calexp", cls.visitId.dimensions, "ExposureF")
108 butlerTests.addDatasetType(cls.repo, "src", cls.visitId.dimensions, "SourceCatalog")
109 butlerTests.addDatasetType(cls.repo, "calexpBackground", cls.visitId.dimensions, "Background")
110 butlerTests.addDatasetType(cls.repo, "srcMatch", cls.visitId.dimensions, "Catalog")
111 butlerTests.addDatasetType(cls.repo, "srcMatchFull", cls.visitId.dimensions, "Catalog")
112 butlerTests.addDatasetType(cls.repo, lsst.skymap.BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
113 cls.skymapId.dimensions, "SkyMap")
114 butlerTests.addDatasetType(cls.repo, "goodSeeingCoadd", cls.patchId.dimensions, "ExposureF")
115 butlerTests.addDatasetType(cls.repo, "deepDiff_differenceExp", cls.visitId.dimensions, "ExposureF")
116 butlerTests.addDatasetType(cls.repo, "deepDiff_differenceTempExp", cls.visitId.dimensions,
117 "ExposureF")
118 butlerTests.addDatasetType(cls.repo, "deepDiff_templateExp", cls.visitId.dimensions, "ExposureF")
119 butlerTests.addDatasetType(cls.repo, "goodSeeingDiff_templateExp", cls.visitId.dimensions,
120 "ExposureF")
121 butlerTests.addDatasetType(cls.repo, "deepDiff_matchedExp", cls.visitId.dimensions, "ExposureF")
122 butlerTests.addDatasetType(cls.repo, "deepDiff_diaSrc", cls.visitId.dimensions, "SourceCatalog")
123 butlerTests.addDatasetType(cls.repo, "deepDiff_diaSrcTable", cls.visitId.dimensions, "DataFrame")
124 butlerTests.addDatasetType(cls.repo, "deepDiff_spatiallySampledMetrics", cls.visitId.dimensions,
125 "ArrowAstropy")
126 butlerTests.addDatasetType(cls.repo, "deepDiff_candidateDiaSrc", cls.visitId.dimensions,
127 "SourceCatalog")
128 butlerTests.addDatasetType(cls.repo, "visitSsObjects", cls.visitOnlyId.dimensions, "DataFrame")
129 butlerTests.addDatasetType(cls.repo, "apdb_marker", cls.visitId.dimensions, "Config")
130 butlerTests.addDatasetType(cls.repo, "deepDiff_assocDiaSrc", cls.visitId.dimensions, "DataFrame")
131 butlerTests.addDatasetType(cls.repo, "deepDiff_longTrailedSrc", cls.visitId.dimensions, "DataFrame")
132 butlerTests.addDatasetType(cls.repo, "deepRealBogusSources", cls.visitId.dimensions, "Catalog")
133 butlerTests.addDatasetType(cls.repo, "deepDiff_diaForcedSrc", cls.visitId.dimensions, "DataFrame")
134 butlerTests.addDatasetType(cls.repo, "deepDiff_diaObject", cls.visitId.dimensions, "DataFrame")
136 def setUp(self):
137 super().setUp()
138 self.butler = butlerTests.makeTestCollection(self.repo, uniqueId=self.id())
140 def testMockIsr(self):
141 # Testing MockIsrTask is tricky because the real ISR has an unstable
142 # interface with dozens of potential inputs, too many to pass through
143 # runTestQuantum. I don't see a good way to test the inputs;
144 # fortunately, this is unlikely to matter for the overall goal of
145 # testing ap_verify's interaction with the AP pipeline.
146 task = MockIsrTask()
147 pipelineTests.assertValidInitOutput(task)
148 result = task.run(afwImage.ExposureF())
149 pipelineTests.assertValidOutput(task, result)
150 # Skip runTestQuantum
152 def testMockCharacterizeImageTask(self):
153 task = MockCharacterizeImageTask()
154 pipelineTests.assertValidInitOutput(task)
155 result = task.run(afwImage.ExposureF())
156 pipelineTests.assertValidOutput(task, result)
158 self.butler.put(afwImage.ExposureF(), "postISRCCD", self.exposureId)
159 quantum = pipelineTests.makeQuantum(
160 task, self.butler, self.visitId,
161 {"exposure": self.exposureId,
162 "characterized": self.visitId,
163 "sourceCat": self.visitId,
164 "backgroundModel": self.visitId,
165 })
166 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
168 def testMockCalibrateTask(self):
169 task = MockCalibrateTask()
170 pipelineTests.assertValidInitOutput(task)
171 # Even the real CalibrateTask won't pass assertValidOutput, because for
172 # some reason the outputs are injected in runQuantum rather than run.
174 self.butler.put(afwImage.ExposureF(), "icExp", self.visitId)
175 self.butler.put(afwMath.BackgroundList(), "icExpBackground", self.visitId)
176 self.butler.put(afwTable.SourceCatalog(), "icSrc", self.visitId)
177 self.butler.put(afwTable.SimpleCatalog(), "gaia_dr3_20230707", self.htmId)
178 self.butler.put(afwTable.SimpleCatalog(), "ps1_pv3_3pi_20170110", self.htmId)
179 quantum = pipelineTests.makeQuantum(
180 task, self.butler, self.visitId,
181 {"exposure": self.visitId,
182 "background": self.visitId,
183 "icSourceCat": self.visitId,
184 "astromRefCat": [self.htmId],
185 "photoRefCat": [self.htmId],
186 "outputExposure": self.visitId,
187 "outputCat": self.visitId,
188 "outputBackground": self.visitId,
189 "matches": self.visitId,
190 "matchesDenormalized": self.visitId,
191 })
192 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
194 def testMockGetTemplateTask(self):
195 task = MockGetTemplateTask()
196 pipelineTests.assertValidInitOutput(task)
197 result = task.run(coaddExposures=[afwImage.ExposureF()],
198 bbox=lsst.geom.Box2I(),
199 wcs=None, # Should not be allowed, but too hard to fake a SkyWcs
200 dataIds=[],
201 )
202 pipelineTests.assertValidOutput(task, result)
204 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId)
205 skymap = lsst.skymap.DiscreteSkyMap(lsst.skymap.DiscreteSkyMapConfig())
206 self.butler.put(skymap, lsst.skymap.BaseSkyMap.SKYMAP_DATASET_TYPE_NAME, self.skymapId)
207 self.butler.put(afwImage.ExposureF(), "goodSeeingCoadd", self.patchId)
208 quantum = pipelineTests.makeQuantum(
209 task, self.butler, self.skymapVisitId,
210 {"bbox": self.visitId,
211 "wcs": self.visitId,
212 "skyMap": self.skymapId,
213 "coaddExposures": [self.patchId],
214 "template": self.visitId,
215 })
216 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
218 def testMockAlardLuptonSubtractTask(self):
219 task = MockAlardLuptonSubtractTask()
220 pipelineTests.assertValidInitOutput(task)
221 result = task.run(afwImage.ExposureF(), afwImage.ExposureF(), afwTable.SourceCatalog())
222 pipelineTests.assertValidOutput(task, result)
224 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId)
225 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId)
226 self.butler.put(afwTable.SourceCatalog(), "src", self.visitId)
227 quantum = pipelineTests.makeQuantum(
228 task, self.butler, self.visitId,
229 {"template": self.visitId,
230 "science": self.visitId,
231 "sources": self.visitId,
232 "difference": self.visitId,
233 "matchedTemplate": self.visitId,
234 })
235 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
237 def testMockDetectAndMeasureTask(self):
238 task = MockDetectAndMeasureTask()
239 pipelineTests.assertValidInitOutput(task)
240 result = task.run(science=afwImage.ExposureF(),
241 matchedTemplate=afwImage.ExposureF(),
242 difference=afwImage.ExposureF(),
243 )
244 pipelineTests.assertValidOutput(task, result)
246 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId)
247 self.butler.put(afwImage.ExposureF(), "deepDiff_matchedExp", self.visitId)
248 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceTempExp", self.visitId)
249 self.butler.put(afwTable.SourceCatalog(), "src", self.visitId)
250 quantum = pipelineTests.makeQuantum(
251 task, self.butler, self.visitId,
252 {"science": self.visitId,
253 "matchedTemplate": self.visitId,
254 "difference": self.visitId,
255 "diaSources": self.visitId,
256 "subtractedMeasuredExposure": self.visitId,
257 "spatiallySampledMetrics": self.visitId,
258 })
259 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
261 def testMockFilterDiaSourceCatalogTask(self):
262 task = MockFilterDiaSourceCatalogTask()
263 pipelineTests.assertValidInitOutput(task)
264 result = task.run(afwTable.SourceCatalog())
265 pipelineTests.assertValidOutput(task, result)
267 def testMockRBTransiNetTask(self):
268 task = MockRBTransiNetTask()
269 pipelineTests.assertValidInitOutput(task)
270 result = task.run(template=afwImage.ExposureF(),
271 science=afwImage.ExposureF(),
272 difference=afwImage.ExposureF(),
273 diaSources=afwTable.SourceCatalog(),
274 )
275 pipelineTests.assertValidOutput(task, result)
277 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId)
278 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId)
279 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId)
280 self.butler.put(afwTable.SourceCatalog(), "deepDiff_candidateDiaSrc", self.visitId)
281 quantum = pipelineTests.makeQuantum(
282 task, self.butler, self.visitId,
283 {"template": self.visitId,
284 "science": self.visitId,
285 "difference": self.visitId,
286 "diaSources": self.visitId,
287 "pretrainedModel": self.emptyId,
288 "classifications": self.visitId,
289 })
290 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
292 def testMockTransformDiaSourceCatalogTask(self):
293 task = MockTransformDiaSourceCatalogTask(initInputs=afwTable.SourceCatalog())
294 pipelineTests.assertValidInitOutput(task)
295 result = task.run(afwTable.SourceCatalog(), afwImage.ExposureF(), 'k', 42)
296 pipelineTests.assertValidOutput(task, result)
298 self.butler.put(afwTable.SourceCatalog(), "deepDiff_candidateDiaSrc", self.visitId)
299 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId)
300 quantum = pipelineTests.makeQuantum(
301 task, self.butler, self.visitId,
302 {"diaSourceCat": self.visitId,
303 "diffIm": self.visitId,
304 "diaSourceTable": self.visitId,
305 })
306 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
308 def testMockDiaPipelineTask(self):
309 config = MockDiaPipelineTask.ConfigClass()
310 config.apdb.db_url = "testing_only"
311 task = MockDiaPipelineTask(config=config)
312 pipelineTests.assertValidInitOutput(task)
313 result = task.run(pandas.DataFrame(), pandas.DataFrame(), afwImage.ExposureF(),
314 afwImage.ExposureF(), afwImage.ExposureF(), 42, 'k')
315 pipelineTests.assertValidOutput(task, result)
317 self.butler.put(pandas.DataFrame(), "deepDiff_diaSrcTable", self.visitId)
318 self.butler.put(pandas.DataFrame(), "visitSsObjects", self.visitId)
319 self.butler.put(afwImage.ExposureF(), "deepDiff_differenceExp", self.visitId)
320 self.butler.put(afwImage.ExposureF(), "calexp", self.visitId)
321 self.butler.put(afwImage.ExposureF(), "deepDiff_templateExp", self.visitId)
322 quantum = pipelineTests.makeQuantum(
323 task, self.butler, self.visitId,
324 {"diaSourceTable": self.visitId,
325 "solarSystemObjectTable": self.visitId,
326 "diffIm": self.visitId,
327 "exposure": self.visitId,
328 "template": self.visitId,
329 "apdbMarker": self.visitId,
330 "associatedDiaSources": self.visitId,
331 "longTrailedSources": self.visitId,
332 "diaForcedSources": self.visitId,
333 "diaObjects": self.visitId,
334 })
335 pipelineTests.runTestQuantum(task, self.butler, quantum, mockRun=False)
338class MemoryTester(lsst.utils.tests.MemoryTestCase):
339 pass
342def setup_module(module):
343 lsst.utils.tests.init()
346if __name__ == "__main__": 346 ↛ 347line 346 didn't jump to line 347, because the condition on line 346 was never true
347 lsst.utils.tests.init()
348 unittest.main()