Coverage for tests/test_calibrate.py: 26%
113 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-22 10:58 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-22 10:58 +0000
1# This file is part of pipe_tasks.
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/>.
22"""Test ProcessCcdTask and its immediate subtasks.
23"""
24import logging
25import os
26import shutil
27import tempfile
28import unittest
30import lsst.utils.tests
31import lsst.afw.image
32import lsst.afw.math
33import lsst.afw.table
34import lsst.daf.butler.tests as butlerTests
35from lsst.utils import getPackageDir
36from lsst.pipe.base import testUtils
37from lsst.pipe.tasks.calibrate import CalibrateTask, CalibrateConfig
38from lsst.pipe.tasks.characterizeImage import CharacterizeImageTask, CharacterizeImageConfig
39import lsst.meas.extensions.piff.piffPsfDeterminer
42class CalibrateTaskTestCaseWithButler(lsst.utils.tests.TestCase):
44 @classmethod
45 def _makeTestRepo(cls, root):
46 """Create a repository with the metadata assumed by CalibrateTask.
47 """
48 # In-memory for performance
49 config = lsst.daf.butler.Config()
50 config["datastore", "cls"] = "lsst.daf.butler.datastores.inMemoryDatastore.InMemoryDatastore"
51 config["datastore", "checksum"] = False
52 config["registry", "db"] = "sqlite:///:memory:"
54 butler = lsst.daf.butler.Butler(lsst.daf.butler.Butler.makeRepo(root, config=config), writeable=True)
55 butler.registry.insertDimensionData(
56 "instrument",
57 {"name": "notACam", "visit_max": 256, "exposure_max": 256, "detector_max": 64})
58 butler.registry.insertDimensionData(
59 "physical_filter",
60 {"instrument": "notACam", "name": "r", "band": "r"},
61 )
62 butler.registry.insertDimensionData(
63 "visit",
64 {"instrument": "notACam", "id": 101, "name": "101", "physical_filter": "r"},
65 )
66 butler.registry.insertDimensionData("detector",
67 {"instrument": "notACam", "id": 42, "full_name": "42"})
68 return butler
70 @classmethod
71 def setUpClass(cls):
72 super().setUpClass()
74 cls.root = tempfile.mkdtemp()
75 cls.repo = cls._makeTestRepo(cls.root)
77 butlerTests.addDatasetType(
78 cls.repo, "icExp", {"instrument", "visit", "detector"},
79 "ExposureF")
80 butlerTests.addDatasetType(
81 cls.repo, "icExpBackground", {"instrument", "visit", "detector"},
82 "Background")
83 butlerTests.addDatasetType(
84 cls.repo, "icSrc", {"instrument", "visit", "detector"},
85 "SourceCatalog")
86 butlerTests.addDatasetType(
87 cls.repo, "cal_ref_cat", {"htm7"},
88 "SimpleCatalog")
89 butlerTests.addDatasetType(
90 cls.repo, "calexp", {"instrument", "visit", "detector"},
91 "ExposureF")
92 butlerTests.addDatasetType(
93 cls.repo, "src", {"instrument", "visit", "detector"},
94 "SourceCatalog")
95 butlerTests.addDatasetType(
96 cls.repo, "calexpBackground", {"instrument", "visit", "detector"},
97 "Background")
98 butlerTests.addDatasetType(
99 cls.repo, "srcMatch", {"instrument", "visit", "detector"},
100 "Catalog")
101 butlerTests.addDatasetType(
102 cls.repo, "srcMatchFull", {"instrument", "visit", "detector"},
103 "Catalog")
105 @classmethod
106 def tearDownClass(cls):
107 shutil.rmtree(cls.root, ignore_errors=True)
108 super().tearDownClass()
110 def setUp(self):
111 super().setUp()
112 self.butler = butlerTests.makeTestCollection(self.repo)
114 self.dataId = {"instrument": "notACam", "visit": 101, "detector": 42}
115 # CalibrateTask absolutely requires an ExpandedDataCoordinate
116 self.dataId = self.butler.registry.expandDataId(self.dataId)
117 self.refcatId = {"htm7": 189584}
119 # Tests do no processing, so we don't need real data
120 self.exposure = lsst.afw.image.ExposureF(10, 10)
121 background = lsst.afw.math.BackgroundMI(self.exposure.getBBox(), self.exposure.getMaskedImage())
122 self.backgroundlist = lsst.afw.math.BackgroundList(
123 (background, lsst.afw.math.Interpolate.UNKNOWN, lsst.afw.math.UndersampleStyle.THROW_EXCEPTION,
124 lsst.afw.math.ApproximateControl.UNKNOWN, 0, 0, 1))
125 self.icSrc = lsst.afw.table.SourceCatalog()
126 self.refcat = lsst.afw.table.SimpleCatalog()
128 self.butler.put(self.exposure, "icExp", self.dataId)
129 self.butler.put(self.backgroundlist, "icExpBackground", self.dataId)
130 self.butler.put(self.icSrc, "icSrc", self.dataId)
131 self.butler.put(self.refcat, "cal_ref_cat", self.refcatId)
133 def testDoAstrometry(self):
134 """Ensure correct inputs passed to run whether or not doAstrometry
135 is set.
136 """
137 allIds = {key: self.dataId for key in {
138 "exposure", "background", "icSourceCat", "outputExposure", "outputCat", "outputBackground",
139 "matches", "matchesDenormalized"
140 }}
141 allIds.update({key: [self.refcatId] for key in {"astromRefCat", "photoRefCat"}})
143 self._checkDoRefcats(doAstrometry=True, doPhotoCal=True, ids=allIds)
144 self._checkDoRefcats(doAstrometry=False, doPhotoCal=True, ids=allIds)
146 def testDoPhotoCal(self):
147 """Ensure correct inputs passed to run whether or not doPhotoCal
148 is set.
149 """
150 allIds = {key: self.dataId for key in {
151 "exposure", "background", "icSourceCat", "outputExposure", "outputCat", "outputBackground",
152 "matches", "matchesDenormalized"
153 }}
154 allIds.update({key: [self.refcatId] for key in {"astromRefCat", "photoRefCat"}})
156 self._checkDoRefcats(doAstrometry=True, doPhotoCal=True, ids=allIds)
157 self._checkDoRefcats(doAstrometry=True, doPhotoCal=False, ids=allIds)
159 def _checkDoRefcats(self, doAstrometry, doPhotoCal, ids):
160 """Test whether run is called with the correct arguments.
162 In the case of `CalibrateTask`, the inputs should not depend on the
163 task configuration.
165 Parameters
166 ----------
167 doAstrometry, doPhotoCal : `bool`
168 Values of the config flags of the same name.
169 ids : `dict` [`str`]
170 A mapping from the input dataset type to the data ID of the
171 dataset to process.
172 """
173 config = CalibrateConfig()
174 config.doWriteMatches = False # no real output to write
175 config.doAstrometry = doAstrometry
176 config.doPhotoCal = doPhotoCal
177 config.connections.photoRefCat = "cal_ref_cat"
178 config.connections.astromRefCat = "cal_ref_cat"
179 config.idGenerator.packer.name = "observation"
180 task = CalibrateTask(config=config)
181 quantumId = ids["exposure"]
183 quantum = testUtils.makeQuantum(task, self.butler, quantumId, ids)
184 run = testUtils.runTestQuantum(task, self.butler, quantum)
186 run.assert_called_once()
187 self.assertEqual(run.call_args[0], ())
188 # Some arguments unprintable because we don't have a full environment
189 # So just check which ones were passed in
190 self.assertEqual(run.call_args[1].keys(),
191 {"exposure", "idGenerator", "background", "icSourceCat"})
193 def testNoAperCorrMap(self):
194 expPath = os.path.join(getPackageDir("pipe_tasks"), "tests", "data", "v695833-e0-c000-a00.sci.fits")
195 exposure = lsst.afw.image.ExposureF(expPath)
197 charImConfig = CharacterizeImageConfig()
198 charImConfig.measurePsf.psfDeterminer = 'piff'
199 charImConfig.measurePsf.psfDeterminer['piff'].spatialOrder = 0
200 charImConfig.measureApCorr.sourceSelector["science"].doSignalToNoise = False
201 charImTask = CharacterizeImageTask(config=charImConfig)
202 charImResults = charImTask.run(exposure)
203 calibConfig = CalibrateConfig()
204 calibConfig.doAstrometry = False
205 calibConfig.doPhotoCal = False
206 calibConfig.doSkySources = False
207 calibConfig.doComputeSummaryStats = False
209 # Force the aperture correction map to None (DM-39626)
210 exposure.info.setApCorrMap(None)
211 calibTask = CalibrateTask(config=calibConfig)
212 with self.assertLogs(level=logging.WARNING) as cm:
213 _ = calibTask.run(charImResults.exposure)
214 self.assertIn("Image does not have valid aperture correction map", cm.output[0])
217def setup_module(module):
218 lsst.utils.tests.init()
221class MemoryTestCase(lsst.utils.tests.MemoryTestCase):
222 pass
225if __name__ == "__main__": 225 ↛ 226line 225 didn't jump to line 226, because the condition on line 225 was never true
226 lsst.utils.tests.init()
227 unittest.main()