1 from __future__ import division
2 import types
3 import pyfits
4 from pytools import fileutil, readgeis
5
6 yes = True
7 no = False
8
9 RESERVED_KEYS = ['NAXIS','BITPIX','DATE','IRAF-TLM','XTENSION','EXTNAME','EXTVER']
10
11 EXTLIST = ('SCI', 'WHT', 'CTX')
12
13 DTH_KEYWORDS=['CD1_1','CD1_2', 'CD2_1', 'CD2_2', 'CRPIX1',
14 'CRPIX2','CRVAL1', 'CRVAL2', 'CTYPE1', 'CTYPE2']
15
17 """
18 This class manages the creation of the array objects
19 which will be used by Drizzle. The three arrays, SCI/WHT/CTX,
20 will be setup either as extensions in a
21 single multi-extension FITS file, or as separate FITS
22 files.
23 """
25 """
26 The object 'plist' must contain at least the following members:
27 plist['output'] - name of output FITS image (for SCI)
28 plist['outnx'] - size of X axis for output array
29 plist['outny'] - size of Y axis for output array
30 If 'single=yes', then 'plist' also needs to contain:
31 plist['outsingle']
32 plist['outsweight']
33 plist['outscontext']
34 If 'blot=yes', then 'plist' also needs:
35 plist['data']
36 plist['outblot']
37 plist['blotnx'],plist['blotny']
38
39 If 'build' is set to 'no', then each extension/array must be
40 in separate FITS objects. This would also require:
41 plist['outdata'] - name of output SCI FITS image
42 plist['outweight'] - name of output WHT FITS image
43 plist['outcontext'] - name of output CTX FITS image
44
45 Optionally, the overall exposure time information can be passed as:
46 plist['texptime'] - total exptime for output
47 plist['expstart'] - start time of combined exposure
48 plist['expend'] - end time of combined exposure
49
50
51 """
52 self.build = build
53 self.single = single
54 self.parlist = plist
55 _nimgs = len(self.parlist)
56 self.bunit = None
57 self.units = 'cps'
58
59 if not blot:
60 self.output = plist[0]['output']
61 self.shape = (plist[0]['outny'],plist[0]['outnx'])
62 else:
63 self.output = plist[0]['outblot']
64 self.shape = (plist[0]['blotny'],plist[0]['blotnx'])
65
66
67 self.wcs = wcs
68
69
70
71
72
73 if single:
74 _outdata = plist[0]['outsingle']
75 _outweight = plist[0]['outsweight']
76 _outcontext = plist[0]['outscontext']
77
78 self.texptime = plist[0]['exptime']
79 self.expstart = plist[0]['expstart']
80 self.expend = plist[0]['expend']
81 else:
82 _outdata = plist[0]['outdata']
83 _outweight = plist[0]['outweight']
84 _outcontext = plist[0]['outcontext']
85
86 self.texptime = plist[0]['texptime']
87 self.expstart = plist[0]['texpstart']
88 self.expend = plist[_nimgs-1]['texpend']
89
90
91 if blot:
92 _outdata = plist[0]['outblot']
93
94 if not self.build or single:
95 self.output = _outdata
96
97 self.outdata = _outdata
98 self.outweight = _outweight
99 self.outcontext = _outcontext
100
102 """ Method used to update the value of the bunit attribute."""
103 self.bunit = bunit
104
106 """ Method used to record what units were specified by the user
107 for the output product."""
108 self.units = units
109
110
111 - def writeFITS(self, template, sciarr, whtarr, ctxarr=None, versions=None, extlist=EXTLIST, overwrite=yes):
112 """ Generate PyFITS objects for each output extension
113 using the file given by 'template' for populating
114 headers.
115
116 The arrays will have the size specified by 'shape'.
117 """
118
119 if fileutil.findFile(self.output):
120 if overwrite:
121 print 'Deleting previous output product: ',self.output
122 fileutil.removeFile(self.output)
123
124 else:
125 print 'WARNING: Output file ',self.output,' already exists and overwrite not specified!'
126 print 'Quitting... Please remove before resuming operations.'
127 raise IOError
128
129
130 nextend = 3
131 if not self.build:
132 nextend = 0
133 if self.outweight:
134 if overwrite:
135 if fileutil.findFile(self.outweight):
136 print 'Deleting previous output WHT product: ',self.outweight
137 fileutil.removeFile(self.outweight)
138 else:
139 print 'WARNING: Output file ',self.outweight,' already exists and overwrite not specified!'
140 print 'Quitting... Please remove before resuming operations.'
141 raise IOError
142
143
144 if self.outcontext:
145 if overwrite:
146 if fileutil.findFile(self.outcontext):
147 print 'Deleting previous output CTX product: ',self.outcontext
148 fileutil.removeFile(self.outcontext)
149 else:
150 print 'WARNING: Output file ',self.outcontext,' already exists and overwrite not specified!'
151 print 'Quitting... Please remove before resuming operations.'
152 raise IOError
153
154
155
156
157
158
159 prihdr,scihdr,errhdr,dqhdr = getTemplates(template,extlist)
160
161 if prihdr == None:
162
163 _indx = template.find('[')
164 if _indx < 0:
165 _data = template
166 else:
167 _data = template[:_indx]
168
169 fpri = readgeis.readgeis(_data)
170 prihdr = fpri[0].header.copy()
171 fpri.close()
172 del fpri
173
174
175
176 prihdu = pyfits.PrimaryHDU(header=prihdr,data=None)
177
178
179 prihdu.header.update('EXTEND',pyfits.TRUE,after='NAXIS')
180 prihdu.header.update('NEXTEND',nextend)
181 prihdu.header.update('FILENAME', self.output)
182
183
184 _indx = self.output.find('_drz')
185 if _indx < 0:
186 prihdu.header.update('ROOTNAME', self.output)
187 else:
188 prihdu.header.update('ROOTNAME', self.output[:_indx])
189
190
191
192
193
194 if self.texptime:
195 prihdu.header.update('EXPTIME', self.texptime)
196 prihdu.header.update('EXPSTART', self.expstart)
197 prihdu.header.update('EXPEND', self.expend)
198
199
200
201 prihdu.header.update('ASN_MTYP', 'PROD-DTH')
202
203
204
205 if prihdu.header.has_key('DRIZCORR') > 0:
206 prihdu.header['DRIZCORR'] = 'COMPLETE'
207 if prihdu.header.has_key('DITHCORR') > 0:
208 prihdu.header['DITHCORR'] = 'COMPLETE'
209
210
211 prihdu.header.update('NDRIZIM',len(self.parlist),
212 comment='Drizzle, No. images drizzled onto output')
213
214 self.addDrizKeywords(prihdu.header,versions)
215
216 if scihdr:
217 del scihdr['OBJECT']
218 if scihdr.has_key('CCDCHIP'): scihdr.update('CCDCHIP','-999')
219 if scihdr.has_key('NCOMBINE') > 0:
220 scihdr.update('NCOMBINE', self.parlist[0]['nimages'])
221
222
223 if self.bunit is not None:
224 scihdr.update('BUNIT',self.bunit,comment="Units of science product")
225
226 if self.wcs:
227
228
229 scihdr.update('ORIENTAT',self.wcs.orient)
230 scihdr.update('CD1_1',self.wcs.cd11)
231 scihdr.update('CD1_2',self.wcs.cd12)
232 scihdr.update('CD2_1',self.wcs.cd21)
233 scihdr.update('CD2_2',self.wcs.cd22)
234 scihdr.update('CRVAL1',self.wcs.crval1)
235 scihdr.update('CRVAL2',self.wcs.crval2)
236 scihdr.update('CRPIX1',self.wcs.crpix1)
237 scihdr.update('CRPIX2',self.wcs.crpix2)
238 scihdr.update('VAFACTOR',1.0)
239
240 if scihdr.has_key('TDDALPHA'):
241 del scihdr['TDDALPHA']
242 del scihdr['TDDBETA']
243
244 if scihdr['ctype1'].find('SIP') > -1:
245 scihdr.update('ctype1', scihdr['ctype1'][:-4])
246 scihdr.update('ctype2',scihdr['ctype2'][:-4])
247
248 for k in scihdr.items():
249 if (k[0][:2] in ['A_','B_']) or (k[0][:3] in ['IDC','SCD'] and k[0] != 'IDCTAB') or \
250 (k[0][:6] in ['SCTYPE','SCRVAL','SNAXIS','SCRPIX']):
251 del scihdr[k[0]]
252 self.addPhotKeywords(scihdr,prihdu.header)
253
254
255
256
257
258 if self.build:
259 print '-Generating multi-extension output file: ',self.output
260 fo = pyfits.HDUList()
261
262
263 fo.append(prihdu)
264
265 hdu = pyfits.ImageHDU(data=sciarr,header=scihdr,name=extlist[0])
266 fo.append(hdu)
267
268
269 if errhdr:
270 errhdr.update('CCDCHIP','-999')
271
272 hdu = pyfits.ImageHDU(data=whtarr,header=errhdr,name=extlist[1])
273 hdu.header.update('EXTVER',1)
274 if self.wcs:
275
276
277 hdu.header.update('ORIENTAT',self.wcs.orient)
278 hdu.header.update('CD1_1',self.wcs.cd11)
279 hdu.header.update('CD1_2',self.wcs.cd12)
280 hdu.header.update('CD2_1',self.wcs.cd21)
281 hdu.header.update('CD2_2',self.wcs.cd22)
282 hdu.header.update('CRVAL1',self.wcs.crval1)
283 hdu.header.update('CRVAL2',self.wcs.crval2)
284 hdu.header.update('CRPIX1',self.wcs.crpix1)
285 hdu.header.update('CRPIX2',self.wcs.crpix2)
286 hdu.header.update('VAFACTOR',1.0)
287
288 fo.append(hdu)
289
290
291
292 if self.outcontext:
293 if ctxarr.shape[0] == 1:
294 _ctxarr = ctxarr[0]
295 else:
296 _ctxarr = ctxarr
297 else:
298 _ctxarr = None
299
300 hdu = pyfits.ImageHDU(data=_ctxarr,header=dqhdr,name=extlist[2])
301 hdu.header.update('EXTVER',1)
302 if self.wcs:
303
304
305 hdu.header.update('ORIENTAT',self.wcs.orient)
306 hdu.header.update('CD1_1',self.wcs.cd11)
307 hdu.header.update('CD1_2',self.wcs.cd12)
308 hdu.header.update('CD2_1',self.wcs.cd21)
309 hdu.header.update('CD2_2',self.wcs.cd22)
310 hdu.header.update('CRVAL1',self.wcs.crval1)
311 hdu.header.update('CRVAL2',self.wcs.crval2)
312 hdu.header.update('CRPIX1',self.wcs.crpix1)
313 hdu.header.update('CRPIX2',self.wcs.crpix2)
314 hdu.header.update('VAFACTOR',1.0)
315
316
317 fo.append(hdu)
318
319 fo.writeto(self.output)
320 fo.close()
321 del fo, hdu
322
323 else:
324 print '-Generating simple FITS output: ',self.outdata
325 fo = pyfits.HDUList()
326
327 hdu = pyfits.PrimaryHDU(data=sciarr, header=prihdu.header)
328
329
330
331 if scihdr:
332 for _card in scihdr.ascard:
333 if _card.key not in RESERVED_KEYS and hdu.header.has_key(_card.key) == 0:
334 hdu.header.ascard.append(_card)
335 del hdu.header['PCOUNT']
336 del hdu.header['GCOUNT']
337 self.addPhotKeywords(hdu.header,prihdu.header)
338 hdu.header.update('filename',self.outdata)
339
340
341 fo.append(hdu)
342 fo.writeto(self.outdata)
343 del fo,hdu
344
345 if self.outweight and whtarr != None:
346
347 fwht = pyfits.HDUList()
348
349 if errhdr:
350 errhdr.update('CCDCHIP','-999')
351
352 hdu = pyfits.PrimaryHDU(data=whtarr, header=prihdu.header)
353
354
355
356 if errhdr:
357 for _card in errhdr.ascard:
358 if _card.key not in RESERVED_KEYS and hdu.header.has_key(_card.key) == 0:
359 hdu.header.ascard.append(_card)
360 hdu.header.update('filename',self.outweight)
361 hdu.header.update('CCDCHIP','-999')
362 if self.wcs:
363
364
365 hdu.header.update('ORIENTAT',self.wcs.orient)
366 hdu.header.update('CD1_1',self.wcs.cd11)
367 hdu.header.update('CD1_2',self.wcs.cd12)
368 hdu.header.update('CD2_1',self.wcs.cd21)
369 hdu.header.update('CD2_2',self.wcs.cd22)
370 hdu.header.update('CRVAL1',self.wcs.crval1)
371 hdu.header.update('CRVAL2',self.wcs.crval2)
372 hdu.header.update('CRPIX1',self.wcs.crpix1)
373 hdu.header.update('CRPIX2',self.wcs.crpix2)
374 hdu.header.update('VAFACTOR',1.0)
375
376
377 fwht.append(hdu)
378 fwht.writeto(self.outweight)
379 del fwht,hdu
380
381
382
383 if self.outcontext and ctxarr != None:
384 fctx = pyfits.HDUList()
385
386
387 if ctxarr.shape[0] == 1:
388 _ctxarr = ctxarr[0]
389 else:
390 _ctxarr = ctxarr
391
392 hdu = pyfits.PrimaryHDU(data=_ctxarr, header=prihdu.header)
393
394
395
396 if dqhdr:
397 for _card in dqhdr.ascard:
398 if _card.key not in RESERVED_KEYS and hdu.header.has_key(_card.key) == 0:
399 hdu.header.ascard.append(_card)
400 hdu.header.update('filename', self.outcontext)
401 if self.wcs:
402
403
404 hdu.header.update('ORIENTAT',self.wcs.orient)
405 hdu.header.update('CD1_1',self.wcs.cd11)
406 hdu.header.update('CD1_2',self.wcs.cd12)
407 hdu.header.update('CD2_1',self.wcs.cd21)
408 hdu.header.update('CD2_2',self.wcs.cd22)
409 hdu.header.update('CRVAL1',self.wcs.crval1)
410 hdu.header.update('CRVAL2',self.wcs.crval2)
411 hdu.header.update('CRPIX1',self.wcs.crpix1)
412 hdu.header.update('CRPIX2',self.wcs.crpix2)
413 hdu.header.update('VAFACTOR',1.0)
414
415 fctx.append(hdu)
416 fctx.writeto(self.outcontext)
417 del fctx,hdu
418
419
421 """ Insure that this header contains all the necessary photometry
422 keywords, moving them into the extension header if necessary.
423 This only moves keywords from the PRIMARY header if the keywords
424 do not already exist in the SCI header.
425 """
426 PHOTKEYS = ['PHOTFLAM','PHOTPLAM','PHOTBW','PHOTZPT','PHOTMODE']
427 for pkey in PHOTKEYS:
428 if not hdr.has_key(pkey):
429
430 if phdr.has_key(pkey):
431
432 hdr.update(pkey,phdr[pkey])
433
434 del phdr[pkey]
435 else:
436
437 if pkey != 'PHOTMODE':
438 hdr.update(pkey,0.0)
439 else:
440 hdr.update(pkey,'')
441
443 """ Add drizzle parameter keywords to header. """
444
445
446 _geom = 'User parameters'
447
448 _imgnum = 0
449 for pl in self.parlist:
450
451
452
453 _imgnum += 1
454 _keyprefix = 'D%03d'%_imgnum
455 if not isinstance(pl['driz_mask'],types.StringType):
456 _driz_mask_name = 'static mask'
457 else:
458 _driz_mask_name = pl['driz_mask']
459
460 hdr.update(_keyprefix+'VER',pl['driz_version'][:44],
461 comment='Drizzle, task version')
462
463
464 hdr.update(_keyprefix+'GEOM','User parameters',
465 comment= 'Drizzle, source of geometric information')
466
467
468
469 hdr.update(_keyprefix+'DATA',pl['data'][:64],
470 comment= 'Drizzle, input data image')
471
472 hdr.update(_keyprefix+'DEXP',pl['exptime'],
473 comment= 'Drizzle, input image exposure time (s)')
474
475 hdr.update(_keyprefix+'OUDA',pl['outdata'][:64],
476 comment= 'Drizzle, output data image')
477
478 hdr.update(_keyprefix+'OUWE',pl['outweight'][:64],
479 comment= 'Drizzle, output weighting image')
480
481 hdr.update(_keyprefix+'OUCO',pl['outcontext'][:64],
482 comment= 'Drizzle, output context image')
483
484 hdr.update(_keyprefix+'MASK',_driz_mask_name[:64],
485 comment= 'Drizzle, input weighting image')
486
487
488
489 if pl['wt_scl'] == 'exptime': _wtscl = pl['exptime']
490 elif pl['wt_scl'] == 'expsq': _wtscl = pl['exptime']*pl['exptime']
491 else: _wtscl = pl['wt_scl']
492
493 hdr.update(_keyprefix+'WTSC',_wtscl,
494 comment= 'Drizzle, weighting factor for input image')
495
496 hdr.update(_keyprefix+'KERN',pl['kernel'],
497 comment= 'Drizzle, form of weight distribution kernel')
498
499 hdr.update(_keyprefix+'PIXF',pl['pixfrac'],
500 comment= 'Drizzle, linear size of drop')
501
502 hdr.update(_keyprefix+'COEF',pl['coeffs'][:64],
503 comment= 'Drizzle, coefficients file name ')
504
505 hdr.update(_keyprefix+'XGIM',pl['xgeoim'][:64],
506 comment= 'Drizzle, X distortion image name ')
507
508 hdr.update(_keyprefix+'YGIM',pl['ygeoim'][:64],
509 comment= 'Drizzle, Y distortion image name ')
510
511 hdr.update(_keyprefix+'LAM',pl['plam'],
512 comment='Drizzle, wavelength applied for transformation (nm)')
513
514
515 hdr.update(_keyprefix+'SCAL',pl['scale'],
516 comment= 'Drizzle, scale (pixel size) of output image')
517
518
519 hdr.update(_keyprefix+'ROT',float("%0.8f"%pl['rot']),
520 comment= 'Drizzle, rotation angle, degrees anticlockwise')
521
522
523
524 hdr.update(_keyprefix+'XSH',pl['xsh'],
525 comment= 'Drizzle, X shift applied')
526
527 hdr.update(_keyprefix+'YSH',pl['ysh'],
528 comment= 'Drizzle, Y shift applied')
529
530 hdr.update(_keyprefix+'SFTU','output',
531 comment='Drizzle, units used for shifts')
532
533 hdr.update(_keyprefix+'SFTF','output',
534 comment= 'Drizzle, frame in which shifts were applied')
535
536 hdr.update(_keyprefix+'EXKY','EXPTIME',
537 comment= 'Drizzle, exposure keyword name in input image')
538
539 hdr.update(_keyprefix+'INUN','counts',
540 comment= 'Drizzle, units of input image - counts or cps')
541
542 hdr.update(_keyprefix+'OUUN',self.units,
543 comment= 'Drizzle, units of output image - counts or cps')
544
545 hdr.update(_keyprefix+'FVAL',pl['fillval'],
546 comment= 'Drizzle, fill value for zero weight output pix')
547
548 OFF=0.5
549
550 hdr.update(_keyprefix+'INXC',float(pl['blotnx']//2)+OFF,
551 comment= 'Drizzle, reference center of input image (X)')
552
553 hdr.update(_keyprefix+'INYC',float(pl['blotny']//2)+OFF,
554 comment= 'Drizzle, reference center of input image (Y)')
555
556 hdr.update(_keyprefix+'OUXC',float(pl['outnx']//2)+OFF,
557 comment= 'Drizzle, reference center of output image (X)')
558
559 hdr.update(_keyprefix+'OUYC',float(pl['outny']//2)+OFF,
560 comment= 'Drizzle, reference center of output image (Y)')
561
562
563 if versions != None:
564 ver_str = "PyDrizzle processing performed using: "
565 hdr.add_history(ver_str)
566 for k in versions.keys():
567 ver_str = ' '+str(k)+' Version '+str(versions[k])
568 hdr.add_history(ver_str)
569
570
571
573
574
575
576
577
578
579 if fname == None:
580 print 'No data files for creating FITS output.'
581 raise Exception
582
583 froot,fextn = fileutil.parseFilename(fname)
584 if fextn is not None:
585 fnum = fileutil.parseExtn(fextn)[1]
586 ftemplate = fileutil.openImage(froot,mode='readonly')
587 prihdr = pyfits.Header(cards=ftemplate['PRIMARY'].header.ascard.copy())
588 del prihdr['pcount']
589 del prihdr['gcount']
590
591 if fname.find('.fits') > 0 and len(ftemplate) > 1:
592
593
594
595 _extkey = 'EXTNAME'
596
597 defnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0])
598
599
600
601
602 if fextn in [None,1]:
603 extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0])
604 else:
605 extnum = (extlist[0],fnum)
606 scihdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy())
607 scihdr.update('extver',1)
608
609 if fextn in [None,1]:
610 extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[1])
611 else:
612
613 count = 0
614 for f in ftemplate:
615 if f.header.has_key('extname') and f.header['extname'] == extlist[1]:
616 count += 1
617 if count > 0:
618 extnum = (extlist[1],fnum)
619 else:
620
621 extnum = (extlist[0],fnum)
622 errhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy())
623 errhdr.update('extver',1)
624
625 if fextn in [None,1]:
626 extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[2])
627 else:
628 count = 0
629 for f in ftemplate:
630 if f.header.has_key('extname') and f.header['extname'] == extlist[2]:
631 count += 1
632 if count > 0:
633 extnum = (extlist[2],fnum)
634 else:
635
636 extnum = (extlist[0],fnum)
637 dqhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy())
638 dqhdr.update('extver',1)
639
640 else:
641
642 scihdr = None
643 errhdr = None
644 dqhdr = None
645
646 ftemplate.close()
647 del ftemplate
648
649
650 try:
651 del scihdr['bscale']
652 del scihdr['bzero']
653 del errhdr['bscale']
654 del errhdr['bzero']
655 del dqhdr['bscale']
656 del dqhdr['bzero']
657 except:
658
659 pass
660
661
662
663
664
665 if errhdr != None and dqhdr != None:
666 for keyword in DTH_KEYWORDS:
667 if not errhdr.has_key(keyword):
668 errhdr.update(keyword,scihdr[keyword])
669 if not dqhdr.has_key(keyword):
670 dqhdr.update(keyword,scihdr[keyword])
671
672 return prihdr,scihdr,errhdr,dqhdr
673