Coverage for tests/test_exposureTable.py: 20%

197 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-24 02:38 -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/>. 

21 

22""" 

23Tests for lsst.afw.table.ExposureTable 

24 

25Run with: 

26 python test_exposureTable.py 

27or 

28 pytest test_exposureTable.py 

29""" 

30 

31import os.path 

32import unittest 

33 

34import numpy as np 

35 

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 

48 

49 

50class ExposureTableTestCase(lsst.utils.tests.TestCase): 

51 

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) 

73 

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 ) 

92 

93 @staticmethod 

94 def makePolygon(): 

95 return Polygon([Point2D(1, 2), Point2D(2, 1)]) 

96 

97 def comparePsfs(self, psf1, psf2): 

98 self.assertIsNotNone(psf1) 

99 self.assertIsNotNone(psf2) 

100 self.assertEqual(psf1, psf2) 

101 

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) 

148 

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 

156 

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) 

176 

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]) 

201 

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()])) 

207 

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) 

231 

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) 

236 

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) 

256 

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()) 

275 

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]) 

281 

282 

283class MemoryTester(lsst.utils.tests.MemoryTestCase): 

284 pass 

285 

286 

287def setup_module(module): 

288 lsst.utils.tests.init() 

289 

290 

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()