Coverage for tests/test_hips.py: 24%
100 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-30 03:34 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-30 03:34 -0700
1# This file is part of pipe_tasks.
2#
3# LSST Data Management System
4# This product includes software developed by the
5# LSST Project (http://www.lsst.org/).
6# See COPYRIGHT file at the top of the source tree.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <https://www.lsstcorp.org/LegalNotices/>.
21#
22"""Test HIPS code."""
23import unittest
24import numpy as np
25import hpgeom as hpg
27import lsst.utils.tests
28import lsst.daf.butler
29import lsst.afw.image
30import lsst.skymap
31import lsst.geom
33from lsst.pipe.tasks.hips import (
34 HighResolutionHipsTask,
35 HighResolutionHipsConfig,
36 HighResolutionHipsConnections
37)
40class MockCoaddImageHandle(lsst.daf.butler.DeferredDatasetHandle):
41 """Simple object that looks like a Gen3 deferred dataset handle
42 to an exposure.
44 Parameters
45 ----------
46 exposure : `lsst.afw.image.ExposureF`
47 Exposure to hold.
48 """
49 def __init__(self, exposure):
50 self.exposure = exposure
52 def get(self, **kwargs):
53 """Retrieve the dataset using the API of the Gen3 Butler.
55 Returns
56 -------
57 exposure : `lsst.afw.image.ExposureF`
58 Exposure held in mock handle.
59 """
60 return self.exposure
62 @property
63 def dataId(self):
64 return {'visit': 0, 'detector': 0}
67class HipsTestCase(unittest.TestCase):
68 def test_hips_single(self):
69 """Test creating a single HIPS image."""
70 np.random.seed(12345)
72 config = HighResolutionHipsConfig()
74 skymap = self._make_skymap()
76 tract = 9597
77 patch = 50
78 tract_info = skymap[tract]
79 patch_info = tract_info[patch]
81 exposure = self._make_noise_exposure(patch_info)
82 handles = [MockCoaddImageHandle(exposure)]
84 center = patch_info.wcs.pixelToSky(patch_info.inner_bbox.getCenter())
85 pixel = self._get_pixel(2**config.hips_order, center)
87 hips_task = HighResolutionHipsTask(config=config)
88 output = hips_task.run([pixel], handles)
90 # Check that all the pixels are filled.
91 npix = (np.isfinite(output.hips_exposures[pixel].image.array.ravel()).sum())
92 self.assertEqual(npix, output.hips_exposures[pixel].image.array.size)
94 # Check that metadata is correct
95 self.assertEqual(output.hips_exposures[pixel].getPhotoCalib(), exposure.getPhotoCalib())
96 self.assertEqual(output.hips_exposures[pixel].getFilter(), exposure.getFilter())
98 def test_hips_double(self):
99 """Test creating a HIPS image from two neighboring patches."""
100 np.random.seed(12345)
102 config = HighResolutionHipsConfig()
104 skymap = self._make_skymap()
106 tract = 9597
107 patches = [50, 51]
108 tract_info = skymap[tract]
110 handles = []
111 centers = []
112 for patch in patches:
113 patch_info = tract_info[patch]
114 exposure = self._make_noise_exposure(patch_info)
115 handles.append(MockCoaddImageHandle(exposure))
116 centers.append(patch_info.wcs.pixelToSky(patch_info.inner_bbox.getCenter()))
118 center = lsst.geom.SpherePoint(
119 (centers[0].getRa().asDegrees() + centers[1].getRa().asDegrees())/2.*lsst.geom.degrees,
120 (centers[0].getDec().asDegrees() + centers[1].getDec().asDegrees())/2.*lsst.geom.degrees
121 )
122 pixel = self._get_pixel(2**config.hips_order, center)
124 # Just transform one, make sure it falls off the edge.
125 hips_task = HighResolutionHipsTask(config=config)
126 output = hips_task.run([pixel], [handles[0]])
128 # Check that not all the pixels are filled.
129 npix = (np.isfinite(output.hips_exposures[pixel].image.array.ravel()).sum())
130 self.assertLess(npix, output.hips_exposures[pixel].image.array.size)
132 # Transform both.
133 hips_task = HighResolutionHipsTask(config=config)
134 output = hips_task.run([pixel], handles)
136 # Check that all the pixels are filled.
137 npix = (np.isfinite(output.hips_exposures[pixel].image.array.ravel()).sum())
138 self.assertEqual(npix, output.hips_exposures[pixel].image.array.size)
140 def test_hips_none(self):
141 """Test making a HIPS image with no overlapping inputs."""
142 np.random.seed(12345)
144 config = HighResolutionHipsConfig()
146 skymap = self._make_skymap()
148 tract = 9597
149 patch = 50
150 tract_info = skymap[tract]
151 patch_info = tract_info[patch]
153 exposure = self._make_noise_exposure(patch_info)
154 handles = [MockCoaddImageHandle(exposure)]
156 pixel = 0
158 hips_task = HighResolutionHipsTask(config=config)
159 output = hips_task.run([pixel], handles)
161 # Check that there is no returned image
162 self.assertEqual(len(output.hips_exposures), 0)
164 def test_hips_connections(self):
165 """Test that the HIPS connections validate properly."""
166 config = HighResolutionHipsConfig()
168 # Test that the connections validate
169 _ = HighResolutionHipsConnections(config=config)
171 # Test that changing hips_order will break things because of the
172 # dimensions mismatch.
173 config.hips_order = 5
174 with self.assertRaises(ValueError):
175 _ = HighResolutionHipsConnections(config=config)
177 # I'd like to change the dimensions but I don't know how to do that.
179 def _make_noise_exposure(self, patch_info):
180 """Make a simple noise exposure.
182 Parameters
183 ----------
184 patch_info : `lsst.skymap.PatchInfo`
185 Patch info to use to make the exposure.
187 Returns
188 -------
189 exposure : `lsst.afw.image.ExposureF`
190 Noise exposure.
191 """
192 exposure = lsst.afw.image.ExposureF(patch_info.outer_bbox)
193 exposure.image.array[:, :] = np.random.normal(scale=1.0, size=exposure.image.array.shape)
194 exposure.setWcs(patch_info.wcs)
195 exposure.setPhotoCalib(lsst.afw.image.PhotoCalib(calibrationMean=1.0))
196 exposure.setFilter(lsst.afw.image.FilterLabel(band='i'))
198 return exposure
200 def _make_skymap(self):
201 """Make a testing skymap.
203 Returns
204 -------
205 skymap : `lsst.skymap.RingsSkyMap`
206 """
208 # Generate a skymap
209 skymap_config = lsst.skymap.ringsSkyMap.RingsSkyMapConfig()
210 skymap_config.numRings = 120
211 skymap_config.projection = "TAN"
212 skymap_config.tractOverlap = 1.0/60
213 skymap_config.pixelScale = 0.168
214 return lsst.skymap.ringsSkyMap.RingsSkyMap(skymap_config)
216 def _get_pixel(self, nside, sphpoint):
217 """Get the pixel value from a spherepoint.
219 Parameters
220 ----------
221 nside : `int`
222 Healpix nside
223 sphpoint : `lsst.geom.SpherePoint`
224 Point to compute pixel value.
226 Returns
227 -------
228 pixel : `int`
229 Healpix pixel (nest ordering)
230 """
231 pixel = hpg.angle_to_pixel(
232 nside,
233 sphpoint.getRa().asDegrees(),
234 sphpoint.getDec().asDegrees(),
235 )
236 return pixel
239if __name__ == "__main__": 239 ↛ 240line 239 didn't jump to line 240, because the condition on line 239 was never true
240 unittest.main()