Coverage for tests/test_quickLook.py: 16%
159 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-14 12:19 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-14 12:19 +0000
1# This file is part of summit_utils.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import contextlib
23import tempfile
24import unittest
26import numpy as np
28import lsst.afw.cameraGeom.testUtils as afwTestUtils
29import lsst.afw.image as afwImage
30from lsst.afw.image import TransmissionCurve
31import lsst.daf.butler.tests as butlerTests
32import lsst.ip.isr.isrMock as isrMock
33import lsst.ip.isr as ipIsr
34import lsst.pex.exceptions
35import lsst.pipe.base as pipeBase
36import lsst.pipe.base.testUtils
37from lsst.summit.utils.quickLook import QuickLookIsrTask, QuickLookIsrTaskConfig
40class QuickLookIsrTaskTestCase(unittest.TestCase):
41 """Tests of the run method with fake data.
42 """
44 def setUp(self):
45 self.mockConfig = isrMock.IsrMockConfig()
46 self.dataContainer = isrMock.MockDataContainer(config=self.mockConfig)
47 self.camera = isrMock.IsrMock(config=self.mockConfig).getCamera()
49 self.ccdExposure = isrMock.RawMock(config=self.mockConfig).run()
50 self.detector = self.ccdExposure.getDetector()
51 amps = self.detector.getAmplifiers()
52 ampNames = [amp.getName() for amp in amps]
54 # # Mock other optional parameters
55 self.bias = self.dataContainer.get("bias")
56 self.dark = self.dataContainer.get("dark")
57 self.flat = self.dataContainer.get("flat")
58 self.defects = self.dataContainer.get("defects")
59 self.ptc = ipIsr.PhotonTransferCurveDataset(ampNames=ampNames) # Mock PTC dataset
60 self.bfKernel = self.dataContainer.get("bfKernel")
61 self.newBFKernel = pipeBase.Struct(gain={})
62 for amp_i, amp in enumerate(ampNames):
63 self.newBFKernel.gain[amp] = 0.9 + 0.1*amp_i
64 self.task = QuickLookIsrTask(config=QuickLookIsrTaskConfig())
66 def test_runQuickLook(self):
67 # Execute the run method with the mock data
68 result = self.task.run(self.ccdExposure,
69 camera=self.camera,
70 bias=self.bias,
71 dark=self.dark,
72 flat=self.flat,
73 defects=self.defects,
74 linearizer=None,
75 crosstalk=None,
76 bfKernel=self.bfKernel,
77 newBFKernel=self.newBFKernel,
78 ptc=self.ptc,
79 crosstalkSources=None
80 )
81 self.assertIsNotNone(result, "Result of run method should not be None")
82 self.assertIsInstance(result, pipeBase.Struct, "Result should be of type lsst.pipe.base.Struct")
83 self.assertIsInstance(result.exposure, afwImage.Exposure,
84 "Resulting exposure should be an instance of lsst.afw.image.Exposure")
86 def test_runQuickLookMissingData(self):
87 # Test without any inputs other than the exposure
88 result = self.task.run(self.ccdExposure)
89 self.assertIsInstance(result.exposure, afwImage.Exposure)
91 def test_runQuickLookBadDark(self):
92 # Test with an incorrect dark frame
93 bbox = self.ccdExposure.getBBox()
94 bbox.grow(-20)
95 with self.assertRaises(lsst.pex.exceptions.wrappers.LengthError):
96 self.task.run(self.ccdExposure, camera=self.camera, bias=self.bias,
97 dark=self.dark[bbox], flat=self.flat, defects=self.defects)
100class QuickLookIsrTaskRunQuantumTests(lsst.utils.tests.TestCase):
101 """Tests of ``QuickLookIsrTask.runQuantum``, which need a test butler,
102 but do not need real images.
104 Adapted from the unit tests of ``CalibrateImageTask.runQuantum``
105 """
106 def setUp(self):
107 instrument = "testCam"
108 exposureId = 100
109 visit = 100101
110 detector = 0
111 physical_filter = "testCam_filter"
112 band = "X"
114 # Map the isrTask connection names to the names of the Butler dataset
115 # inputs
116 ccdExposure = "raw"
117 camera = "camera"
118 bias = "bias"
119 dark = "dark"
120 flat = "flat"
121 defects = "defects"
122 bfKernel = "bfKernel"
123 newBFKernel = "brighterFatterKernel"
124 ptc = "ptc"
125 filterTransmission = "transmission_filter"
126 deferredChargeCalib = "cpCtiCalib"
127 opticsTransmission = "transmission_optics"
128 strayLightData = "yBackground"
129 atmosphereTransmission = "transmission_atmosphere"
130 crosstalk = "crosstalk"
131 illumMaskedImage = "illum"
132 linearizer = "linearizer"
133 fringes = "fringe"
134 sensorTransmission = "transmission_sensor"
135 crosstalkSources = "isrOverscanCorrected"
137 # outputs
138 outputExposure = "postISRCCD"
140 # quickLook-only outputs
141 exposure = "quickLookExp"
143 # Create a and populate a test butler for runQuantum tests.
144 self.repo_path = tempfile.TemporaryDirectory(ignore_cleanup_errors=True)
145 self.repo = butlerTests.makeTestRepo(self.repo_path.name)
147 # dataIds for fake data
148 butlerTests.addDataIdValue(self.repo, "instrument", instrument)
149 butlerTests.addDataIdValue(self.repo, "physical_filter", physical_filter, band=band)
150 butlerTests.addDataIdValue(self.repo, "detector", detector)
151 butlerTests.addDataIdValue(self.repo, "exposure", exposureId, physical_filter=physical_filter)
152 butlerTests.addDataIdValue(self.repo, "visit", visit)
154 # inputs
155 butlerTests.addDatasetType(self.repo, ccdExposure,
156 {"instrument", "exposure", "detector"}, "Exposure")
157 butlerTests.addDatasetType(self.repo, camera,
158 {"instrument"}, "Camera")
159 butlerTests.addDatasetType(self.repo, bias,
160 {"instrument", "detector"}, "Exposure")
161 butlerTests.addDatasetType(self.repo, dark,
162 {"instrument", "detector"}, "Exposure")
163 butlerTests.addDatasetType(self.repo, flat,
164 {"instrument", "physical_filter", "detector"}, "Exposure")
165 butlerTests.addDatasetType(self.repo, defects,
166 {"instrument", "detector"}, "Defects")
167 butlerTests.addDatasetType(self.repo, linearizer,
168 {"instrument", "detector"}, "Linearizer")
169 butlerTests.addDatasetType(self.repo, crosstalk,
170 {"instrument", "detector"}, "CrosstalkCalib")
171 butlerTests.addDatasetType(self.repo, bfKernel,
172 {"instrument"}, "NumpyArray")
173 butlerTests.addDatasetType(self.repo, newBFKernel,
174 {"instrument", "detector"}, "BrighterFatterKernel")
175 butlerTests.addDatasetType(self.repo, ptc,
176 {"instrument", "detector"}, "PhotonTransferCurveDataset")
177 butlerTests.addDatasetType(self.repo, filterTransmission,
178 {"instrument", "physical_filter"}, "TransmissionCurve")
179 butlerTests.addDatasetType(self.repo, opticsTransmission,
180 {"instrument"}, "TransmissionCurve")
181 butlerTests.addDatasetType(self.repo, deferredChargeCalib,
182 {"instrument", "detector"}, "IsrCalib")
183 butlerTests.addDatasetType(self.repo, strayLightData,
184 {"instrument", "physical_filter", "detector"}, "Exposure")
185 butlerTests.addDatasetType(self.repo, atmosphereTransmission,
186 {"instrument"}, "TransmissionCurve")
187 butlerTests.addDatasetType(self.repo, illumMaskedImage,
188 {"instrument", "physical_filter", "detector"}, "MaskedImage")
189 butlerTests.addDatasetType(self.repo, fringes,
190 {"instrument", "physical_filter", "detector"}, "Exposure")
191 butlerTests.addDatasetType(self.repo, sensorTransmission,
192 {"instrument", "detector"}, "TransmissionCurve")
193 butlerTests.addDatasetType(self.repo, crosstalkSources,
194 {"instrument", "exposure", "detector"}, "Exposure")
196 # outputs
197 butlerTests.addDatasetType(self.repo, outputExposure,
198 {"instrument", "exposure", "detector"}, "Exposure")
199 butlerTests.addDatasetType(self.repo, exposure,
200 {"instrument", "exposure", "detector"}, "Exposure")
202 # dataIds
203 self.exposure_id = self.repo.registry.expandDataId(
204 {"instrument": instrument, "exposure": exposureId, "detector": detector,
205 "physical_filter": physical_filter})
206 self.instrument_id = self.repo.registry.expandDataId(
207 {"instrument": instrument})
208 self.flat_id = self.repo.registry.expandDataId(
209 {"instrument": instrument, "physical_filter": physical_filter, "detector": detector})
210 self.detector_id = self.repo.registry.expandDataId(
211 {"instrument": instrument, "detector": detector})
212 self.filter_id = self.repo.registry.expandDataId(
213 {"instrument": instrument, "physical_filter": physical_filter})
215 # put empty data
216 transmissionCurve = TransmissionCurve.makeSpatiallyConstant(np.ones(2), np.linspace(0, 1, 2), 0., 0.)
217 self.butler = butlerTests.makeTestCollection(self.repo)
218 self.butler.put(afwImage.ExposureF(), ccdExposure, self.exposure_id)
219 self.butler.put(afwTestUtils.CameraWrapper().camera, camera, self.instrument_id)
220 self.butler.put(afwImage.ExposureF(), bias, self.detector_id)
221 self.butler.put(afwImage.ExposureF(), dark, self.detector_id)
222 self.butler.put(afwImage.ExposureF(), flat, self.flat_id)
223 self.butler.put(lsst.ip.isr.Defects(), defects, self.detector_id)
224 self.butler.put(np.zeros(2), bfKernel, self.instrument_id)
225 self.butler.put(lsst.ip.isr.brighterFatterKernel.BrighterFatterKernel(),
226 newBFKernel, self.detector_id)
227 self.butler.put(ipIsr.PhotonTransferCurveDataset(), ptc, self.detector_id)
228 self.butler.put(transmissionCurve, filterTransmission, self.filter_id)
229 self.butler.put(lsst.ip.isr.calibType.IsrCalib(), deferredChargeCalib, self.detector_id)
230 self.butler.put(transmissionCurve, opticsTransmission, self.instrument_id)
231 self.butler.put(afwImage.ExposureF(), strayLightData, self.flat_id)
232 self.butler.put(transmissionCurve, atmosphereTransmission, self.instrument_id)
233 self.butler.put(lsst.ip.isr.crosstalk.CrosstalkCalib(), crosstalk, self.detector_id)
234 self.butler.put(afwImage.ExposureF().maskedImage, illumMaskedImage, self.flat_id)
235 self.butler.put(lsst.ip.isr.linearize.Linearizer(), linearizer, self.detector_id)
236 self.butler.put(afwImage.ExposureF(), fringes, self.flat_id)
237 self.butler.put(transmissionCurve, sensorTransmission, self.detector_id)
238 self.butler.put(afwImage.ExposureF(), crosstalkSources, self.exposure_id)
240 def tearDown(self):
241 del self.repo_path # this removes the temporary directory
243 def test_runQuantum(self):
244 config = ipIsr.IsrTaskConfig()
245 # Remove some outputs
246 config.doBinnedExposures = False
247 config.doSaveInterpPixels = False
248 config.qa.doThumbnailOss = False
249 config.qa.doThumbnailFlattened = False
250 config.doCalculateStatistics = False
252 # Turn on all optional inputs
253 config.doAttachTransmissionCurve = True
254 config.doIlluminationCorrection = True
255 config.doStrayLight = True
256 config.doDeferredCharge = True
257 config.usePtcReadNoise = True
258 config.doCrosstalk = True
259 config.doBrighterFatter = True
261 # Override a method in IsrTask that is executed early, to instead raise
262 # a custom exception called ExitMock that we can catch and ignore.
263 isrTask = ipIsr.IsrTask
264 isrTask.ensureExposure = raiseExitMockError
265 task = QuickLookIsrTask(isrTask=isrTask)
266 lsst.pipe.base.testUtils.assertValidInitOutput(task)
268 # Use the names of the connections here, not the Butler dataset name
269 quantum = lsst.pipe.base.testUtils.makeQuantum(
270 task, self.butler, self.exposure_id,
271 {"ccdExposure": self.exposure_id,
272 "camera": self.instrument_id,
273 "bias": self.detector_id,
274 "dark": self.detector_id,
275 "flat": self.flat_id,
276 "defects": self.detector_id,
277 "bfKernel": self.instrument_id,
278 "newBFKernel": self.detector_id,
279 "ptc": self.detector_id,
280 "filterTransmission": self.filter_id,
281 "deferredChargeCalib": self.detector_id,
282 "opticsTransmission": self.instrument_id,
283 "strayLightData": self.flat_id,
284 "atmosphereTransmission": self.instrument_id,
285 "crosstalk": self.detector_id,
286 "illumMaskedImage": self.flat_id,
287 "linearizer": self.detector_id,
288 "fringes": self.flat_id,
289 "sensorTransmission": self.detector_id,
290 "crosstalkSources": [self.exposure_id, self.exposure_id],
291 # outputs
292 "outputExposure": self.exposure_id,
293 "exposure": self.exposure_id,
294 })
295 # Check that the proper kwargs are passed to run().
296 with contextlib.suppress(ExitMockError):
297 lsst.pipe.base.testUtils.runTestQuantum(task, self.butler, quantum, mockRun=False)
300def raiseExitMockError(*args):
301 """Raise a custom exception.
302 """
303 raise ExitMockError
306class ExitMockError(Exception):
308 """A custom exception to catch during a unit test.
309 """
311 pass