Coverage for tests/test_fitsChan.py : 4%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import os.path
2import unittest
3import numpy as np
5import astshim as ast
6from astshim.test import ObjectTestCase
9def pad(card):
10 """Pad a string withs paces to length 80 characters"""
11 return "%-80s" % (card,)
14def writeFitsWcs(frameSet, extraOptions=None):
15 """Write a FrameSet as FITS-WCS
17 extraOptions are in addition to Encoding=Fits-WCS, CDMatrix=1
18 """
19 options = "Encoding=FITS-WCS, CDMatrix=1"
20 if extraOptions is not None:
21 options = "%s, %s" % (options, extraOptions)
22 fc = ast.FitsChan(ast.StringStream(), options)
23 fc.write(frameSet)
24 return fc
27class TestFitsChan(ObjectTestCase):
29 def setUp(self):
30 self.dataDir = os.path.join(os.path.dirname(__file__), "data")
31 shortCards = (
32 "NAXIS1 = 200",
33 "NAXIS2 = 200",
34 "CTYPE1 = 'RA--TAN '",
35 "CTYPE2 = 'DEC-TAN '",
36 "CRPIX1 = 100",
37 "CRPIX2 = 100",
38 "CDELT1 = 0.001",
39 "CDELT2 = 0.001",
40 "CRVAL1 = 0",
41 "CRVAL2 = 0",
42 "BOOL = F",
43 "UNDEF =",
44 "BOOL = T / Repeat",
45 "COMMENT one of two comments",
46 "COMMENT another of two comments",
47 "HISTORY one of two history fields",
48 "HISTORY second of three history fields",
49 "HISTORY third of three history fields",
50 )
51 self.cards = [pad(card) for card in shortCards]
53 def insertPixelMapping(self, mapping, frameSet):
54 """Make a new WCS by inserting a new mapping at the beginnning of the
55 GRID-IWC mapping
57 Return the new FrameSet (the original is not altered).
58 """
59 frameSet = frameSet.copy()
61 skyFrame = frameSet.getFrame(ast.FrameSet.CURRENT) # use this copy for the new sky frame
62 self.assertIsInstance(skyFrame, ast.SkyFrame)
63 oldSkyIndex = frameSet.current
65 if not frameSet.findFrame(ast.Frame(2, "Domain=GRID")):
66 raise KeyError("No GRID frame")
67 gridIndex = frameSet.current
69 if not frameSet.findFrame(ast.Frame(2, "Domain=IWC")):
70 raise KeyError("No IWC frame")
71 oldIwcIndex = frameSet.current
72 iwcFrame = frameSet.getFrame(oldIwcIndex) # use this copy for the new IWC frame
74 oldGridToIwc = frameSet.getMapping(gridIndex, oldIwcIndex)
75 iwcToSky = frameSet.getMapping(oldIwcIndex, oldSkyIndex)
77 # Remove frames in order high to low, so removal doesn't alter the
78 # indices remaining to be removed;
79 # update gridIndex during removal so it still points to the GRID frame
80 framesToRemove = reversed(sorted([oldIwcIndex, oldSkyIndex]))
81 for index in framesToRemove:
82 if (index < gridIndex):
83 gridIndex -= 1
84 frameSet.removeFrame(index)
86 newGridToIwc = mapping.then(oldGridToIwc).simplified()
87 frameSet.addFrame(gridIndex, newGridToIwc, iwcFrame)
88 frameSet.addFrame(ast.FrameSet.CURRENT, iwcToSky, skyFrame)
89 return frameSet
91 def test_FitsChanAttributes(self):
92 """Test getting and setting FitsChan attributes
94 Does not test the behavior of the attributes.
95 """
96 ss = ast.StringStream("".join(self.cards))
97 fc = ast.FitsChan(ss)
98 self.assertFalse(fc.carLin)
99 self.assertFalse(fc.cdMatrix)
100 self.assertFalse(fc.clean)
101 self.assertFalse(fc.defB1950)
102 self.assertEqual(fc.encoding, "FITS-WCS")
103 self.assertEqual(fc.fitsAxisOrder, "<auto>")
104 self.assertAlmostEqual(fc.fitsTol, 0.1)
105 self.assertFalse(fc.iwc)
106 self.assertTrue(fc.sipOK)
107 self.assertTrue(fc.sipReplace)
108 self.assertEqual(fc.tabOK, 0)
109 self.assertEqual(fc.polyTan, -1)
110 warningSet = set(fc.warnings.split(" "))
111 desiredWarningSet = set("BadKeyName BadKeyValue Tnx Zpx BadCel BadMat BadPV BadCTYPE".split(" "))
112 self.assertEqual(warningSet, desiredWarningSet)
114 fc.carLin = True
115 self.assertTrue(fc.carLin)
116 fc.cdMatrix = True
117 self.assertTrue(fc.cdMatrix)
118 fc.clean = True
119 self.assertTrue(fc.clean)
120 fc.defB1950 = True
121 self.assertTrue(fc.defB1950)
122 fc.encoding = "NATIVE"
123 self.assertEqual(fc.encoding, "NATIVE")
124 fc.fitsAxisOrder = "<copy>"
125 self.assertEqual(fc.fitsAxisOrder, "<copy>")
126 fc.fitsTol = 0.001
127 self.assertAlmostEqual(fc.fitsTol, 0.001)
128 fc.iwc = True
129 self.assertTrue(fc.iwc)
130 fc.tabOK = 1
131 self.assertEqual(fc.tabOK, 1)
132 fc.polyTan = 0
133 self.assertEqual(fc.polyTan, 0)
134 fc.warnings = "BadKeyName BadMat"
135 self.assertEqual(fc.warnings, "BadKeyName BadMat")
137 def test_FitsChanPreloaded(self):
138 """Test a FitsChan that starts out loaded with data
139 """
140 ss = ast.StringStream("".join(self.cards))
141 fc = ast.FitsChan(ss)
142 self.assertEqual(fc.nCard, len(self.cards))
143 # there are 2 COMMENT and 3 HISTORY cards,
144 # and two BOOL cards so 4 fewer unique keys
145 self.assertEqual(fc.nKey, len(self.cards) - 4)
146 self.assertEqual(fc.className, "FitsChan")
147 fv = fc.getFitsF("CRVAL1")
148 self.assertTrue(fv.found)
149 self.assertEqual(fv.value, 0.0)
151 self.assertEqual(fc.encoding, "FITS-WCS")
153 self.assertEqual(fc.getAllCardNames(),
154 [card.split(" ", 1)[0] for card in self.cards])
156 def test_FitsChanFileStream(self):
157 """Test a FitsChan with a FileStream/
159 In particular, make sure that cards are written as the channel is
160 destroyed.
161 """
162 path = os.path.join(self.dataDir, "test_fitsChanFileStream.fits")
163 fc1 = ast.FitsChan(ast.FileStream(path, True))
164 fc1.putCards("".join(self.cards))
165 # delete the channel, which writes cards,
166 # and then deletes the file stream, closing the file
167 del fc1
169 fc2 = ast.FitsChan(ast.FileStream(path, False))
170 self.assertEqual(fc2.nCard, len(self.cards))
171 del fc2
172 os.remove(path)
174 def test_FitsChanWriteOnDelete(self):
175 """Test that a FitsChan writes cards when it is deleted
176 """
177 ss = ast.StringStream()
178 fc = ast.FitsChan(ss)
179 fc.putCards("".join(self.cards))
180 self.assertEqual(ss.getSinkData(), "")
181 del fc
182 self.assertEqual(len(ss.getSinkData()), 80 * len(self.cards))
184 def test_FitsChanGetFitsSetFits(self):
185 """Test FitsChan.getFits<X>, FitsChan.setFits<X> and getCardType
186 """
187 fc = ast.FitsChan(ast.StringStream())
188 self.assertEqual(fc.className, "FitsChan")
190 # add a card for each type
191 complexVal = complex(9.8, -5.15)
192 continueVal = "This is a continue card"
193 floatVal = 1.5
194 intVal = 99
195 logicalVal = True
196 strVal = "This is a string"
197 fc.setFitsCF("ACOMPLEX", complexVal, "Comment for ACOMPLEX")
198 commentVal = "This is a comment"
199 fc.setFitsCN("ACONT", continueVal, "Comment for ACONT")
200 fc.setFitsF("AFLOAT", floatVal, "Comment for AFLOAT")
201 fc.setFitsI("ANINT", intVal, "Comment for ANINT")
202 fc.setFitsL("ALOGICAL", logicalVal, "Comment for ALOGICAL")
203 fc.setFitsS("ASTRING", strVal, "Comment for ASTRING")
204 fc.setFitsU("UNDEFVAL", "Comment for UNDEFVAL")
205 fc.setFitsCM(commentVal)
207 self.assertEqual(fc.nCard, 8)
208 self.assertEqual(fc.getAllCardNames(),
209 ["ACOMPLEX", "ACONT", "AFLOAT", "ANINT",
210 "ALOGICAL", "ASTRING", "UNDEFVAL", " "])
212 fv = fc.getFitsI("ANINT")
213 self.assertEqual(fc.getCardType(), ast.CardType.INT)
214 self.assertTrue(fv.found)
215 self.assertEqual(fv.value, intVal)
216 self.assertEqual(fc.getCardComm(), "Comment for ANINT")
217 self.assertEqual(fc.getCard(), 4)
219 fv = fc.getFitsS("ANINT")
220 self.assertTrue(fv.found)
221 self.assertEqual(fv.value, str(intVal))
222 self.assertEqual(fc.getCard(), 4)
224 fv = fc.getFitsI() # read the current card
225 self.assertTrue(fv.found)
226 self.assertEqual(fv.value, intVal)
227 self.assertEqual(fc.getCard(), 4)
229 fv = fc.getFitsI("") # alternate way to read the current card
230 self.assertTrue(fv.found)
231 self.assertEqual(fv.value, intVal)
232 self.assertEqual(fc.getCard(), 4)
234 fv = fc.getFitsF("AFLOAT")
235 self.assertEqual(fc.getCardType(), ast.CardType.FLOAT)
236 self.assertEqual(fc.getCard(), 3)
237 self.assertTrue(fv.found)
238 self.assertAlmostEqual(fv.value, floatVal)
239 self.assertEqual(fc.getCardComm(), "Comment for AFLOAT")
241 fv = fc.getFitsF() # read the current card
242 self.assertEqual(fc.getCardType(), ast.CardType.FLOAT)
243 self.assertEqual(fc.getCard(), 3)
244 self.assertTrue(fv.found)
245 self.assertAlmostEqual(fv.value, floatVal)
246 self.assertEqual(fc.getCardComm(), "Comment for AFLOAT")
248 fv = fc.getFitsCN("ACONT")
249 self.assertEqual(fc.getCardType(), ast.CardType.CONTINUE)
250 self.assertEqual(fc.getCard(), 2)
251 self.assertTrue(fv.found)
252 self.assertAlmostEqual(fv.value, continueVal)
253 self.assertEqual(fc.getCardComm(), "Comment for ACONT")
255 fv = fc.getFitsCN() # read the current card
256 self.assertEqual(fc.getCardType(), ast.CardType.CONTINUE)
257 self.assertEqual(fc.getCard(), 2)
258 self.assertTrue(fv.found)
259 self.assertAlmostEqual(fv.value, continueVal)
260 self.assertEqual(fc.getCardComm(), "Comment for ACONT")
262 fv = fc.getFitsCF("ACOMPLEX")
263 self.assertEqual(fc.getCardType(), ast.CardType.COMPLEXF)
264 self.assertEqual(fc.getCard(), 1)
265 self.assertTrue(fv.found)
266 self.assertAlmostEqual(fv.value, complexVal)
267 self.assertEqual(fc.getCardComm(), "Comment for ACOMPLEX")
269 fv = fc.getFitsCF() # read the current card
270 self.assertEqual(fc.getCardType(), ast.CardType.COMPLEXF)
271 self.assertEqual(fc.getCard(), 1)
272 self.assertTrue(fv.found)
273 self.assertAlmostEqual(fv.value, complexVal)
274 self.assertEqual(fc.getCardComm(), "Comment for ACOMPLEX")
276 fv = fc.getFitsL("ALOGICAL")
277 self.assertEqual(fc.getCardType(), ast.CardType.LOGICAL)
278 self.assertEqual(fc.getCard(), 5)
279 self.assertTrue(fv.found)
280 self.assertAlmostEqual(fv.value, logicalVal)
281 self.assertEqual(fc.getCardComm(), "Comment for ALOGICAL")
283 fv = fc.getFitsL() # read the current card
284 self.assertEqual(fc.getCardType(), ast.CardType.LOGICAL)
285 self.assertEqual(fc.getCard(), 5)
286 self.assertTrue(fv.found)
287 self.assertAlmostEqual(fv.value, logicalVal)
288 self.assertEqual(fc.getCardComm(), "Comment for ALOGICAL")
290 fv = fc.getFitsS("ASTRING")
291 self.assertEqual(fc.getCardType(), ast.CardType.STRING)
292 self.assertEqual(fc.getCard(), 6)
293 self.assertTrue(fv.found)
294 self.assertAlmostEqual(fv.value, strVal)
295 self.assertEqual(fc.getCardComm(), "Comment for ASTRING")
297 fv = fc.getFitsS() # read the current card
298 self.assertEqual(fc.getCardType(), ast.CardType.STRING)
299 self.assertEqual(fc.getCard(), 6)
300 self.assertTrue(fv.found)
301 self.assertAlmostEqual(fv.value, strVal)
302 self.assertEqual(fc.getCardComm(), "Comment for ASTRING")
304 fv = fc.getFitsS("BADNAME") # a card that does not exist
305 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
306 self.assertEqual(fc.getCard(), fc.nCard + 1)
307 self.assertFalse(fv.found)
309 fc.setCard(7)
310 self.assertEqual(fc.getCardType(), ast.CardType.UNDEF)
311 with self.assertRaises(RuntimeError):
312 fc.getFitsS()
313 self.assertEqual(fc.getCardComm(), "Comment for UNDEFVAL")
315 fc.setCard(8)
316 self.assertEqual(fc.getCardType(), ast.CardType.COMMENT)
317 with self.assertRaises(RuntimeError):
318 fc.getFitsS()
319 self.assertEqual(fc.getCardComm(), commentVal)
321 # replace ANINT card with new everything: name, value type and comment
322 fc.setCard(4)
323 fc.setFitsCF("NEWNAME", complex(99.9, 99.8), "New comment", overwrite=True)
324 self.assertEqual(fc.getAllCardNames(),
325 ["ACOMPLEX", "ACONT", "AFLOAT", "NEWNAME",
326 "ALOGICAL", "ASTRING", "UNDEFVAL", " "])
327 fc.setCard(1) # force a search
328 fv = fc.getFitsCF("NEWNAME")
329 self.assertTrue(fv.found)
330 self.assertEqual(fv.value.real, 99.9)
331 self.assertEqual(fv.value.imag, 99.8)
332 self.assertEqual(fc.getCardComm(), "New comment")
333 self.assertEqual(fc.getCard(), 4)
335 def test_FitsChanGetCurrentForNonexistentCard(self):
336 """Test getting info on the current card when it does not exist
337 """
338 fc = ast.FitsChan(ast.StringStream())
339 fc.setFitsI("ANINT", 200)
340 fc.setFitsS("ASTRING", "string value")
341 fc.setCard(fc.nCard + 1)
342 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
343 self.assertEqual(fc.testFits(), ast.FitsKeyState.ABSENT)
344 with self.assertRaises(RuntimeError):
345 fc.getFitsCN()
346 with self.assertRaises(RuntimeError):
347 fc.getFitsF()
348 with self.assertRaises(RuntimeError):
349 fc.getFitsI()
350 with self.assertRaises(RuntimeError):
351 fc.getFitsL()
352 with self.assertRaises(RuntimeError):
353 fc.getFitsS()
354 with self.assertRaises(RuntimeError):
355 fc.getFitsCF()
356 self.assertEqual(fc.getCardName(), "")
357 self.assertEqual(fc.getCardComm(), "")
359 def test_FitsChanGetFitsMissing(self):
360 """Test FitsChan.getFits<X> for missing cards, with and without
361 defaults
362 """
363 fc = ast.FitsChan(ast.StringStream())
364 fc.setFitsI("ANINT", 200)
365 fc.setFitsS("ASTRING", "string value")
367 self.assertEqual(fc.nCard, 2)
369 # test getFitsX for missing cards with default values
370 fv = fc.getFitsCF("BOGUS", complex(9, -5))
371 self.assertFalse(fv.found)
372 self.assertEqual(fv.value, complex(9, -5))
373 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
374 self.assertEqual(fc.getCard(), fc.nCard + 1)
376 fv = fc.getFitsCN("BOGUS", "not_there")
377 self.assertFalse(fv.found)
378 self.assertEqual(fv.value, "not_there")
379 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
380 self.assertEqual(fc.getCard(), fc.nCard + 1)
382 fv = fc.getFitsF("BOGUS", 55.5)
383 self.assertFalse(fv.found)
384 self.assertEqual(fv.value, 55.5)
385 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
386 self.assertEqual(fc.getCard(), fc.nCard + 1)
388 fv = fc.getFitsI("BOGUS", 55)
389 self.assertFalse(fv.found)
390 self.assertEqual(fv.value, 55)
391 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
392 self.assertEqual(fc.getCard(), fc.nCard + 1)
394 fv = fc.getFitsL("BOGUS", True)
395 self.assertFalse(fv.found)
396 self.assertEqual(fv.value, True)
397 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
398 self.assertEqual(fc.getCard(), fc.nCard + 1)
400 fv = fc.getFitsS("BOGUS", "missing")
401 self.assertFalse(fv.found)
402 self.assertEqual(fv.value, "missing")
403 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
404 self.assertEqual(fc.getCard(), fc.nCard + 1)
406 # test getFitsX for missing cards without default values
407 fv = fc.getFitsCF("BOGUS")
408 self.assertFalse(fv.found)
409 self.assertEqual(fv.value, complex())
410 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
411 self.assertEqual(fc.getCard(), fc.nCard + 1)
413 fv = fc.getFitsCN("BOGUS")
414 self.assertFalse(fv.found)
415 self.assertEqual(fv.value, "")
416 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
417 self.assertEqual(fc.getCard(), fc.nCard + 1)
419 fv = fc.getFitsF("BOGUS")
420 self.assertFalse(fv.found)
421 self.assertEqual(fv.value, 0)
422 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
423 self.assertEqual(fc.getCard(), fc.nCard + 1)
425 fv = fc.getFitsI("BOGUS")
426 self.assertFalse(fv.found)
427 self.assertEqual(fv.value, 0)
428 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
429 self.assertEqual(fc.getCard(), fc.nCard + 1)
431 fv = fc.getFitsL("BOGUS")
432 self.assertFalse(fv.found)
433 self.assertEqual(fv.value, False)
434 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
435 self.assertEqual(fc.getCard(), fc.nCard + 1)
437 fv = fc.getFitsS("BOGUS")
438 self.assertFalse(fv.found)
439 self.assertEqual(fv.value, "")
440 self.assertEqual(fc.getCardType(), ast.CardType.NOTYPE)
441 self.assertEqual(fc.getCard(), fc.nCard + 1)
443 fv = fc.findFits("BOGUS", inc=False)
444 self.assertFalse(fv.found)
445 self.assertEqual(fv.value, "")
447 def test_FitsChanEmptyFits(self):
448 ss = ast.StringStream("".join(self.cards))
449 fc = ast.FitsChan(ss)
450 self.assertEqual(fc.nCard, len(self.cards))
451 fc.emptyFits()
452 self.assertEqual(fc.nCard, 0)
454 def test_FitsChanPutCardsPutFits(self):
455 ss = ast.StringStream()
456 fc = ast.FitsChan(ss)
457 cards = "CRVAL1 = 0 " + \
458 "CRVAL2 = 0 "
459 fc.putCards(cards)
460 self.assertEqual(fc.getCard(), 1)
461 fc.setCard(100) # past the end = end of cards
462 self.assertEqual(fc.getCard(), 3)
463 fc.clearCard()
464 self.assertEqual(fc.getCard(), 1)
465 self.assertEqual(fc.getAllCardNames(), ["CRVAL1", "CRVAL2"])
467 # insert new cards at the beginning
468 for card in self.cards[0:8]:
469 fc.putFits(card, overwrite=False)
470 self.assertEqual(fc.nCard, 10)
471 self.assertEqual(fc.getCard(), 9)
472 predCardNames = [c.split()[0] for c in self.cards[0:8]] + ["CRVAL1", "CRVAL2"]
473 self.assertEqual(fc.getAllCardNames(), predCardNames)
475 def test_FitsChanFindFits(self):
476 ss = ast.StringStream("".join(self.cards))
477 fc = ast.FitsChan(ss)
478 expectedNCards = fc.nCard
480 # append a card with no value
481 fc.setCard(fc.nCard + 1)
482 fc.setFitsU("UNDEFVAL")
483 expectedNCards += 1
484 self.assertEqual(fc.nCard, expectedNCards)
486 fc.setCard(9) # index of CRVAL1
487 self.assertEqual(fc.getCardName(), "CRVAL1")
488 fv = fc.findFits("%f", inc=False)
489 self.assertTrue(fv.found)
490 self.assertEqual(fv.value, pad("CRVAL1 = 0"))
492 # delete CRVAL1 card
493 fc.delFits()
494 expectedNCards -= 1
495 self.assertEqual(fc.nCard, expectedNCards)
496 self.assertEqual(fc.getCard(), 9)
497 fv = fc.findFits("%f", inc=False)
498 self.assertEqual(fc.getCard(), 9)
499 self.assertTrue(fv.found)
500 self.assertEqual(fv.value, pad("CRVAL2 = 0"))
502 # insert CRVAL1 card before current card; verify that the index
503 # is incremented to point to the next card
504 fc.putFits("CRVAL1 = 99", overwrite=False)
505 expectedNCards += 1
506 self.assertEqual(fc.nCard, expectedNCards)
507 self.assertEqual(fc.getCard(), 10)
508 fv = fc.findFits("%f", inc=False)
509 self.assertTrue(fv.found)
510 self.assertEqual(fv.value, pad("CRVAL2 = 0"))
512 fc.setCard(9) # index of CRVAL1
513 fv = fc.findFits("%f", inc=False)
514 self.assertTrue(fv.found)
515 self.assertEqual(fv.value, pad("CRVAL1 = 99"))
517 # overwrite CRVAL1 card
518 fc.setCard(9)
519 fc.putFits("CRVAL1 = 0", overwrite=True)
520 self.assertEqual(fc.nCard, expectedNCards)
521 fc.setCard(9)
522 fv = fc.findFits("%f", inc=False)
523 self.assertTrue(fv.found)
524 self.assertEqual(fv.value, pad("CRVAL1 = 0"))
526 # test that findFits does not wrap around
527 fv = fc.findFits("CTYPE2", inc=False)
528 self.assertFalse(fv.found)
529 fc.clearCard()
530 fv = fc.findFits("CTYPE2", inc=False)
531 self.assertTrue(fv.found)
532 self.assertEqual(fv.value, pad("CTYPE2 = 'DEC-TAN '"))
533 self.assertEqual(fc.getCard(), 4)
535 # test that we can find a card with undefined value
536 fc.clearCard()
537 fv = fc.findFits("UNDEFVAL", inc=False)
538 self.assertTrue(fv.found)
539 self.assertEqual(fv.value,
540 "UNDEFVAL= ")
542 def test_FitsChanReadWrite(self):
543 ss = ast.StringStream("".join(self.cards))
544 fc1 = ast.FitsChan(ss)
545 obj1 = fc1.read()
546 self.assertEqual(obj1.className, "FrameSet")
548 ss2 = ast.StringStream()
549 fc2 = ast.FitsChan(ss2, "Encoding=FITS-WCS")
550 n = fc2.write(obj1)
551 self.assertEqual(n, 1)
552 self.assertEqual(fc2.nCard, 10)
553 fc2.clearCard()
555 fv = fc2.findFits("%f", inc=True)
556 self.assertTrue(fv.found)
557 self.assertEqual(fv.value, pad("WCSAXES = 2 / Number of WCS axes"))
559 fv = fc2.findFits("%f", inc=True)
560 self.assertTrue(fv.found)
561 self.assertEqual(fv.value, pad("CRPIX1 = 100.0 / Reference pixel on axis 1"))
563 fv = fc2.findFits("%f", inc=True)
564 self.assertTrue(fv.found)
565 self.assertEqual(fv.value, pad("CRPIX2 = 100.0 / Reference pixel on axis 2"))
567 fv = fc2.findFits("%f", inc=True)
568 self.assertTrue(fv.found)
569 self.assertEqual(fv.value, pad("CRVAL1 = 0.0 / Value at ref. pixel on axis 1"))
571 fv = fc2.findFits("%f", inc=True)
572 self.assertTrue(fv.found)
573 self.assertEqual(fv.value, pad("CRVAL2 = 0.0 / Value at ref. pixel on axis 2"))
575 fv = fc2.findFits("%f", inc=True)
576 self.assertTrue(fv.found)
577 self.assertEqual(fv.value, pad("CTYPE1 = 'RA---TAN' / Type of co-ordinate on axis 1"))
579 fv = fc2.findFits("%f", inc=True)
580 self.assertTrue(fv.found)
581 self.assertEqual(fv.value, pad("CTYPE2 = 'DEC--TAN' / Type of co-ordinate on axis 2"))
583 fv = fc2.findFits("%f", inc=True)
584 self.assertTrue(fv.found)
585 self.assertEqual(fv.value, pad("CDELT1 = 0.001 / Pixel size on axis 1"))
587 fv = fc2.findFits("%f", inc=True)
588 self.assertTrue(fv.found)
589 self.assertEqual(fv.value, pad("CDELT2 = 0.001 / Pixel size on axis 2"))
591 fv = fc2.findFits("%f", inc=True)
592 self.assertTrue(fv.found)
593 self.assertEqual(fv.value, pad("RADESYS = 'ICRS ' / Reference frame for RA/DEC values"))
595 self.assertEqual(ss2.getSinkData(), "")
596 self.assertEqual(fc2.nCard, 10)
597 fc2.writeFits()
598 self.assertEqual(fc2.nCard, 0)
599 a = ss2.getSinkData()
601 ss3 = ast.StringStream(ss2.getSinkData())
602 fc3 = ast.FitsChan(ss3, "Encoding=FITS-WCS")
603 fc3.readFits()
604 obj3 = fc3.read()
606 ss4 = ast.StringStream()
607 fc4 = ast.FitsChan(ss4, "Encoding=FITS-WCS")
608 n = fc4.write(obj3)
609 self.assertEqual(n, 1)
610 del fc4
611 b = ss4.getSinkData()
612 self.assertEqual(a, b)
614 def test_FitsChanTestFits(self):
615 fc = ast.FitsChan(ast.StringStream())
616 self.assertEqual(fc.className, "FitsChan")
618 # add a card for each type
619 fc.setFitsF("AFLOAT", 1.5)
620 fc.setFitsS("ASTRING", "a string")
621 fc.setFitsU("UNDEFVAL")
623 self.assertEqual(fc.testFits("AFLOAT"), ast.FitsKeyState.PRESENT)
624 self.assertEqual(fc.testFits("ASTRING"), ast.FitsKeyState.PRESENT)
625 self.assertEqual(fc.testFits("UNDEFVAL"), ast.FitsKeyState.NOVALUE)
626 self.assertEqual(fc.testFits("BADNAME"), ast.FitsKeyState.ABSENT)
628 fc.setCard(1)
629 self.assertEqual(fc.getCardName(), "AFLOAT")
630 self.assertEqual(fc.testFits(), ast.FitsKeyState.PRESENT)
631 fc.setCard(3)
632 self.assertEqual(fc.getCardName(), "UNDEFVAL")
633 self.assertEqual(fc.testFits(), ast.FitsKeyState.NOVALUE)
635 def test_FitsChanInsertShift(self):
636 """Check that a simple WCS can still be written as FITS-WCS
637 after inserting a shift at the beginning of GRID to IWC
639 This tests LSST ticket DM-12524
640 """
641 ss = ast.StringStream("".join(self.cards))
642 fc = ast.FitsChan(ss, "Encoding=FITS-WCS, IWC=1")
643 frameSet = fc.read()
644 self.assertIsInstance(frameSet, ast.FrameSet)
645 self.assertAlmostEqual(fc.fitsTol, 0.1)
647 shift = 30
648 shiftMap = ast.ShiftMap([shift, shift])
649 shiftedFrameSet = self.insertPixelMapping(shiftMap, frameSet)
651 fc2 = writeFitsWcs(frameSet)
652 self.assertGreater(fc2.nCard, 9)
653 for i in (1, 2):
654 fv = fc2.getFitsF("CRPIX%d" % (i,))
655 self.assertAlmostEqual(fv.value, 100)
657 fc3 = writeFitsWcs(shiftedFrameSet)
658 self.assertGreaterEqual(fc3.nCard, fc2.nCard)
659 for i in (1, 2):
660 fv = fc3.getFitsF("CRPIX%d" % (i,))
661 self.assertAlmostEqual(fv.value, 100 - shift)
662 for name in fc2.getAllCardNames():
663 self.assertEqual(fc3.testFits(name), ast.FitsKeyState.PRESENT)
665 def test_FitsChanFitsTol(self):
666 """Test that increasing FitsTol allows writing a WCS with distortion
667 as FITS-WCS.
668 """
669 ss = ast.StringStream("".join(self.cards))
670 fc = ast.FitsChan(ss, "Encoding=FITS-WCS, IWC=1")
671 frameSet = fc.read()
673 distortion = ast.PcdMap(0.001, [0.0, 0.0])
674 distortedFrameSet = self.insertPixelMapping(distortion, frameSet)
676 # Writing as FTIS-WCS should fail with the default FitsTol
677 fc = writeFitsWcs(distortedFrameSet)
678 self.assertEqual(fc.nCard, 0)
680 # Writing as FITS-WCS should succeed with adequate FitsTol
681 fc2 = writeFitsWcs(distortedFrameSet, "FitsTol=1000")
682 self.assertGreater(fc2.nCard, 9)
683 for i in (1, 2):
684 fv = fc2.getFitsF("CRVAL%d" % (i,))
685 self.assertAlmostEqual(fv.value, 0)
686 fv2 = fc2.getFitsS("CTYPE1")
687 self.assertEqual(fv2.value, "RA---TAN")
688 fv3 = fc2.getFitsS("CTYPE2")
689 self.assertEqual(fv3.value, "DEC--TAN")
691 def test_FitsChanDM13686(self):
692 """Test that a particular FrameSet will not segfault when
693 we attempt to write it to a FitsChan as FITS-WCS
694 """
695 def readObjectFromShow(path):
696 """Read an ast object saved as Object.show()"""
697 with open(path, "r") as f:
698 objectText = f.read()
699 stream = ast.StringStream(objectText)
700 chan = ast.Channel(stream)
701 return chan.read()
703 path = os.path.join(self.dataDir, "frameSetDM13686.txt")
704 frameSet = readObjectFromShow(path)
705 strStream = ast.StringStream()
706 fitsChan = ast.FitsChan(strStream, "Encoding=FITS-WCS")
707 # This FrameSet can be represtented as FITS-WCS, so 1 object is written
708 self.assertEqual(fitsChan.write(frameSet), 1)
710 def test_FitsChanTAB(self):
711 """Test that FITS -TAB WCS can be created.
712 """
714 wavelength = np.array([0., 0.5, 1.5, 3., 5.])
716 # Create a FrameSet using a LutMap with non-linear coordinates
717 pixelFrame = ast.Frame(1, "Domain=PIXELS")
718 wavelengthFrame = ast.SpecFrame("System=wave, unit=nm")
719 lutMap = ast.LutMap(wavelength, 1, 1)
720 frameSet = ast.FrameDict(pixelFrame)
721 frameSet.addFrame("PIXELS", lutMap, wavelengthFrame)
723 # Now serialize it using -TAB WCS
724 fc = writeFitsWcs(frameSet, "TabOk=1")
726 fv = fc.getFitsS("CTYPE1")
727 self.assertEqual(fv.value, "WAVE-TAB")
729 # PS1_0 is the table extension name
730 fv = fc.getFitsS("PS1_0")
731 waveext = fv.value
732 self.assertEqual(waveext, "WCS-TAB")
734 # PS1_1 is the column name for the wavelength
735 fv = fc.getFitsS("PS1_1")
736 wavecol = fv.value
737 self.assertEqual(wavecol, "COORDS1")
739 # Get the WCS table from the FitsChan
740 km = fc.getTables()
741 table = km.getA(waveext, 0)
742 fc_bintab = table.getTableHeader()
744 fv = fc_bintab.getFitsS("TDIM1")
745 self.assertEqual(fv.value, "(1,5)")
747 self.assertEqual(table.nRow, 1)
748 self.assertEqual(table.nColumn, 1)
750 # 1-based column numbering to match FITS
751 cname = table.columnName(1)
752 self.assertEqual(cname, "COORDS1")
753 self.assertEqual(table.columnType(cname), ast.DataType.DoubleType)
754 self.assertEqual(table.columnSize(cname), 40)
755 self.assertEqual(table.columnNdim(cname), 2)
756 self.assertEqual(table.columnUnit(cname), "nm")
757 self.assertEqual(table.columnLength(cname), 5)
758 self.assertEqual(table.columnShape(cname), [1, 5])
759 coldata = table.getColumnData1D(cname)
760 self.assertEqual(list(coldata), list(wavelength))
762 # This will be shaped correctly as a numpy array with third dimension
763 # the row count.
764 coldata = table.getColumnData(cname)
765 self.assertEqual(coldata.ndim, 3)
766 self.assertEqual(coldata.shape, (1, 5, 1))
768 def test_python(self):
769 """Test Python Mapping/Sequence interface to FitsChan.
770 """
771 ss = ast.StringStream("".join(self.cards))
772 fc = ast.FitsChan(ss)
773 self.assertEqual(len(fc), 18)
774 cards = "".join(c for c in fc)
776 self.assertEqual(cards, "".join(self.cards))
777 self.assertIn("CTYPE2", fc)
778 self.assertIn(10, fc)
779 self.assertNotIn(-1, fc)
780 self.assertNotIn(20, fc)
781 self.assertNotIn("CTYPE3", fc)
783 self.assertEqual(fc["CTYPE1"], "RA--TAN")
784 self.assertEqual(fc["NAXIS2"], 200)
785 self.assertEqual(fc["CDELT2"], 0.001)
786 self.assertFalse(fc["BOOL"])
787 self.assertEqual(fc[4].rstrip(), "CRPIX1 = 100")
788 with self.assertRaises(KeyError):
789 fc["NOTIN"]
790 with self.assertRaises(IndexError):
791 fc[100]
793 # Update values
794 fc["BOOL"] = True # This will remove second card
795 self.assertEqual(fc["BOOL"], True)
796 fc["CRVAL2"] = None
797 self.assertIsNone(fc["CRVAL2"])
798 fc["NEWSTR"] = "Test"
799 self.assertEqual(fc["NEWSTR"], "Test")
800 fc["NEWINT"] = 1024
801 self.assertEqual(fc["NEWINT"], 1024)
802 fc["NEWFLT"] = 3.5
803 self.assertEqual(fc["NEWFLT"], 3.5)
804 fc["UNDEF"] = "not undef"
805 self.assertEqual(fc["UNDEF"], "not undef")
807 fc[""] = "A new BLANK comment"
808 fc[0] = "COMMENT Introduction comment"
809 self.assertEqual(fc[0].rstrip(), "COMMENT Introduction comment")
811 # This will fail since a string is required
812 with self.assertRaises(TypeError):
813 fc[0] = 52
815 # Delete the 3rd card
816 del fc[2]
817 self.assertEqual(fc[2].rstrip(), "CTYPE2 = 'DEC-TAN '")
818 self.assertEqual(len(fc), 20)
820 # Delete all the HISTORY cards
821 del fc["HISTORY"]
822 self.assertEqual(len(fc), 17)
824 # Change a card to blank
825 fc[3] = None
826 self.assertEqual(fc[3].strip(), "")
827 fc[3] = "COMMENT 1"
828 self.assertEqual(fc[3].strip(), "COMMENT 1")
829 fc[3] = ""
830 self.assertEqual(fc[3].strip(), "")
832 # Use negative index
833 self.assertEqual(fc[-1], fc[fc.nCard-1])
834 fc[-2] = "COMMENT new comment"
835 self.assertEqual(fc[-2], fc[fc.nCard-2])
836 self.assertEqual(fc[-2].rstrip(), "COMMENT new comment")
838 # Append a comment to the end
839 nCards = len(fc)
840 fc[fc.nCard] = "COMMENT X"
841 self.assertEqual(len(fc), nCards + 1)
842 self.assertEqual(fc[-1].rstrip(), "COMMENT X")
844 # Try to access and append using a high index
845 with self.assertRaises(IndexError):
846 fc[fc.nCard + 1]
847 with self.assertRaises(IndexError):
848 fc[fc.nCard + 1] = ""
849 with self.assertRaises(IndexError):
850 fc[fc.nCard]
852 # Or the wrong type of key
853 with self.assertRaises(KeyError):
854 fc[3.14] = 52
856 # Delete final card
857 nCards = len(fc)
858 del fc[-1]
859 self.assertEqual(fc[-1].rstrip(), "NEWFLT = 3.5")
860 self.assertEqual(len(fc), nCards - 1)
862 with self.assertRaises(IndexError):
863 del fc[-fc.nCard - 1]
865 with self.assertRaises(IndexError):
866 del fc[fc.nCard]
868 with self.assertRaises(KeyError):
869 del fc[3.14]
871 with self.assertRaises(KeyError):
872 del fc["NOTTHERE"]
874 # Test stringification
875 header = str(fc)
876 self.assertIn("BOOL = 1", header)
878 # All the items
879 collected = []
880 for k, v in fc.items():
881 collected.append((k, v))
882 self.assertEqual(len(collected), len(fc))
885if __name__ == "__main__": 885 ↛ 886line 885 didn't jump to line 886, because the condition on line 885 was never true
886 unittest.main()