Coverage for tests / test_sipApproximation.py: 19%

126 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-23 01:26 -0700

1# 

2# Developed for the LSST Data Management System. 

3# This product includes software developed by the LSST Project 

4# (https://www.lsst.org). 

5# See the COPYRIGHT file at the top-level directory of this distribution 

6# for details of code ownership. 

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 GNU General Public License 

19# along with this program. If not, see <https://www.gnu.org/licenses/>. 

20# 

21 

22import os 

23import unittest 

24 

25import astropy.coordinates 

26import astropy.units as u 

27import astropy.wcs 

28import numpy as np 

29 

30import lsst.utils.tests 

31from lsst.daf.base import PropertyList 

32from lsst.geom import Point2D, Point2I, Extent2I, Box2D, Box2I, SpherePoint, arcseconds, degrees 

33from lsst.afw.geom import SipApproximation, makeSkyWcs, makeCdMatrix, SkyWcs 

34 

35 

36class SipApproximationTestCases(lsst.utils.tests.TestCase): 

37 @staticmethod 

38 def make_wcs(md): 

39 return makeSkyWcs(PropertyList.from_mapping(md)) 

40 

41 def compare_to_astropy(self, wcs, bbox, deltaSkyMax, deltaPixelMax): 

42 """Compare a WCS to Astropy's WCS via its FITS representation.""" 

43 x, y = np.meshgrid(np.linspace(bbox.x.min, bbox.x.max, 50), np.linspace(bbox.y.min, bbox.y.max, 50)) 

44 x = x.flatten() 

45 y = y.flatten() 

46 astropy_wcs = astropy.wcs.WCS(wcs.getFitsMetadata(bbox=bbox)) 

47 astropy_coords = astropy_wcs.pixel_to_world(x, y) 

48 afw_ra, afw_dec = wcs.pixelToSkyArray(x, y) 

49 afw_coords = astropy.coordinates.SkyCoord(afw_ra * u.radian, afw_dec * u.radian) 

50 sky_separation = astropy_coords.separation(afw_coords).to(u.arcsec) 

51 self.assertLess(sky_separation.max(), deltaSkyMax) 

52 astropy_x, astropy_y = astropy_wcs.world_to_pixel(afw_coords) 

53 pixel_separation = ((astropy_x - x) ** 2 + (astropy_y - y) ** 2) ** 0.5 

54 self.assertLess(pixel_separation.max(), deltaPixelMax) 

55 

56 def test_pure_tan(self): 

57 """Test 'approximating' a pure TAN WCS that we should be able to 

58 represent exactly with no SIP. 

59 """ 

60 pixelOrigin = Point2D(500.0, 3000.09) 

61 skyOrigin = SpherePoint(60.0, 40.0, degrees) 

62 cd = makeCdMatrix(0.2 * arcseconds, orientation=30 * degrees) 

63 target = makeSkyWcs(pixelOrigin, skyOrigin, cd) 

64 bbox = Box2I(Point2I(0, 0), Extent2I(2048, 4176)) 

65 approx = SipApproximation(target, Box2D(bbox), Extent2I(5, 5), 0, pixelOrigin=pixelOrigin) 

66 self.assertAlmostEqual(approx.getPixelOrigin(), pixelOrigin) 

67 self.assertLess(approx.getSkyOrigin().separation(skyOrigin), 1e-9 * arcseconds) 

68 self.assertFloatsAlmostEqual(approx.getCdMatrix(), cd, rtol=1e-15) 

69 deltaSky, deltaPixel = approx.computeDeltas() 

70 self.assertLess(deltaSky, 1e-9 * arcseconds) 

71 self.assertLess(deltaPixel, 1e-9) 

72 approxWcs = approx.getWcs() 

73 fits = dict(approxWcs.getFitsMetadata(bbox=bbox)) 

74 self.assertFloatsAlmostEqual(fits["CRPIX1"], pixelOrigin.x + 1, rtol=1e-15) 

75 self.assertFloatsAlmostEqual(fits["CRPIX2"], pixelOrigin.y + 1, rtol=1e-15) 

