Coverage for tests/test_exposureTable.py: 18%
197 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-08 03:13 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-08 03:13 -0700
1# This file is part of afw.
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"""
23Tests for lsst.afw.table.ExposureTable
25Run with:
26 python test_exposureTable.py
27or
28 pytest test_exposureTable.py
29"""
31import os.path
32import unittest
34import numpy as np
36import lsst.utils.tests
37import lsst.pex.exceptions
38from lsst.daf.base import DateTime, PropertySet, PropertyList
39import lsst.geom
40import lsst.afw.table
41from lsst.afw.coord import Observatory, Weather
42from lsst.geom import arcseconds, degrees, radians, Point2D, Extent2D, Box2D, SpherePoint
43from lsst.afw.geom import Polygon, makeSkyWcs
44import lsst.afw.image
45import lsst.afw.detection
46from lsst.afw.cameraGeom.testUtils import DetectorWrapper
47from testTableArchivesLib import DummyPsf
50class ExposureTableTestCase(lsst.utils.tests.TestCase):
52 @staticmethod
53 def createWcs():
54 metadata = PropertySet()
55 metadata.set("SIMPLE", "T")
56 metadata.set("BITPIX", -32)
57 metadata.set("NAXIS", 2)
58 metadata.set("NAXIS1", 1024)
59 metadata.set("NAXIS2", 1153)
60 metadata.set("RADESYS", 'FK5')
61 metadata.set("EQUINOX", 2000.)
62 metadata.setDouble("CRVAL1", 215.604025685476)
63 metadata.setDouble("CRVAL2", 53.1595451514076)
64 metadata.setDouble("CRPIX1", 1109.99981456774)
65 metadata.setDouble("CRPIX2", 560.018167811613)
66 metadata.set("CTYPE1", 'RA---SIN')
67 metadata.set("CTYPE2", 'DEC--SIN')
68 metadata.setDouble("CD1_1", 5.10808596133527E-05)
69 metadata.setDouble("CD1_2", 1.85579539217196E-07)
70 metadata.setDouble("CD2_2", -5.10281493481982E-05)
71 metadata.setDouble("CD2_1", -8.27440751733828E-07)
72 return makeSkyWcs(metadata)
74 @staticmethod
75 def createVisitInfo():
76 return lsst.afw.image.VisitInfo(
77 10.01,
78 11.02,
79 DateTime(65321.1, DateTime.MJD, DateTime.TAI),
80 12345.1,
81 45.1*degrees,
82 SpherePoint(23.1*degrees, 73.2*degrees),
83 SpherePoint(134.5*degrees, 33.3*degrees),
84 1.73,
85 73.2*degrees,
86 lsst.afw.image.RotType.SKY,
87 Observatory(11.1*degrees, 22.2*degrees, 0.333),
88 Weather(1.1, 2.2, 34.5),
89 "testCam"
90 )
92 @staticmethod
93 def makePolygon():
94 return Polygon([Point2D(1, 2), Point2D(2, 1)])
96 def comparePsfs(self, psf1, psf2):
97 self.assertIsNotNone(psf1)
98 self.assertIsNotNone(psf2)
99 self.assertEqual(psf1, psf2)
101 def setUp(self):
102 np.random.seed(1)
103 schema = lsst.afw.table.ExposureTable.makeMinimalSchema()
104 self.ka = schema.addField("a", type=np.float64, doc="doc for a")
105 self.kb = schema.addField("b", type=np.int64, doc="doc for b")
106 self.cat = lsst.afw.table.ExposureCatalog(schema)
107 self.plist = PropertyList()
108 self.plist['VALUE'] = 1.0
109 self.cat.setMetadata(self.plist)
110 self.wcs = self.createWcs()
111 self.psf = DummyPsf(2.0)
112 self.bbox0 = lsst.geom.Box2I(
113 lsst.geom.Box2D(
114 self.wcs.getPixelOrigin() - lsst.geom.Extent2D(5.0, 4.0),
115 self.wcs.getPixelOrigin() + lsst.geom.Extent2D(20.0, 30.0)
116 )
117 )
118 self.bbox1 = lsst.geom.Box2I(
119 lsst.geom.Box2D(
120 self.wcs.getPixelOrigin() - lsst.geom.Extent2D(15.0, 40.0),
121 self.wcs.getPixelOrigin() + lsst.geom.Extent2D(3.0, 6.0)
122 )
123 )
124 # these numbers are what were persisted as `Calib` objects in the files.
125 self.photoCalib = lsst.afw.image.makePhotoCalibFromCalibZeroPoint(56.0, 2.2)
126 self.visitInfo = self.createVisitInfo()
127 self.detector = DetectorWrapper().detector
128 record0 = self.cat.addNew()
129 record0.setId(1)
130 record0.set(self.ka, np.pi)
131 record0.set(self.kb, 4)
132 record0.setBBox(self.bbox0)
133 record0.setPsf(self.psf)
134 record0.setWcs(self.wcs)
135 record0.setPhotoCalib(self.photoCalib)
136 record0.setVisitInfo(self.visitInfo)
137 record0.setValidPolygon(None)
138 record0.setDetector(None)
139 record1 = self.cat.addNew()
140 record1.setId(2)
141 record1.set(self.ka, 2.5)
142 record1.set(self.kb, 2)
143 record1.setWcs(self.wcs)
144 record1.setBBox(self.bbox1)
145 record1.setValidPolygon(self.makePolygon())
146 record1.setDetector(self.detector)
148 def tearDown(self):
149 del self.cat
150 del self.psf
151 del self.wcs
152 del self.photoCalib
153 del self.visitInfo
154 del self.detector
156 def testAccessors(self):
157 record0 = self.cat[0]
158 record1 = self.cat[1]
159 self.assertEqual(record0.getId(), 1)
160 self.assertEqual(record1.getId(), 2)
161 self.assertEqual(record0.getWcs(), self.wcs)
162 self.assertEqual(record1.getWcs(), self.wcs)
163 self.assertEqual(record0.getBBox(), self.bbox0)
164 self.assertEqual(record1.getBBox(), self.bbox1)
165 self.comparePsfs(record0.getPsf(), self.psf)
166 self.assertIsNone(record1.getPsf())
167 self.assertEqual(record0.getPhotoCalib(), self.photoCalib)
168 self.assertIsNone(record1.getPhotoCalib())
169 self.assertEqual(record0.getVisitInfo(), self.visitInfo)
170 self.assertIsNone(record1.getVisitInfo())
171 self.assertEqual(record0.getValidPolygon(), None)
172 self.assertEqual(record1.getValidPolygon(), self.makePolygon())
173 self.assertIsNone(record0.getDetector())
174 self.assertDetectorsEqual(record1.getDetector(), self.detector)
176 def testPersistence(self):
177 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
178 self.cat.writeFits(tmpFile)
179 cat1 = lsst.afw.table.ExposureCatalog.readFits(tmpFile)
180 self.assertEqual(self.cat[0].get(self.ka), cat1[0].get(self.ka))
181 self.assertEqual(self.cat[0].get(self.kb), cat1[0].get(self.kb))
182 self.comparePsfs(self.cat[0].getPsf(), cat1[0].getPsf())
183 self.assertEqual(self.cat[0].getWcs(), cat1[0].getWcs())
184 self.assertEqual(self.cat[1].get(self.ka), cat1[1].get(self.ka))
185 self.assertEqual(self.cat[1].get(self.kb), cat1[1].get(self.kb))
186 self.assertEqual(self.cat[1].getWcs(), cat1[1].getWcs())
187 self.assertIsNone(self.cat[1].getPsf())
188 self.assertIsNone(self.cat[1].getPhotoCalib())
189 self.assertEqual(self.cat[0].getPhotoCalib(), cat1[0].getPhotoCalib())
190 self.assertEqual(self.cat[0].getVisitInfo(),
191 cat1[0].getVisitInfo())
192 self.assertIsNone(cat1[1].getVisitInfo())
193 self.assertIsNone(cat1[0].getDetector())
194 self.assertDetectorsEqual(cat1[1].getDetector(), self.detector)
195 # We are not checking for plist equality because reading from
196 # fits may add extra keys; for this test we care that the
197 # keys we set are properly round-tripped.
198 for key in self.plist:
199 self.assertEqual(self.plist[key], cat1.getMetadata()[key])
201 def testGeometry(self):
202 bigBox = lsst.geom.Box2D(lsst.geom.Box2I(self.bbox0))
203 bigBox.include(lsst.geom.Box2D(self.bbox1))
204 points = (np.random.rand(100, 2)*np.array([bigBox.getWidth(), bigBox.getHeight()])
205 + np.array([bigBox.getMinX(), bigBox.getMinY()]))
207 # make a very slightly perturbed wcs so the celestial transform isn't a
208 # no-op
209 crval2 = self.wcs.getSkyOrigin()
210 crval2 = lsst.geom.SpherePoint(crval2.getLongitude() + 5*arcseconds,
211 crval2.getLatitude() - 5*arcseconds)
212 wcs2 = makeSkyWcs(
213 crval=crval2,
214 crpix=self.wcs.getPixelOrigin() + lsst.geom.Extent2D(30.0, -50.0),
215 cdMatrix=self.wcs.getCdMatrix()*1.1,
216 )
217 for x1, y1 in points:
218 p1 = lsst.geom.Point2D(x1, y1)
219 c = self.wcs.pixelToSky(p1)
220 p2 = wcs2.skyToPixel(c)
221 subset1 = self.cat.subsetContaining(c)
222 subset2 = self.cat.subsetContaining(p2, wcs2)
223 for record in self.cat:
224 inside = lsst.geom.Box2D(record.getBBox()).contains(p1)
225 self.assertEqual(inside, record.contains(c))
226 self.assertEqual(inside, record.contains(p2, wcs2))
227 self.assertEqual(inside, record.contains(p1, self.wcs))
228 self.assertEqual(inside, record in subset1)
229 self.assertEqual(inside, record in subset2)
231 crazyPoint = lsst.geom.SpherePoint(crval2.getLongitude() + np.pi*radians,
232 crval2.getLatitude())
233 subset3 = self.cat.subsetContaining(crazyPoint)
234 self.assertEqual(len(subset3), 0)
236 def testCoaddInputs(self):
237 coaddInputs = lsst.afw.image.CoaddInputs(
238 lsst.afw.table.ExposureTable.makeMinimalSchema(),
239 lsst.afw.table.ExposureTable.makeMinimalSchema()
240 )
241 coaddInputs.visits.addNew().setId(2)
242 coaddInputs.ccds.addNew().setId(3)
243 coaddInputs.ccds.addNew().setId(4)
244 exposureIn = lsst.afw.image.ExposureF(10, 10)
245 exposureIn.getInfo().setCoaddInputs(coaddInputs)
246 with lsst.utils.tests.getTempFilePath(".fits") as filename:
247 exposureIn.writeFits(filename)
248 exposureOut = lsst.afw.image.ExposureF(filename)
249 coaddInputsOut = exposureOut.getInfo().getCoaddInputs()
250 self.assertEqual(len(coaddInputsOut.visits), 1)
251 self.assertEqual(len(coaddInputsOut.ccds), 2)
252 self.assertEqual(coaddInputsOut.visits[0].getId(), 2)
253 self.assertEqual(coaddInputsOut.ccds[0].getId(), 3)
254 self.assertEqual(coaddInputsOut.ccds[1].getId(), 4)
256 def testReadV1Catalog(self):
257 testDir = os.path.dirname(__file__)
258 v1CatalogPath = os.path.join(
259 testDir, "data", "exposure_catalog_v1.fits")
260 catV1 = lsst.afw.table.ExposureCatalog.readFits(v1CatalogPath)
261 self.assertEqual(self.cat[0].get(self.ka), catV1[0].get(self.ka))
262 self.assertEqual(self.cat[0].get(self.kb), catV1[0].get(self.kb))
263 self.comparePsfs(self.cat[0].getPsf(), catV1[0].getPsf())
264 bbox = Box2D(Point2D(0, 0), Extent2D(2000, 2000))
265 self.assertWcsAlmostEqualOverBBox(self.cat[0].getWcs(), catV1[0].getWcs(), bbox)
266 self.assertEqual(self.cat[1].get(self.ka), catV1[1].get(self.ka))
267 self.assertEqual(self.cat[1].get(self.kb), catV1[1].get(self.kb))
268 self.assertEqual(self.cat[1].getWcs(), catV1[1].getWcs())
269 self.assertIsNone(self.cat[1].getPsf())
270 self.assertIsNone(self.cat[1].getPhotoCalib())
271 self.assertEqual(self.cat[0].getPhotoCalib(), catV1[0].getPhotoCalib())
272 self.assertIsNone(catV1[0].getVisitInfo())
273 self.assertIsNone(catV1[1].getVisitInfo())
275 def testBoolArraySubset(self):
276 i = np.array([True, False], dtype=bool)
277 subset = self.cat[i]
278 self.assertEqual(len(subset), 1)
279 self.assertEqual(subset[0], self.cat[0])
282class MemoryTester(lsst.utils.tests.MemoryTestCase):
283 pass
286def setup_module(module):
287 lsst.utils.tests.init()
290if __name__ == "__main__": 290 ↛ 291line 290 didn't jump to line 291, because the condition on line 290 was never true
291 lsst.utils.tests.init()
292 unittest.main()