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