Coverage for tests/test_makeSurveyPropertyMaps.py: 19%
127 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-16 01:25 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-16 01:25 -0800
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 HealSparsePropertyMapTask.
23"""
24import unittest
25import numpy as np
26import healsparse as hsp
27import esutil
28import warnings
30import lsst.utils.tests
31import lsst.daf.butler
32import lsst.afw.table as afwTable
33import lsst.afw.geom as afwGeom
34import lsst.afw.image as afwImage
35from lsst.skymap.discreteSkyMap import DiscreteSkyMap
36import lsst.geom as geom
38from lsst.pipe.tasks.healSparseMapping import HealSparsePropertyMapTask
39from lsst.pipe.tasks.healSparseMappingProperties import (register_property_map,
40 BasePropertyMap)
42from surveyPropertyMapsTestUtils import (makeMockVisitSummary,
43 MockVisitSummaryReference,
44 MockCoaddReference,
45 MockInputMapReference)
48# Test creation of an arbitrary new property map by registering it here
49# and using it in the test class.
50@register_property_map("dist_times_psfarea")
51class DistTimesPsfAreaPropertyMap(BasePropertyMap):
52 """Property map to compute the distance from the boresight center
53 by the psf area. Do not try this at home."""
54 requires_psf = True
56 def _compute(self, row, ra, dec, scalings, psf_array=None):
57 boresight = row.getVisitInfo().getBoresightRaDec()
58 dist = esutil.coords.sphdist(ra, dec,
59 boresight.getRa().asDegrees(), boresight.getDec().asDegrees())
60 return np.deg2rad(dist)*psf_array['psf_area']
63class HealSparsePropertyMapTaskTestCase(lsst.utils.tests.TestCase):
64 """Test of HealSparsePropertyMapTask.
66 These tests bypass the middleware used for accessing data and
67 managing Task execution.
68 """
69 def setUp(self):
70 tract = 0
71 band = 'r'
72 patch = 0
73 visits = [100, 101]
74 # Good to test crossing 0.
75 ra_center = 0.0
76 dec_center = -45.0
77 pixel_scale = 0.2
78 coadd_zp = 27.0
80 # Generate a mock skymap with one patch
81 config = DiscreteSkyMap.ConfigClass()
82 config.raList = [ra_center]
83 config.decList = [dec_center]
84 config.radiusList = [150*pixel_scale/3600.]
85 config.patchInnerDimensions = (350, 350)
86 config.patchBorder = 50
87 config.tractOverlap = 0.0
88 config.pixelScale = pixel_scale
89 sky_map = DiscreteSkyMap(config)
91 visit_summaries = [makeMockVisitSummary(visit,
92 ra_center=ra_center,
93 dec_center=dec_center)
94 for visit in visits]
95 visit_summary_refs = [MockVisitSummaryReference(visit_summary, visit)
96 for visit_summary, visit in zip(visit_summaries, visits)]
97 self.visit_summary_dict = {visit: ref.get()
98 for ref, visit in zip(visit_summary_refs, visits)}
100 # Generate an input map. Note that this does not need to be consistent
101 # with the visit_summary projections, we're just tracking values.
102 with warnings.catch_warnings():
103 # Healsparse will emit a warning if nside coverage is greater than
104 # 128. In the case of generating patch input maps, and not global
105 # maps, high nside coverage works fine, so we can suppress this
106 # warning.
107 warnings.simplefilter("ignore")
108 input_map = hsp.HealSparseMap.make_empty(nside_coverage=256,
109 nside_sparse=32768,
110 dtype=hsp.WIDE_MASK,
111 wide_mask_maxbits=len(visits)*2)
113 patch_poly = afwGeom.Polygon(geom.Box2D(sky_map[tract][patch].getOuterBBox()))
114 sph_pts = sky_map[tract].getWcs().pixelToSky(patch_poly.convexHull().getVertices())
115 patch_poly_radec = np.array([(sph.getRa().asDegrees(), sph.getDec().asDegrees())
116 for sph in sph_pts])
117 poly = hsp.Polygon(ra=patch_poly_radec[: -1, 0],
118 dec=patch_poly_radec[: -1, 1],
119 value=[0])
120 poly_pixels = poly.get_pixels(nside=input_map.nside_sparse)
121 # The input map has full coverage for bits 0 and 1
122 input_map.set_bits_pix(poly_pixels, [0])
123 input_map.set_bits_pix(poly_pixels, [1])
125 input_map_ref = MockInputMapReference(input_map, patch=patch, tract=tract)
126 self.input_map_dict = {patch: input_map_ref}
128 coadd = afwImage.ExposureF(sky_map[tract][patch].getOuterBBox(),
129 sky_map[tract].getWcs())
130 instFluxMag0 = 10.**(coadd_zp/2.5)
131 pc = afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0)
132 coadd.setPhotoCalib(pc)
134 # Mock the coadd input ccd table
135 schema = afwTable.ExposureTable.makeMinimalSchema()
136 schema.addField("ccd", type="I")
137 schema.addField("visit", type="I")
138 schema.addField("weight", type="F")
139 ccds = afwTable.ExposureCatalog(schema)
140 ccds.resize(2)
141 ccds['id'] = np.arange(2)
142 ccds['visit'][0] = visits[0]
143 ccds['visit'][1] = visits[1]
144 ccds['ccd'][0] = 0
145 ccds['ccd'][1] = 1
146 ccds['weight'] = 10.0
147 for ccd_row in ccds:
148 summary = self.visit_summary_dict[ccd_row['visit']].find(ccd_row['ccd'])
149 ccd_row.setWcs(summary.getWcs())
150 ccd_row.setPsf(summary.getPsf())
151 ccd_row.setBBox(summary.getBBox())
152 ccd_row.setPhotoCalib(summary.getPhotoCalib())
154 inputs = afwImage.CoaddInputs()
155 inputs.ccds = ccds
156 coadd.getInfo().setCoaddInputs(inputs)
158 coadd_ref = MockCoaddReference(coadd, patch=patch, tract=tract)
159 self.coadd_dict = {patch: coadd_ref}
161 self.tract = tract
162 self.band = band
163 self.sky_map = sky_map
164 self.input_map = input_map
166 def testPropertyMapCreation(self):
167 """Test creation of property maps."""
168 config = HealSparsePropertyMapTask.ConfigClass()
170 # Add our new test map to the set of maps
171 config.property_maps.names |= ['dist_times_psfarea']
172 config.property_maps['dist_times_psfarea'].do_min = True
173 config.property_maps['dist_times_psfarea'].do_max = True
174 config.property_maps['dist_times_psfarea'].do_mean = True
176 property_task = HealSparsePropertyMapTask(config=config)
178 property_task.run(self.sky_map,
179 self.tract,
180 self.band,
181 self.coadd_dict,
182 self.input_map_dict,
183 self.visit_summary_dict)
185 valid_pixels = self.input_map.valid_pixels
187 # Verify each map exists and has the correct pixels set.
188 for name, map_config, PropertyMapClass in config.property_maps.apply():
189 self.assertTrue(name in property_task.property_maps)
190 property_map = property_task.property_maps[name]
191 if map_config.do_min:
192 self.assertTrue(hasattr(property_map, 'min_map'))
193 np.testing.assert_array_equal(property_map.min_map.valid_pixels, valid_pixels)
194 else:
195 self.assertFalse(hasattr(property_map, 'min_map'))
196 if map_config.do_max:
197 self.assertTrue(hasattr(property_map, 'max_map'))
198 np.testing.assert_array_equal(property_map.max_map.valid_pixels, valid_pixels)
199 else:
200 self.assertFalse(hasattr(property_map, 'max_map'))
201 if map_config.do_mean:
202 self.assertTrue(hasattr(property_map, 'mean_map'))
203 np.testing.assert_array_equal(property_map.mean_map.valid_pixels, valid_pixels)
204 else:
205 self.assertFalse(hasattr(property_map, 'mean_map'))
206 if map_config.do_weighted_mean:
207 self.assertTrue(hasattr(property_map, 'weighted_mean_map'))
208 np.testing.assert_array_equal(property_map.weighted_mean_map.valid_pixels, valid_pixels)
209 else:
210 self.assertFalse(hasattr(property_map, 'weighted_mean_map'))
211 if map_config.do_sum:
212 self.assertTrue(hasattr(property_map, 'sum_map'))
213 np.testing.assert_array_equal(property_map.sum_map.valid_pixels, valid_pixels)
214 else:
215 self.assertFalse(hasattr(property_map, 'sum_map'))
218class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
219 pass
222def setup_module(module):
223 lsst.utils.tests.init()
226if __name__ == "__main__": 226 ↛ 227line 226 didn't jump to line 227, because the condition on line 226 was never true
227 lsst.utils.tests.init()
228 unittest.main()