76 self.assertFloatsAlmostEqual(fits["CRVAL1"], skyOrigin.getRa().asDegrees(), rtol=1e-15) 

77 self.assertFloatsAlmostEqual(fits["CRVAL2"], skyOrigin.getDec().asDegrees(), rtol=1e-15) 

78 self.assertFloatsAlmostEqual(fits["CD1_1"], cd[0, 0], rtol=1e-15) 

79 self.assertFloatsAlmostEqual(fits["CD1_2"], cd[0, 1], rtol=1e-15) 

80 self.assertFloatsAlmostEqual(fits["CD2_1"], cd[1, 0], rtol=1e-15) 

81 self.assertFloatsAlmostEqual(fits["CD2_2"], cd[1, 1], rtol=1e-15) 

82 self.assertEqual(fits["CTYPE1"], "RA---TAN") 

83 self.assertEqual(fits["CTYPE2"], "DEC--TAN") 

84 self.compare_to_astropy(approxWcs, bbox, deltaSkyMax=1e-9 * u.arcsec, deltaPixelMax=1e-8) 

85 self.compare_to_astropy( 

86 target.copyWithFitsApproximation(approxWcs), 

87 bbox, 

88 deltaSkyMax=1e-9 * u.arcsec, 

89 deltaPixelMax=1e-8, 

90 ) 

91 

92 def test_linear(self): 

93 """Test 'approximating' a TAN-SIP WCS with only linear terms that we 

94 should be able to represent exactly with no SIP, by nulling the linear 

95 terms. 

96 """ 

97 pixelOrigin = Point2D(500.0, 3000.09) 

98 skyOrigin = SpherePoint(60.0, 40.0, degrees) 

99 cd = makeCdMatrix(0.2 * arcseconds, orientation=30 * degrees) 

100 bbox = Box2I(Point2I(0, 0), Extent2I(2048, 4176)) 

101 target = self.make_wcs( 

102 { 

103 "CD1_1": cd[0, 0], 

104 "CD1_2": cd[0, 1], 

105 "CD2_1": cd[1, 0], 

106 "CD2_2": cd[1, 1], 

107 "CRPIX1": pixelOrigin.x + 1, 

108 "CRPIX2": pixelOrigin.y + 1, 

109 "CRVAL1": skyOrigin.getRa().asDegrees(), 

110 "CRVAL2": skyOrigin.getDec().asDegrees(), 

111 "CTYPE1": "RA---TAN-SIP", 

112 "CTYPE2": "DEC--TAN-SIP", 

113 "CUNIT1": "deg", 

114 "CUNIT2": "deg", 

115 "NAXES1": bbox.width, 

116 "NAXES2": bbox.height, 

117 "NAXIS": 2, 

118 "RADESYS": "ICRS", 

119 "A_ORDER": 1, 

120 "B_ORDER": 1, 

121 "AP_ORDER": 1, 

122 "BP_ORDER": 1, 

123 "A_1_0": 1.0, 

124 "A_0_1": 2.0, 

125 "B_1_0": 2.0, 

126 "B_0_1": 3.0, 

127 "AP_1_0": 0.0, 

128 "AP_0_1": -0.5, 

129 "BP_1_0": -0.5, 

130 "BP_0_1": -0.5, 

131 } 

132 ) 

133 approx = SipApproximation(target, Box2D(bbox), Extent2I(5, 5), 0, pixelOrigin=pixelOrigin) 

134 self.assertAlmostEqual(approx.getPixelOrigin(), pixelOrigin) 

135 self.assertLess(approx.getSkyOrigin().separation(skyOrigin), 1e-9 * arcseconds) 

136 deltaSky, deltaPixel = approx.computeDeltas() 

137 self.assertLess(deltaSky, 1e-9 * arcseconds) 

138 self.assertLess(deltaPixel, 1e-9) 

139 approxWcs = approx.getWcs() 

140 fits = dict(approxWcs.getFitsMetadata(bbox=bbox)) 

