summaryrefslogtreecommitdiff
path: root/wcsutil/headerlet.py
diff options
context:
space:
mode:
Diffstat (limited to 'wcsutil/headerlet.py')
-rw-r--r--wcsutil/headerlet.py244
1 files changed, 192 insertions, 52 deletions
diff --git a/wcsutil/headerlet.py b/wcsutil/headerlet.py
index c479e81..5104a2f 100644
--- a/wcsutil/headerlet.py
+++ b/wcsutil/headerlet.py
@@ -1,15 +1,110 @@
from __future__ import division
import time
+import numpy as np
import pyfits
from hstwcs import HSTWCS
import altwcs
from pyfits import HDUList
from mappings import basic_wcs
-
+def isWCSIdentical(scifile, file2):
+ """
+ Compares the WCS solution of 2 files.
+
+ These can be 2 science observations or 2 headerlets
+ or a science observation and a headerlet. The two files
+ have the same WCS solution if the following are the same:
+
+ - rootname/destim
+ - primary WCS
+ - SIP coefficients
+ - NPOL distortion
+ - D2IM correction
+ - Velocity aberation
+ """
+ result = True
+ numsci1 = max(countext(scifile, 'SCI'), countext(scifile, 'SIPWCS'))
+ numsci2 = max(countext(file2, 'SCI'), countext(file2, 'SIPWCS'))
+ if numsci1 == 0 or numsci2==0 or numsci1!= numsci2:
+ print "Number of SCI and SIPWCS extensions do not match."
+ result = False
+
+ if getRootname(scifile) != getRootname(file2):
+ print 'Rootnames do not match.'
+ result = False
+ try:
+ extname1 = pyfits.getval(scifile, 'EXTNAME', ext=('SCI', 1))
+ except KeyError:
+ extname1 = 'SIPWCS'
+ try:
+ extname2 = pyfits.getval(file2, 'EXTNAME', ext=('SCI', 1))
+ except KeyError:
+ extname2 = 'SIPWCS'
+
+ for i in range(1, numsci1+1):
+ w1 = HSTWCS(scifile,ext=(extname1,i))
+ w2 = HSTWCS(file2, ext=(extname2,i))
+ if not (w1.wcs.crval == w2.wcs.crval).all() or \
+ not (w1.wcs.crpix == w2.wcs.crpix).all() or \
+ not (w1.wcs.cd == w2.wcs.cd).all() or \
+ not (np.array(w1.wcs.ctype) == np.array(w2.wcs.ctype)).all():
+ print 'Primary WCSs do not match'
+ result = False
+ if w1.sip or w2.sip:
+ if (w2.sip and not w1.sip) or (w1.sip and not w2.sip) or \
+ not (w1.sip.a == w2.sip.a).all() or \
+ not (w1.sip.b == w2.sip.b).all():
+ print 'SIP coefficients do not match'
+ result = False
+ if w1.cpdis1 or w2.cipdis1:
+ if w1.cpdis1 and not w2.cpdis1 or \
+ w2.cpdis1 and not w1.cpdis1 or \
+ not (w1.cpdis1.data == w2.cpdis1.data).all():
+ print 'NPOL distortions do not match'
+ result = False
+ if w1.cpdis2 or w2.cpdis2:
+ if w1.cpdis2 and not w2.cpdis2 or \
+ w2.cpdis2 and not w1.cpdis2 or \
+ not (w1.cpdis2.data == w2.cpdis2.data).all():
+ print 'NPOL distortions do not match'
+ result = False
+ if w1.det2im1 or w2.det2im1:
+ if w1.det2im1 and not w2.det2im1 or \
+ w2.det2im1 and not w1.det2im1 or\
+ not (w1.det2im1.data == w2.det2im1.data).all():
+ print 'Det2Im corrections do not match'
+ result = False
+ if w1.det2im2 or w2.det2im2:
+ if w1.det2im2 and not w2.det2im2 or \
+ w2.det2im2 and not w1.det2im2 or\
+ not (w1.det2im2.data == w2.det2im2.data).all():
+ print 'Det2Im corrections do not match'
+ result = False
+ if w1.vafactor != w2.vafactor:
+ print 'VA factors do not match'
+ result = False
+
+ return result
+
def createHeaderlet(fname, hdrname, destim=None, output=None):
"""
- creates a headerlet from a science observation
+ Create a headerlet from a science observation
+
+ Parameters
+ ----------
+ fname: string
+ Name of file with science observation
+ hdrname: string
+ Name for the headerlet, stored in the primary header of the headerlet
+ If output is None, hdrname is used as output
+ destim: string
+ Destination image, stored in the primary header of the headerlet.
+ If None ROOTNAME is used of the science observation is used.
+ ROOTNAME has precedence, destim is used for observations without
+ ROOTNAME in the primary header
+ output: string
+ Name for the headerlet file.
+ HDRNAME is used if output is not given.
"""
fmt="%Y-%m-%dT%H:%M:%S"
phdukw = {'IDCTAB': True,
@@ -96,9 +191,23 @@ def createHeaderlet(fname, hdrname, destim=None, output=None):
hdul.writeto(output,clobber=True)
fobj.close()
+def applyHeaderlet(hdrfile, destfile, destim=None, hdrname=None, createheaderlet=True):
+ """
+ apply headerlet 'hdrfile' to a science observation 'destfile'
+ """
+ hlet = Headerlet(hdrfile)
+ hlet.apply2obs(destfile, destim=destim, hdrname=hdrname, createheaderlet=createheaderlet)
+
def updateRefFiles(source, dest):
- #dest is destination extension header.ascard
- #source is source header.ascard
+ """
+ Update the reference files name in the primary header of 'dest'
+ using values from 'source'
+
+ Parameters
+ ----------
+ source: pyfits.Header.ascardlist
+ dest: pyfits.Header.ascardlist
+ """
phdukw = {'IDCTAB': True,
'NPOLFILE': True,
'D2IMFILE': True}
@@ -113,8 +222,21 @@ def updateRefFiles(source, dest):
dest.insert(wind, value)
except KeyError:
phdukw[key] = False
-
+
+def getRootname(fname):
+ """
+ returns the value of ROOTNAME or DESTIM
+ """
+ try:
+ rootname = pyfits.getval(fname, 'ROOTNAME')
+ except KeyError:
+ rootname = pyfits.getval(fname, 'DESTIM')
+ return rootname
+
def mapFitsExt2HDUListInd(fname, extname):
+ """
+ Map FITS extensions with 'EXTNAME' to HDUList indexes.
+ """
if isinstance(fname, str):
f = pyfits.open(fname)
else:
@@ -128,6 +250,9 @@ def mapFitsExt2HDUListInd(fname, extname):
return d
def countext(fname, extname):
+ """
+ Return the number of extensions with EXTNAME in the file.
+ """
if isinstance(fname, str):
f = pyfits.open(fname)
else:
@@ -138,24 +263,24 @@ def countext(fname, extname):
numext+=1
return numext
-def _cleanDestWCS(dest):
- #clean all WCSs in the destination file
- #dkeys = altwcs.wcskeys(pyfits.getheader(dest,ext=('SCI',1)))
- #Warning: Does not clean teh primary WCS
+def _delDestWCS(dest):
+ """
+ Delete the WCS of a science file
+ """
fobj = pyfits.open(dest, mode='update')
numext = len(fobj)
for e in range(numext):
- removeD2IM(fobj[e])
- removeSIP(fobj[e])
- removeLUT(fobj[e])
- removePrimaryWCS(fobj[e])
- removeIDCCoeffs(fobj[e])
+ _removeD2IM(fobj[e])
+ _removeSIP(fobj[e])
+ _removeLUT(fobj[e])
+ _removePrimaryWCS(fobj[e])
+ _removeIDCCoeffs(fobj[e])
try:
del fobj[e].header.ascard['VAFACTOR']
except KeyError: pass
- removeAltWCS(fobj, ext=range(numext))
+ _removeAltWCS(fobj, ext=range(numext))
numwdvarr = countext(dest,'WCSDVARR')
numd2im = countext(dest,'D2IMARR')
for i in range(1, numwdvarr+1):
@@ -164,7 +289,10 @@ def _cleanDestWCS(dest):
del fobj[('D2IMARR',i)]
fobj.close()
-def removeSIP(ext):
+def _removeSIP(ext):
+ """
+ Remove the SIP distortion of a FITS extension
+ """
for prefix in ['A','B', 'AP', 'BP']:
try:
order = ext.header[prefix+'_ORDER']
@@ -183,7 +311,10 @@ def removeSIP(ext):
except KeyError:
pass
-def removeLUT(ext):
+def _removeLUT(ext):
+ """
+ Remove the Lookup Table distortion of a FITS extension
+ """
try:
cpdis = ext.header['CPDIS*']
except KeyError:
@@ -198,7 +329,10 @@ def removeLUT(ext):
except KeyError:
pass
-def removeD2IM(ext):
+def _removeD2IM(ext):
+ """
+ Remove the Detector to Image correction of a FITS extension
+ """
d2imkeys = ['D2IMFILE', 'AXISCORR', 'D2IMEXT', 'D2IMERR']
for k in d2imkeys:
try:
@@ -206,12 +340,19 @@ def removeD2IM(ext):
except KeyError:
pass
-def removeAltWCS(dest, ext):
+def _removeAltWCS(dest, ext):
+ """
+ Remove Alternate WCSs of a FITS extension.
+ A WCS with wcskey 'O' is never deleted.
+ """
dkeys = altwcs.wcskeys(dest[('SCI',1)].header)
for k in dkeys:
altwcs.deleteWCS(dest, ext=ext, wcskey=k)
-def removePrimaryWCS(ext):
+def _removePrimaryWCS(ext):
+ """
+ Remove the primary WCS of a FITS extension
+ """
naxis = ext.header.ascard['NAXIS'].value
for key in basic_wcs:
for i in range(1,naxis+1):
@@ -222,7 +363,10 @@ def removePrimaryWCS(ext):
del ext.header.ascard['WCSAXES']
except KeyError: pass
-def removeIDCCoeffs(ext):
+def _removeIDCCoeffs(ext):
+ """
+ Remove IDC coefficients of a FITS extension
+ """
coeffs = ['OCX10', 'OCX11', 'OCY10', 'OCY11', 'IDCSCALE']
for k in coeffs:
try:
@@ -231,8 +375,22 @@ def removeIDCCoeffs(ext):
pass
class Headerlet(HDUList):
+ """
+ A Headerlet class
+ Ref: http://stsdas.stsci.edu/stsci_python_sphinxdocs/stwcs/headerlet_def.html
+ """
def __init__(self, fname, wcskeys=[]):
-
+ """
+ Parameters
+ ----------
+ fname: string
+ Name of headerlet file
+ wcskeys: python list
+ a list of wcskeys to be included in the headerlet
+ created from the old WCS solution before the
+ science file is updated. If empty: all alternate (if any)
+ WCSs are copied to the headerlet.
+ """
self.wcskeys = wcskeys
if isinstance(fname,str):
fobj = pyfits.open(fname)
@@ -260,7 +418,7 @@ class Headerlet(HDUList):
if self.verify_dest(dest):
if createheaderlet:
createHeaderlet(dest, hdrname, destim)
- _cleanDestWCS(dest)
+ _delDestWCS(dest)
fobj = pyfits.open(dest, mode='update')
updateRefFiles(self[0].header.ascard, fobj[0].header.ascard)
@@ -286,7 +444,7 @@ class Headerlet(HDUList):
fhdr.insert(wind, siphdr[k])
else:
pass
- #! Always attach these extensions last. Otherwise thier headers may
+ #! Always attach these extensions last. Otherwise therr headers may
# get updated with the other WCS kw.
numwdvar = countext(self,'WCSDVARR')
numd2im = countext(self, 'D2IMARR')
@@ -304,42 +462,24 @@ class Headerlet(HDUList):
self.verify()
assert(self[0].header.has_key('DESTIM') and self[0].header['DESTIM']!= " ")
assert(self[0].header.has_key('HDRNAME') and self[0].header['HDRNAME']!= " ")
- #assert(self[0].header.has_key('STWCSVER') and self[0].header['STWCSVER']!= " ")
- """
- npolfile, vafactor and d2imfile are optional.
- idctab may be optional too ...
- assert(self[0].header.has_key('IDCTAB')
- and self[0].header['IDCTAB']!= " ")
- assert(self[0].header.has_key('NPOLFILE')
- and self[0].header['NPOLFILE']!= " ")
- """
+ assert(self[0].header.has_key('STWCSVER'))
+
def verify_dest(self, dest):
"""
verifies that the headerlet can be applied to the observation
- requirements:
- - if self.destim = fname.rootname
- - if fname has the same file structure.
- - if idctab, npolfile, d2imfile are different for self and fname
- - if vafactor is different
- -
+
+ DESTIM in the primary header of the headerlet must match ROOTNAME
+ of the science file (or the name of the destination file)
"""
- dobj = pyfits.open(dest)
try:
- droot = dobj[0].header['ROOTNAME']
+ droot = pyfits.getval(dest, 'ROOTNAME')
except KeyError:
- dobj.close()
- print "This headerlet cannot be applied to observation %s. " % destfile
- print "It can only be applied to observations with root name %s" % self.destim
- return False
- dnumsci = countext(dest, 'SCI')
- hnumsip = countext(self, 'SIPWCS')
- if dnumsci != hnumsip:
- print "This headerlet cannot be applied to observation %s. " % dest
- print "The observation and the headerlet have a different number of 'SCI' extensions."
+ droot = dest.split('.fits')[0]
+ if droot == self.destim:
+ return True
+ else:
return False
- dobj.close()
- return True
def tofile(self, fname, destim=None, hdrname=None, clobber=False):
if not destim or not hdrname: