Coverage for tests/test_exposureTable.py: 18%
197 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-05 17:50 -0800
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-05 17:50 -0800
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 10313423,
78 10.01,
79 11.02,
80 DateTime(65321.1, DateTime.MJD, DateTime.TAI),
81 12345.1,
82 45.1*degrees,
83 SpherePoint(23.1*degrees, 73.2*degrees),
84 SpherePoint(134.5*degrees, 33.3*degrees),
85 1.73,
86 73.2*degrees,
87 lsst.afw.image.RotType.SKY,
88 Observatory(11.1*degrees, 22.2*degrees, 0.333),
89 Weather(1.1, 2.2, 34.5),
90 "testCam"
91 )
93 @staticmethod
94 def makePolygon():
95 return Polygon([Point2D(1, 2), Point2D(2, 1)])
97 def comparePsfs(self, psf1, psf2):
98 self.assertIsNotNone(psf1)
99 self.assertIsNotNone(psf2)
100 self.assertEqual(psf1, psf2)
102 def setUp(self):
103 np.random.seed(1)
104 schema = lsst.afw.table.ExposureTable.makeMinimalSchema()
105 self.ka = schema.addField("a", type=np.float64, doc="doc for a")
106 self.kb = schema.addField("b", type=np.int64, doc="doc for b")
107 self.cat = lsst.afw.table.ExposureCatalog(schema)
108 self.plist = PropertyList()
109 self.plist['VALUE'] = 1.0
110 self.cat.setMetadata(self.plist)
111 self.wcs = self.createWcs()
112 self.psf = DummyPsf(2.0)
113 self.bbox0 = lsst.geom.Box2I(
114 lsst.geom.Box2D(
115 self.wcs.getPixelOrigin() - lsst.geom.Extent2D(5.0, 4.0),
116 self.wcs.getPixelOrigin() + lsst.geom.Extent2D(20.0, 30.0)
117 )
118 )
119 self.bbox1 = lsst.geom.Box2I(
120 lsst.geom.Box2D(
121 self.wcs.getPixelOrigin() - lsst.geom.Extent2D(15.0, 40.0),
122 self.wcs.getPixelOrigin() + lsst.geom.Extent2D(3.0, 6.0)
123 )
124 )
125 # these numbers are what were persisted as `Calib` objects in the files.
126 self.photoCalib = lsst.afw.image.makePhotoCalibFromCalibZeroPoint(56.0, 2.2)
127 self.visitInfo = self.createVisitInfo()
128 self.detector = DetectorWrapper().detector
129 record0 = self.cat.addNew()
130 record0.setId(1)
131 record0.set(self.ka, np.pi)
132 record0.set(self.kb, 4)
133 record0.setBBox(self.bbox0)
134 record0.setPsf(self.psf)
135 record0.setWcs(self.wcs)
136 record0.setPhotoCalib(self.photoCalib)
137 record0.setVisitInfo(self.visitInfo)
138 record0.setValidPolygon(None)
139 record0.setDetector(None)
140 record1 = self.cat.addNew()
141 record1.setId(2)
142 record1.set(self.ka, 2.5)
143 record1.set(self.kb, 2)
144 record1.setWcs(self.wcs)
145 record1.setBBox(self.bbox1)
146 record1.setValidPolygon(self.makePolygon())
147 record1.setDetector(self.detector)
149 def tearDown(self):
150 del self.cat
151 del self.psf
152 del self.wcs
153 del self.photoCalib
154 del self.visitInfo
155 del self.detector
157 def testAccessors(self):
158 record0 = self.cat[0]
159 record1 = self.cat[1]
160 self.assertEqual(record0.getId(), 1)
161 self.assertEqual(record1.getId(), 2)
162 self.assertEqual(record0.getWcs(), self.wcs)
163 self.assertEqual(record1.getWcs(), self.wcs)
164 self.assertEqual(record0.getBBox(), self.bbox0)
165 self.assertEqual(record1.getBBox(), self.bbox1)
166 self.comparePsfs(record0.getPsf(), self.psf)
167 self.assertIsNone(record1.getPsf())
168 self.assertEqual(record0.getPhotoCalib(), self.photoCalib)
169 self.assertIsNone(record1.getPhotoCalib())
170 self.assertEqual(record0.getVisitInfo(), self.visitInfo)
171 self.assertIsNone(record1.getVisitInfo())
172 self.assertEqual(record0.getValidPolygon(), None)
173 self.assertEqual(record1.getValidPolygon(), self.makePolygon())
174 self.assertIsNone(record0.getDetector())
175 self.assertDetectorsEqual(record1.getDetector(), self.detector)
177 def testPersistence(self):
178 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
179 self.cat.writeFits(tmpFile)
180 cat1 = lsst.afw.table.ExposureCatalog.readFits(tmpFile)
181 self.assertEqual(self.cat[0].get(self.ka), cat1[0].get(self.ka))
182 self.assertEqual(self.cat[0].get(self.kb), cat1[0].get(self.kb))
183 self.comparePsfs(self.cat[0].getPsf(), cat1[0].getPsf())
184 self.assertEqual(self.cat[0].getWcs(), cat1[0].getWcs())
185 self.assertEqual(self.cat[1].get(self.ka), cat1[1].get(self.ka))
186 self.assertEqual(self.cat[1].get(self.kb), cat1[1].get(self.kb))
187 self.assertEqual(self.cat[1].getWcs(), cat1[1].getWcs())
188 self.assertIsNone(self.cat[1].getPsf())
189 self.assertIsNone(self.cat[1].getPhotoCalib())
190 self.assertEqual(self.cat[0].getPhotoCalib(), cat1[0].getPhotoCalib())
191 self.assertEqual(self.cat[0].getVisitInfo(),
192 cat1[0].getVisitInfo())
193 self.assertIsNone(cat1[1].getVisitInfo())
194 self.assertIsNone(cat1[0].getDetector())
195 self.assertDetectorsEqual(cat1[1].getDetector(), self.detector)
196 # We are not checking for plist equality because reading from
197 # fits may add extra keys; for this test we care that the
198 # keys we set are properly round-tripped.
199 for key in self.plist:
200 self.assertEqual(self.plist[key], cat1.getMetadata()[key])
202 def testGeometry(self):
203 bigBox = lsst.geom.Box2D(lsst.geom.Box2I(self.bbox0))
204 bigBox.include(lsst.geom.Box2D(self.bbox1))
205 points = (np.random.rand(100, 2)*np.array([bigBox.getWidth(), bigBox.getHeight()])
206 + np.array([bigBox.getMinX(), bigBox.getMinY()]))
208 # make a very slightly perturbed wcs so the celestial transform isn't a
209 # no-op
210 crval2 = self.wcs.getSkyOrigin()
211 crval2 = lsst.geom.SpherePoint(crval2.getLongitude() + 5*arcseconds,
212 crval2.getLatitude() - 5*arcseconds)
213 wcs2 = makeSkyWcs(
214 crval=crval2,
215 crpix=self.wcs.getPixelOrigin() + lsst.geom.Extent2D(30.0, -50.0),
216 cdMatrix=self.wcs.getCdMatrix()*1.1,
217 )
218 for x1, y1 in points:
219 p1 = lsst.geom.Point2D(x1, y1)
220 c = self.wcs.pixelToSky(p1)
221 p2 = wcs2.skyToPixel(c)
222 subset1 = self.cat.subsetContaining(c)
223 subset2 = self.cat.subsetContaining(p2, wcs2)
224 for record in self.cat:
225 inside = lsst.geom.Box2D(record.getBBox()).contains(p1)
226 self.assertEqual(inside, record.contains(c))
227 self.assertEqual(inside, record.contains(p2, wcs2))
228 self.assertEqual(inside, record.contains(p1, self.wcs))
229 self.assertEqual(inside, record in subset1)
230 self.assertEqual(inside, record in subset2)
232 crazyPoint = lsst.geom.SpherePoint(crval2.getLongitude() + np.pi*radians,
233 crval2.getLatitude())
234 subset3 = self.cat.subsetContaining(crazyPoint)
235 self.assertEqual(len(subset3), 0)
237 def testCoaddInputs(self):
238 coaddInputs = lsst.afw.image.CoaddInputs(
239 lsst.afw.table.ExposureTable.makeMinimalSchema(),
240 lsst.afw.table.ExposureTable.makeMinimalSchema()
241 )
242 coaddInputs.visits.addNew().setId(2)
243 coaddInputs.ccds.addNew().setId(3)
244 coaddInputs.ccds.addNew().setId(4)
245 exposureIn = lsst.afw.image.ExposureF(10, 10)
246 exposureIn.getInfo().setCoaddInputs(coaddInputs)
247 with lsst.utils.tests.getTempFilePath(".fits") as filename:
248 exposureIn.writeFits(filename)
249 exposureOut = lsst.afw.image.ExposureF(filename)
250 coaddInputsOut = exposureOut.getInfo().getCoaddInputs()
251 self.assertEqual(len(coaddInputsOut.visits), 1)
252 self.assertEqual(len(coaddInputsOut.ccds), 2)
253 self.assertEqual(coaddInputsOut.visits[0].getId(), 2)
254 self.assertEqual(coaddInputsOut.ccds[0].getId(), 3)
255 self.assertEqual(coaddInputsOut.ccds[1].getId(), 4)
257 def testReadV1Catalog(self):
258 testDir = os.path.dirname(__file__)
259 v1CatalogPath = os.path.join(
260 testDir, "data", "exposure_catalog_v1.fits")
261 catV1 = lsst.afw.table.ExposureCatalog.readFits(v1CatalogPath)
262 self.assertEqual(self.cat[0].get(self.ka), catV1[0].get(self.ka))
263 self.assertEqual(self.cat[0].get(self.kb), catV1[0].get(self.kb))
264 self.comparePsfs(self.cat[0].getPsf(), catV1[0].getPsf())
265 bbox = Box2D(Point2D(0, 0), Extent2D(2000, 2000))
266 self.assertWcsAlmostEqualOverBBox(self.cat[0].getWcs(), catV1[0].getWcs(), bbox)
267 self.assertEqual(self.cat[1].get(self.ka), catV1[1].get(self.ka))
268 self.assertEqual(self.cat[1].get(self.kb), catV1[1].get(self.kb))
269 self.assertEqual(self.cat[1].getWcs(), catV1[1].getWcs())
270 self.assertIsNone(self.cat[1].getPsf())
271 self.assertIsNone(self.cat[1].getPhotoCalib())
272 self.assertEqual(self.cat[0].getPhotoCalib(), catV1[0].getPhotoCalib())
273 self.assertIsNone(catV1[0].getVisitInfo())
274 self.assertIsNone(catV1[1].getVisitInfo())
276 def testBoolArraySubset(self):
277 i = np.array([True, False], dtype=bool)
278 subset = self.cat[i]
279 self.assertEqual(len(subset), 1)
280 self.assertEqual(subset[0], self.cat[0])
283class MemoryTester(lsst.utils.tests.MemoryTestCase):
284 pass
287def setup_module(module):
288 lsst.utils.tests.init()
291if __name__ == "__main__": 291 ↛ 292line 291 didn't jump to line 292, because the condition on line 291 was never true
292 lsst.utils.tests.init()
293 unittest.main()