141 self.assertFloatsAlmostEqual(fits["CRPIX1"], pixelOrigin.x + 1) 

142 self.assertFloatsAlmostEqual(fits["CRPIX2"], pixelOrigin.y + 1) 

143 self.assertFloatsAlmostEqual(fits["CRVAL1"], skyOrigin.getRa().asDegrees(), rtol=1e-15) 

144 self.assertFloatsAlmostEqual(fits["CRVAL2"], skyOrigin.getDec().asDegrees(), rtol=1e-15) 

145 self.assertEqual(fits["CTYPE1"], "RA---TAN") 

146 self.assertEqual(fits["CTYPE2"], "DEC--TAN") 

147 self.compare_to_astropy(approxWcs, bbox, deltaSkyMax=1e-9 * u.arcsec, deltaPixelMax=1e-8) 

148 self.compare_to_astropy( 

149 target.copyWithFitsApproximation(approxWcs), 

150 bbox, 

151 deltaSkyMax=1e-9 * u.arcsec, 

152 deltaPixelMax=1e-8, 

153 ) 

154 

155 def test_calexp03(self): 

156 """Test on a real WCS, from the calexp of HSC visit=1228 ccd=3, 

157 from run RC/w_2017_50/DM-12929. It has realistic distortion with CRPIX 

158 within the CCD image. 

159 """ 

160 pixelOrigin = Point2D(1096.8935760454308, 2262.9403834197587) 

161 skyOrigin = SpherePoint(149.81129315622917, 1.527518593302043, degrees) 

162 cd = np.array( 

163 [ 

164 [-1.178015203669291e-06, 4.498766772429112e-05], 

165 [ 

166 4.29304691824093e-05, 

167 -1.0762546100726416e-06, 

168 ], 

169 ] 

170 ) 

171 bbox = Box2I(Point2I(0, 0), Extent2I(2048, 4176)) 

172 target = self.make_wcs( 

173 { 

174 "AP_0_0": -0.00042766492723573385, 

175 "AP_0_1": -1.421294634690333e-06, 

176 "AP_0_2": -2.249070237131596e-06, 

177 "AP_0_3": 7.614693711846379e-11, 

178 "AP_0_4": -2.1350939718171946e-15, 

179 "AP_1_0": -2.9070491393671955e-06, 

180 "AP_1_1": -2.600191883647906e-06, 

181 "AP_1_2": 3.209251813253422e-10, 

182 "AP_1_3": -6.377163911922792e-15, 

183 "AP_2_0": -6.917400901963954e-06, 

184 "AP_2_1": 1.441645068817284e-10, 

185 "AP_2_2": -1.4384914067292817e-14, 

186 "AP_3_0": 5.179922357600516e-10, 

187 "AP_3_1": -9.618846794061896e-15, 

188 "AP_4_0": -1.6455748303909694e-14, 

189 "AP_ORDER": 4, 

190 "A_0_2": 2.2496092550091135e-06, 

191 "A_0_3": -5.7226624826215967e-11, 

192 "A_1_1": 2.601332947490435e-06, 

193 "A_1_2": -2.548161981578503e-10, 

194 "A_2_0": 6.918453783853945e-06, 

195 "A_2_1": -7.070288496574992e-11, 

196 "A_3_0": -4.1515075181628575e-10, 

197 "A_ORDER": 3, 

198 "BP_0_0": -0.00027519363188290014, 

199 "BP_0_1": -1.339922915231262e-06, 

200 "BP_0_2": -2.7508000129989704e-06, 

201 "BP_0_3": 1.6166435243727447e-10, 

202 "BP_0_4": -2.6159444529413283e-15, 

203 "BP_1_0": -7.170533032300998e-07, 

204 "BP_1_1": -4.157202213924163e-06, 

205 "BP_1_2": 1.0655925530147004e-10, 

206 "BP_1_3": -5.8777807071581165e-15, 

207 "BP_2_0": -1.4037210918092256e-06, 

208 "BP_2_1": 1.9156184107700897e-10, 

209 "BP_2_2": -5.251709685663605e-15, 

210 "BP_3_0": -7.09409582069615e-11, 

211 "BP_3_1": -5.02267443301453e-15, 

212 "BP_4_0": 5.642051133209865e-16, 

213 "BP_ORDER": 4, 

214 "B_0_2": 2.751296696053813e-06, 

215 "B_0_3": -1.363848403847289e-10, 

216 "B_1_1": 4.157792860966118e-06, 

217 "B_1_2": -5.4037152183616375e-11, 

218 "B_2_0": 1.4039800636228212e-06, 

219 "B_2_1": -1.2897941316430668e-10, 

220 "B_3_0": 9.63138959016586e-11, 

221 "B_ORDER": 3, 

222 "CD1_1": cd[0, 0], 

223 "CD1_2": cd[0, 1], 

224 "CD2_1": cd[1, 0], 

225 "CD2_2": cd[1, 1], 

226 "CRPIX1": pixelOrigin.x + 1, 

227 "CRPIX2": pixelOrigin.y + 1, 

228 "CRVAL1": skyOrigin.getRa().asDegrees(), 

229 "CRVAL2": skyOrigin.getDec().asDegrees(), 

230 "CTYPE1": "RA---TAN-SIP", 

231 "CTYPE2": "DEC--TAN-SIP", 

232 "CUNIT1": "deg", 

233 "CUNIT2": "deg", 

234 "NAXES1": bbox.width, 

235 "NAXES2": bbox.height, 

236 "NAXIS": 2, 

237 "RADESYS": "ICRS", 

238 } 

239 ) 

