Coverage for tests/test_make_direct_warp.py: 19%
98 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-27 03:33 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-27 03:33 -0700
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/>.
22import unittest
24import numpy as np
26import lsst.utils.tests
28import lsst.afw.image
29from lsst.daf.butler import DataCoordinate, DimensionUniverse
30from lsst.pipe.base import InMemoryDatasetHandle
31from lsst.pipe.tasks.make_direct_warp import (MakeDirectWarpConfig, MakeDirectWarpTask,)
32from lsst.pipe.tasks.coaddBase import makeSkyInfo
33import lsst.skymap as skyMap
34from lsst.afw.detection import GaussianPsf
35import lsst.afw.cameraGeom.testUtils
38def generate_data_id(
39 *,
40 tract: int = 9813,
41 patch: int = 42,
42 band: str = "r",
43 detector_id: int = 9,
44 visit_id: int = 1234,
45 detector_max: int = 109,
46 visit_max: int = 10000
47) -> DataCoordinate:
48 """Generate a DataCoordinate instance to use as data_id.
50 Parameters
51 ----------
52 tract : `int`, optional
53 Tract ID for the data_id
54 patch : `int`, optional
55 Patch ID for the data_id
56 band : `str`, optional
57 Band for the data_id
58 detector_id : `int`, optional
59 Detector ID for the data_id
60 visit_id : `int`, optional
61 Visit ID for the data_id
62 detector_max : `int`, optional
63 Maximum detector ID for the data_id
64 visit_max : `int`, optional
65 Maximum visit ID for the data_id
67 Returns
68 -------
69 data_id : `lsst.daf.butler.DataCoordinate`
70 An expanded data_id instance.
71 """
72 universe = DimensionUniverse()
74 instrument = universe["instrument"]
75 instrument_record = instrument.RecordClass(
76 name="DummyCam",
77 class_name="lsst.obs.base.instrument_tests.DummyCam",
78 detector_max=detector_max,
79 visit_max=visit_max,
80 )
82 skymap = universe["skymap"]
83 skymap_record = skymap.RecordClass(name="test_skymap")
85 band_element = universe["band"]
86 band_record = band_element.RecordClass(name=band)
88 visit = universe["visit"]
89 visit_record = visit.RecordClass(id=visit_id, instrument="test")
91 detector = universe["detector"]
92 detector_record = detector.RecordClass(id=detector_id, instrument="test")
94 physical_filter = universe["physical_filter"]
95 physical_filter_record = physical_filter.RecordClass(name=band, instrument="test", band=band)
97 patch_element = universe["patch"]
98 patch_record = patch_element.RecordClass(
99 skymap="test_skymap", tract=tract, patch=patch,
100 )
102 if "day_obs" in universe:
103 day_obs_element = universe["day_obs"]
104 day_obs_record = day_obs_element.RecordClass(id=20240201, instrument="test")
105 else:
106 day_obs_record = None
108 # A dictionary with all the relevant records.
109 record = {
110 "instrument": instrument_record,
111 "visit": visit_record,
112 "detector": detector_record,
113 "patch": patch_record,
114 "tract": 9813,
115 "band": band_record.name,
116 "skymap": skymap_record.name,
117 "physical_filter": physical_filter_record,
118 }
120 if day_obs_record:
121 record["day_obs"] = day_obs_record
123 # A dictionary with all the relevant recordIds.
124 record_id = record.copy()
125 for key in ("visit", "detector"):
126 record_id[key] = record_id[key].id
128 # TODO: Catching mypy failures on Github Actions should be made easier,
129 # perhaps in DM-36873. Igroring these for now.
130 data_id = DataCoordinate.standardize(record_id, universe=universe)
131 return data_id.expanded(record)
134class MakeWarpTestCase(lsst.utils.tests.TestCase):
135 def setUp(self):
136 np.random.seed(12345)
138 self.config = MakeDirectWarpConfig()
140 meanCalibration = 1e-4
141 calibrationErr = 1e-5
142 self.exposurePhotoCalib = lsst.afw.image.PhotoCalib(meanCalibration, calibrationErr)
143 # An external photoCalib calibration to return
144 self.externalPhotoCalib = lsst.afw.image.PhotoCalib(1e-6, 1e-8)
146 crpix = lsst.geom.Point2D(0, 0)
147 crval = lsst.geom.SpherePoint(0, 45, lsst.geom.degrees)
148 cdMatrix = lsst.afw.geom.makeCdMatrix(scale=1.0*lsst.geom.arcseconds)
149 self.skyWcs = lsst.afw.geom.makeSkyWcs(crpix, crval, cdMatrix)
150 externalCdMatrix = lsst.afw.geom.makeCdMatrix(scale=0.9*lsst.geom.arcseconds)
151 # An external skyWcs to return
152 self.externalSkyWcs = lsst.afw.geom.makeSkyWcs(crpix, crval, externalCdMatrix)
154 self.exposure = lsst.afw.image.ExposureF(10, 10)
155 self.exposure.maskedImage.image.array = np.random.random((10, 10)).astype(np.float32) * 1000
156 self.exposure.maskedImage.variance.array = np.random.random((10, 10)).astype(np.float32)
157 # mask at least one pixel
158 self.exposure.maskedImage.mask[5, 5] = 3
159 # set the PhotoCalib and Wcs objects of this exposure.
160 self.exposure.setPhotoCalib(lsst.afw.image.PhotoCalib(meanCalibration, calibrationErr))
161 self.exposure.setWcs(self.skyWcs)
162 self.exposure.setPsf(GaussianPsf(5, 5, 2.5))
163 self.exposure.setFilter(lsst.afw.image.FilterLabel(physical="fakeFilter", band="fake"))
165 self.visit = 100
166 self.detector = 5
167 detectorName = f"detector {self.detector}"
168 detector = lsst.afw.cameraGeom.testUtils.DetectorWrapper(name=detectorName, id=self.detector).detector
169 self.exposure.setDetector(detector)
171 dataId_dict = {"detector_id": self.detector, "visit_id": 1248, "band": "i"}
172 dataId = generate_data_id(**dataId_dict)
173 self.dataRef = InMemoryDatasetHandle(self.exposure, dataId=dataId)
174 simpleMapConfig = skyMap.discreteSkyMap.DiscreteSkyMapConfig()
175 simpleMapConfig.raList = [crval.getRa().asDegrees()]
176 simpleMapConfig.decList = [crval.getDec().asDegrees()]
177 simpleMapConfig.radiusList = [0.1]
179 self.simpleMap = skyMap.DiscreteSkyMap(simpleMapConfig)
180 self.tractId = 0
181 self.patchId = self.simpleMap[0].findPatch(crval).sequential_index
182 self.skyInfo = makeSkyInfo(self.simpleMap, self.tractId, self.patchId)
184 def test_makeWarp(self):
185 """Test basic MakeWarpTask."""
186 makeWarp = MakeDirectWarpTask(config=self.config)
187 inputs = {"calexp_list": [self.dataRef]}
188 result = makeWarp.run(
189 inputs,
190 sky_info=self.skyInfo,
191 visit_summary=None
192 )
194 warp = result.warp
195 mfrac = result.masked_fraction_warp
196 noise = result.noise_warp0
198 # Ensure we got an exposure out
199 self.assertIsInstance(warp, lsst.afw.image.ExposureF)
200 # Ensure that masked fraction is an ImageF object.
201 self.assertIsInstance(mfrac, lsst.afw.image.ImageF)
202 # Ensure that the noise image is a MaskedImageF object.
203 self.assertIsInstance(noise, lsst.afw.image.MaskedImageF)
204 # Ensure the warp has valid pixels
205 self.assertGreater(np.isfinite(warp.image.array.ravel()).sum(), 0)
206 # Ensure the warp has the correct WCS
207 self.assertEqual(warp.getWcs(), self.skyInfo.wcs)
208 # Ensure that mfrac has pixels between 0 and 1
209 self.assertTrue(np.nanmax(mfrac.array) <= 1)
210 self.assertTrue(np.nanmin(mfrac.array) >= 0)
213def setup_module(module):
214 lsst.utils.tests.init()
217class MatchMemoryTestCase(lsst.utils.tests.MemoryTestCase):
218 pass
221if __name__ == "__main__": 221 ↛ 222line 221 didn't jump to line 222, because the condition on line 221 was never true
222 lsst.utils.tests.init()
223 unittest.main()