Coverage for tests / test_sipApproximation.py: 19%
126 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 16:53 -0700
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 16:53 -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#
22import os
23import unittest
25import astropy.coordinates
26import astropy.units as u
27import astropy.wcs
28import numpy as np
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
36class SipApproximationTestCases(lsst.utils.tests.TestCase):
37 @staticmethod
38 def make_wcs(md):
39 return makeSkyWcs(PropertyList.from_mapping(md))
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)
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 )
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 )
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 )
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 )
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 )
542class MemoryTester(lsst.utils.tests.MemoryTestCase):
543 pass
546def setup_module(module):
547 lsst.utils.tests.init()
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()