240 approx = SipApproximation(target, Box2D(bbox), Extent2I(6, 6), 4, pixelOrigin=pixelOrigin) 

241 self.assertAlmostEqual(approx.getPixelOrigin(), pixelOrigin) 

242 self.assertLess(approx.getSkyOrigin().separation(skyOrigin), 1e-9 * arcseconds) 

243 self.assertFloatsAlmostEqual(approx.getCdMatrix(), cd, rtol=1e-7) 

244 deltaSky, deltaPixel = approx.computeDeltas() 

245 self.assertLess(deltaSky, 1e-7 * arcseconds) 

246 self.assertLess(deltaPixel, 1e-6) 

247 approxWcs = approx.getWcs() 

248 fits = dict(approxWcs.getFitsMetadata(bbox=bbox)) 

249 self.assertFloatsAlmostEqual(fits["CRPIX1"], pixelOrigin.x + 1, rtol=1e-8) 

250 self.assertFloatsAlmostEqual(fits["CRPIX2"], pixelOrigin.y + 1, rtol=1e-8) 

251 self.assertFloatsAlmostEqual(fits["CRVAL1"], skyOrigin.getRa().asDegrees(), rtol=1e-8) 

252 self.assertFloatsAlmostEqual(fits["CRVAL2"], skyOrigin.getDec().asDegrees(), rtol=1e-8) 

253 self.assertEqual(fits["CTYPE1"], "RA---TAN-SIP") 

254 self.assertEqual(fits["CTYPE2"], "DEC--TAN-SIP") 

255 self.compare_to_astropy(approxWcs, bbox, deltaSkyMax=1e-7 * u.arcsec, deltaPixelMax=1e-5) 

256 self.compare_to_astropy( 

257 target.copyWithFitsApproximation(approxWcs), 

258 bbox, 

259 deltaSkyMax=1e-6 * u.arcsec, 

260 deltaPixelMax=1e-5, 

261 ) 

262 

263 def test_wcs22(self): 

264 """Test on real WCS, from the [meas_mosaic] wcs of HSC visit=1228 

265 ccd=22 tract=9813, from rerun RC/w_2017_50/DM-12929. This has 

266 realistic distortion with CRPIX near the center of the focal plane (off 

267 the edge of the CCD), which means we cannot represent it exactly with 

268 SipApproximation, since that requires CRPIX within its bbox. 

269 """ 

270 bbox = Box2I(Point2I(0, 0), Extent2I(2048, 4176)) 

271 target = self.make_wcs( 

272 { 

273 "AP_0_1": -1.4877747209973921e-05, 

274 "AP_0_2": 2.595831425638402e-09, 

275 "AP_0_3": -3.538473304544541e-13, 

276 "AP_0_4": -1.7364255070987416e-17, 

277 "AP_0_5": 4.158354613624071e-21, 

278 "AP_0_6": 6.031504872540217e-26, 

279 "AP_0_7": -1.8843528197634618e-29, 

280 "AP_0_8": -4.411702853182809e-35, 

281 "AP_0_9": 2.998016558839638e-38, 

282 "AP_1_0": 2.1597763415259763e-05, 

283 "AP_1_1": -1.7037264968756363e-08, 

284 "AP_1_2": 1.0563437512655601e-10, 

285 "AP_1_3": 5.513447366302908e-17, 

286 "AP_1_4": 4.1396908622107236e-20, 

287 "AP_1_5": -5.300207420437093e-25, 

288 "AP_1_6": 1.1459136839582329e-28, 

289 "AP_1_7": 1.0114481756477905e-33, 

290 "AP_1_8": 5.688355826686257e-38, 

291 "AP_2_0": 2.9292904845913305e-09, 

292 "AP_2_1": -2.31720223718549e-13, 

293 "AP_2_2": -7.483299584011452e-17, 

294 "AP_2_3": -1.0888257447773327e-21, 

295 "AP_2_4": 5.387989056591254e-25, 

296 "AP_2_5": 1.644007231402398e-29, 

297 "AP_2_6": -1.0830432046814581e-33, 

298 "AP_2_7": -3.804272720395786e-38, 

299 "AP_3_0": 1.0448304714804088e-10, 

300 "AP_3_1": 2.6347274534827444e-17, 

301 "AP_3_2": 9.623865277012687e-20, 

302 "AP_3_3": -2.8543130699430308e-25, 

303 "AP_3_4": 3.0929382240412716e-28, 

304 "AP_3_5": 8.14501749342599e-34, 

305 "AP_3_6": 2.2629352809700625e-37, 

306 "AP_4_0": -1.2664081335530406e-17, 

307 "AP_4_1": 8.338516492121341e-22, 

308 "AP_4_2": 4.683815141227516e-25, 

309 "AP_4_3": 3.8297278086295593e-29, 

310 "AP_4_4": -1.0848140289090295e-33, 

311 "AP_4_5": -1.6055236700259204e-37, 

312 "AP_5_0": 5.923796465250516e-20, 

313 "AP_5_1": -3.0109528249623673e-25, 

314 "AP_5_2": 2.07651550777521e-28, 

315 "AP_5_3": -3.3488672921196585e-34, 

316 "AP_5_4": 5.371228109055884e-37, 

317 "AP_6_0": 3.0606077273393017e-26, 

318 "AP_6_1": -7.470520624005137e-30, 

319 "AP_6_2": -7.924054929029662e-34, 

320 "AP_6_3": -8.993856894381261e-38, 

321 "AP_7_0": 2.8965736955513715e-29, 

322 "AP_7_1": 6.805599512576653e-34, 

323 "AP_7_2": 5.5526197352423534e-37, 

324 "AP_8_0": 4.496329614076484e-35, 

325 "AP_8_1": 2.915048166495553e-38, 

326 "AP_9_0": 1.9036813587133663e-37, 

327 "AP_ORDER": 9, 

328 "A_0_2": -1.6811953691767574e-09, 

329 "A_0_3": 1.0433743662634e-12, 

330 "A_0_4": -6.8711691147178074e-18, 

331 "A_0_5": -1.2339761900405834e-20, 

332 "A_0_6": 9.361497711139168e-26, 

333 "A_0_7": 5.447712238518265e-29, 

334 "A_0_8": -2.283455665486541e-34, 

335 "A_0_9": -8.148729256556932e-38, 

336 "A_1_1": 1.3292850389050882e-09, 

337 "A_1_2": -1.0511955221299713e-10, 

338 "A_1_3": 2.0198006554663002e-16, 

339 "A_1_4": -2.2187859071190358e-20, 

340 "A_1_5": -9.096711215990621e-25, 

341 "A_1_6": -1.0779518715344257e-29, 

342 "A_1_7": 1.3704000006676665e-33, 

343 "A_1_8": -7.427824514345201e-38, 

344 "A_2_0": 6.368561442632054e-09, 

345 "A_2_1": -2.4600357643424362e-12, 

346 "A_2_2": -2.435654620248234e-17, 

347 "A_2_3": 3.547267533946869e-20, 

348 "A_2_4": -6.487365679719972e-26, 

349 "A_2_5": -1.521351230094737e-28, 

350 "A_2_6": 2.1227383264900538e-34, 

351 "A_2_7": 2.0108583869008413e-37, 

352 "A_3_0": -1.043925630542753e-10, 

353 "A_3_1": 1.75976184042504e-16, 

354 "A_3_2": -3.2500931028178183e-20, 

355 "A_3_3": -1.921035718735496e-24, 

356 "A_3_4": -1.6197076806807766e-28, 

357 "A_3_5": 4.657442220122837e-33, 

358 "A_3_6": -4.1544398563283404e-38, 

359 "A_4_0": -1.572172681976455e-16, 

360 "A_4_1": 4.101331132363016e-20, 

361 "A_4_2": 6.1547414425568145e-25, 

362 "A_4_3": -3.9664912422773684e-28, 

363 "A_4_4": -9.219688587239831e-34, 

364 "A_4_5": 8.961182174237393e-37, 

365 "A_5_0": -3.1263190379608905e-20, 

366 "A_5_1": -6.744938189499249e-25, 

367 "A_5_2": -1.6066918861635898e-28, 

368 "A_5_3": 4.500410209244365e-33, 

369 "A_5_4": 1.6023740299725829e-37, 

370 "A_6_0": 9.442291591849256e-25, 

371 "A_6_1": -1.9578930866414858e-28, 

372 "A_6_2": -1.9703616513681726e-33, 

373 "A_6_3": 9.254059979828214e-37, 

374 "A_7_0": 2.857311310929313e-29, 

375 "A_7_1": 8.203568899883087e-34, 

376 "A_7_2": 8.581372417066432e-39, 

377 "A_8_0": -1.8039031898052798e-33, 

378 "A_8_1": 2.898481891491671e-37, 

379 "A_9_0": -1.4089135319319912e-37, 

380 "A_ORDER": 9, 

381 "BP_0_1": 1.3269406378579873e-05, 

382 "BP_0_2": -2.4020130376277656e-08, 

383 "BP_0_3": 1.0578604850716356e-10, 

384 "BP_0_4": 1.2705099582590507e-17, 

385 "BP_0_5": 4.374702590256722e-20, 

386 "BP_0_6": -1.1904361273665637e-25, 

387 "BP_0_7": 9.365376813229858e-29, 

388 "BP_0_8": 1.0249348542687937e-35, 

389 "BP_0_9": 9.913174239204098e-38, 

390 "BP_1_0": 5.3154970941211545e-06, 

391 "BP_1_1": 1.338585221404198e-09, 

392 "BP_1_2": -4.403323203838703e-13, 

393 "BP_1_3": -4.927675412191317e-17, 

394 "BP_1_4": 4.2056599337502155e-21, 

395 "BP_1_5": 4.347494937639946e-25, 

396 "BP_1_6": -1.7016369393589545e-29, 

397 "BP_1_7": -9.250712710300761e-34, 

398 "BP_1_8": 2.903862291589102e-38, 

399 "BP_2_0": -8.361037592783e-09, 

400 "BP_2_1": 1.0557933487998814e-10, 

401 "BP_2_2": 6.851578459014938e-17, 

402 "BP_2_3": 9.166056602172931e-20, 

403 "BP_2_4": -5.588794654793661e-25, 

404 "BP_2_5": 2.799146126748001e-28, 

405 "BP_2_6": 4.736465967290488e-34, 

406 "BP_2_7": 3.479972936276621e-37, 

407 "BP_3_0": 1.9579873417948577e-13, 

408 "BP_3_1": -3.4635677527711934e-18, 

409 "BP_3_2": 7.39087279804992e-21, 

410 "BP_3_3": 1.7492745475725066e-25, 

411 "BP_3_4": -4.035333126173646e-29, 

412 "BP_3_5": -1.3361684693427232e-33, 

413 "BP_3_6": 4.955950912353302e-38, 

414 "BP_4_0": 8.209637950392852e-18, 

415 "BP_4_1": 5.1024702870142e-20, 

416 "BP_4_2": -6.8032763060891895e-25, 

417 "BP_4_3": 2.1044072099103315e-28, 

418 "BP_4_4": 1.6036540498846812e-33, 

419 "BP_4_5": 7.0605046394838895e-37, 

420 "BP_5_0": -1.2718164521958228e-21, 

421 "BP_5_1": 3.861294906642736e-26, 

422 "BP_5_2": -3.728708833310905e-29, 

423 "BP_5_3": 7.585835353752152e-34, 

424 "BP_5_4": 1.0442735673821763e-37, 

425 "BP_6_0": 1.315728787073803e-26, 

426 "BP_6_1": 5.121275456285683e-29, 

427 "BP_6_2": 1.3292445159690183e-33, 

428 "BP_6_3": 5.9934345037665075e-37, 

429 "BP_7_0": -2.0388122227546495e-30, 

430 "BP_7_1": -2.75093255434579e-34, 

431 "BP_7_2": 6.416444202667438e-38, 

432 "BP_8_0": -1.4895913066402677e-34, 

433 "BP_8_1": 1.6803705066965438e-37, 

434 "BP_9_0": 1.8813475916412184e-38, 

435 "BP_ORDER": 9, 

436 "B_0_2": 2.42424716719325e-08, 

437 "B_0_3": -1.0625210421541499e-10, 

438 "B_0_4": -3.734011267534742e-17, 

439 "B_0_5": -4.4320952447253e-21, 

440 "B_0_6": 2.136396320364695e-25, 

441 "B_0_7": -1.0261671476558508e-28, 

442 "B_0_8": -2.8687265716879407e-34, 

443 "B_0_9": 7.34451334399625e-38, 

444 "B_1_1": -2.4662102612928633e-09, 

445 "B_1_2": 4.6033704144968226e-14, 

446 "B_1_3": 6.575057893720466e-17, 

447 "B_1_4": 5.132957383456082e-22, 

448 "B_1_5": -4.354806940180001e-25, 

449 "B_1_6": -9.86162124079778e-30, 

450 "B_1_7": 7.692996166964473e-34, 

451 "B_1_8": 2.4662028685683337e-38, 

452 "B_2_0": 9.397728194428527e-09, 

453 "B_2_1": -1.0671833625668622e-10, 

454 "B_2_2": -5.398605316354907e-17, 

455 "B_2_3": -1.862909181494854e-21, 

456 "B_2_4": 4.0889634152600245e-25, 

457 "B_2_5": -3.6402639280175727e-28, 

458 "B_2_6": -6.9963627184091545e-34, 

459 "B_2_7": 4.295158728944756e-37, 

460 "B_3_0": -1.8786163554348966e-13, 

461 "B_3_1": 1.972512581046491e-17, 

462 "B_3_2": 3.6729496252874392e-22, 

463 "B_3_3": -3.3840481271540886e-25, 

464 "B_3_4": -6.797729495720485e-30, 

465 "B_3_5": 1.4493402427155075e-33, 

466 "B_3_6": 3.998788271456866e-38, 

467 "B_4_0": -3.7050392480384804e-17, 

468 "B_4_1": -3.1322715658144286e-22, 

469 "B_4_2": 4.180620258608441e-25, 

470 "B_4_3": -3.4512946689359176e-28, 

471 "B_4_4": -1.0034951748320315e-33, 

472 "B_4_5": 5.8604050242447385e-37, 

473 "B_5_0": -2.236401243933395e-22, 

474 "B_5_1": -9.814956405914982e-26, 

475 "B_5_2": -2.921874946735589e-30, 

476 "B_5_3": -2.8112248331124586e-34, 

477 "B_5_4": 1.1980683642446688e-38, 

478 "B_6_0": 1.6355097123858816e-25, 

479 "B_6_1": -1.2020157950352392e-28, 

480 "B_6_2": -8.155965356039375e-34, 

481 "B_6_3": 3.5708930267652927e-37, 

482 "B_7_0": 1.1594106652283982e-29, 

483 "B_7_1": 3.168975065824031e-34, 

484 "B_7_2": 1.1734898293897363e-39, 

485 "B_8_0": -2.184412963604129e-34, 

486 "B_8_1": 1.019604698867224e-37, 

487 "B_9_0": -3.408083556979094e-38, 

488 "B_ORDER": 9, 

489 "CD1_1": 4.034435112527688e-08, 

490 "CD1_2": -4.688657441390689e-05, 

491 "CD2_1": -4.687791920020537e-05, 

492 "CD2_2": -5.0493192130940185e-08, 

493 "CRPIX1": -5340.870233465987, 

494 "CRPIX2": 17440.391355863132, 

495 "CRVAL1": 150.11251452060122, 

496 "CRVAL2": 2.2004651419030177, 

497 "CTYPE1": "RA---TAN-SIP", 

498 "CTYPE2": "DEC--TAN-SIP", 

499 "CUNIT1": "deg", 

500 "CUNIT2": "deg", 

501 "NAXES1": bbox.width, 

502 "NAXES2": bbox.height, 

503 "NAXIS": 2, 

504 "RADESYS": "ICRS", 

505 } 

506 ) 

507 approx = SipApproximation(target, Box2D(bbox), Extent2I(25, 25), 5) 

508 deltaSky, deltaPixel = approx.computeDeltas() 

509 self.assertLess(deltaSky, 1e-4 * arcseconds) 

510 self.assertLess(deltaPixel, 1e-3) 

511 approxWcs = approx.getWcs() 

512 self.compare_to_astropy(approxWcs, bbox, deltaSkyMax=1e-7 * u.arcsec, deltaPixelMax=1e-5) 

513 self.compare_to_astropy( 

514 target.copyWithFitsApproximation(approxWcs), 

515 bbox, 

516 deltaSkyMax=1e-4 * u.arcsec, 

517 deltaPixelMax=1e-3, 

518 ) 

519 

520 def test_jointcal(self): 

521 """'jointcal' data are from the jointcal solution of HSC visit=30600 

522 ccd=88 tract=16973. This doesn't have a direct TAN-SIP representation. 

523 """ 

524 bbox = Box2I(Point2I(0, 0), Extent2I(2048, 4176)) 

525 target = SkyWcs.readFits( 

526 os.path.join(os.path.abspath(os.path.dirname(__file__)), "data", "jointcal_wcs-0030600-088.fits") 

527 ) 

528 approx = SipApproximation(target, Box2D(bbox), Extent2I(25, 25), 5) 

529 deltaSky, deltaPixel = approx.computeDeltas() 

530 self.assertLess(deltaSky, 1e-4 * arcseconds) 

531 self.assertLess(deltaPixel, 1e-3) 

532 approxWcs = approx.getWcs() 

533 self.compare_to_astropy(approxWcs, bbox, deltaSkyMax=1e-7 * u.arcsec, deltaPixelMax=1e-5) 

534 self.compare_to_astropy( 

535 target.copyWithFitsApproximation(approxWcs), 

536 bbox, 

537 deltaSkyMax=1e-4 * u.arcsec, 

538 deltaPixelMax=1e-3, 

539 ) 

540 

541 

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

543 pass 

544 

545 

546def setup_module(module): 

547 lsst.utils.tests.init() 

548 

549 

550if __name__ == "__main__": 550 ↛ 551line 550 didn't jump to line 551 because the condition on line 550 was never true

551 lsst.utils.tests.init() 

552 unittest.main()