summaryrefslogtreecommitdiff
path: root/updatewcs/dgeo.py
diff options
context:
space:
mode:
Diffstat (limited to 'updatewcs/dgeo.py')
-rw-r--r--updatewcs/dgeo.py206
1 files changed, 206 insertions, 0 deletions
diff --git a/updatewcs/dgeo.py b/updatewcs/dgeo.py
new file mode 100644
index 0000000..32e1a38
--- /dev/null
+++ b/updatewcs/dgeo.py
@@ -0,0 +1,206 @@
+import pyfits
+from pytools import fileutil
+from hstwcs.mappings import dgeo_vals
+
+class DGEO(object):
+ """
+ Purpose
+ =======
+ Defines a Lookup table prior distortion correction as per WCS paper IV.
+ It uses a reference file defined by the DGEOFILE keyword in the primary header.
+
+ Algorithm
+ =========
+ - Using extensions in the reference file create a WCSDVARR extension
+ and add it to the file object.
+ - Add record-valued keywords which describe the looikup tables to the
+ science extension header
+ - Add a keyword 'DGEOFILE' to the science extension header, whose
+ value is the reference file used to create the WCSVARR extension
+
+ """
+ def __init__(self, fobj):
+ """
+ :Parameters:
+ `fobj`: pyfits object
+ Science file, for which a distortion correc tion in a DGEOFILE is available
+
+ """
+ assert isinstance(fobj, pyfits.NP_pyfits.HDUList)
+ self.fobj = fobj
+ self.applyDgeoCorr()
+
+
+ def applyDgeoCorr(self):
+ """
+ For each science extension in a pyfits file object:
+ - create a WCSDVARR extension
+ - update science header
+ - add/update DGEOFILE keyword
+ """
+
+ dgeover = 0
+ dgfile = fileutil.osfn(self.fobj[0].header['DGEOFILE'])
+ wcsdvarr_ind = self.getwcsindex()
+ for ext in self.fobj:
+ try:
+ extname = ext.header['EXTNAME'].lower()
+ except KeyError:
+ continue
+ if extname == 'sci':
+ extversion = ext.header['EXTVER']
+ for ename in ['DX', 'DY']:
+ dgeover +=1
+
+ self.addSciExtKw(ext.header, extver=dgeover, ename=ename)
+ hdu = self.createDgeoHDU(dgeofile=dgfile, dgeover=dgeover,ename=ename, extver=extversion)
+ if wcsdvarr_ind:
+ self.fobj[wcsdvarr_ind[dgeover]] = hdu
+ else:
+ self.fobj.append(hdu)
+ self.updateDGEOkw(ext.header)
+
+ def getwcsindex(self):
+ """
+ Returns the index of a WCSDVARR extension in a pyfits file object if it exists.
+ If it exists subsequent updates will overwrite it. If not, it will be
+ added to the file object.
+ """
+ wcsd = {}
+ for e in range(len(self.fobj)):
+ try:
+ ename = self.fobj[e].header['EXTNAME']
+ except KeyError:
+ continue
+ if ename == 'WCSDVARR':
+ wcsd[self.fobj[e].header['EXTVER']] = e
+ return wcsd
+
+ return self.fobj.index_of(('WCSDVARR', dgeover))
+
+ def addSciExtKw(self, hdr, extver=None, ename=None):
+ """
+ Adds kw to sci extension to define dgeo correction extensions
+ kw to be added to sci ext:
+ CPERRORj
+ CPDISj
+ DPj.EXTVER
+ DPj.NAXES
+ DPj.AXIS.i (i=DP1.NAXES)
+ """
+ if ename =='DX':
+ j=1
+ else:
+ j=2
+
+ cperror = 'CPERROR%s' %j
+ cpdis = 'CPDIS%s' %j
+ dpext = 'DP%s.' %j + 'EXTVER'
+ dpnaxes = 'DP%s.' %j +'NAXES'
+ dpaxis1 = 'DP%s.' %j+'AXIS.1'
+ dpaxis2 = 'DP%s.' %j+'AXIS.2'
+ keys = [cperror, cpdis, dpext, dpnaxes, dpaxis1, dpaxis2]
+ values = {cperror: 0.0, cpdis: 'Lookup', dpext: extver, dpnaxes: 2,
+ dpaxis1: 1, dpaxis2: 2}
+
+ comments = {cperror: 'Maximum error of dgeo correction for axis %s' % (extver/2),
+ cpdis: 'Prior distortion funcion type',
+ dpext: 'Version number of WCSDVARR extension containing lookup distortion table',
+ dpnaxes: 'Number of independent variables in distortion function',
+ dpaxis1: 'Axis number of the jth independent variable in a distortion function',
+ dpaxis2: 'Axis number of the jth independent variable in a distortion function'
+ }
+
+ for key in keys:
+ hdr.update(key=key, value=values[key], comment=comments[key], before='HISTORY')
+
+ dgfile = self.fobj[0].header['DGEOFILE']
+ hdr.update(key='DGEOFILE', value=dgfile, comment='DGEOFILE used to create WCSDVARR extensions', before='HISTORY')
+
+
+ def getDgeoData(self, dgfile=None, ename=None, extver=1):
+ """
+ Given a dgeo file name, creates an array to be used
+ as a data array in the dgeo extension.
+ """
+ return pyfits.getdata(dgfile, ext=(ename,extver))
+
+ def createDgeoHDU(self, dgeofile=None, dgeover=1, ename=None,extver=1):
+ """
+ Creates an HDU to be added to the file object.
+ """
+ dgeokw = {'naxis1':None, 'naxis2':None, 'extver':dgeover, 'crpix1':None,
+ 'crpix2':None, 'cdelt1':None, 'cdelt2':None, 'crval1':None, 'crval2':None}
+ hdr = self.createDgeoHdr(**dgeokw)
+ data = self.getDgeoData(dgfile=dgeofile, ename=ename, extver=extver)
+ hdu=pyfits.ImageHDU(header=hdr, data=data)
+ return hdu
+
+ def createDgeoHdr(self, **kw):
+ """
+ Creates a header for the dgeo extension based on dgeo file
+ and sci extension header.
+ **kw = {'naxis1':None, 'naxis2':None, 'extver':None, 'crpix1':None,
+ 'crpix2':None, 'cdelt1':None, 'cdelt2':None, 'crval1':None, 'crval2':None}
+ """
+ instr = self.fobj[0].header['INSTRUME']
+ instr_vals = dgeo_vals[instr]
+ naxis1 = kw['naxis1'] or instr_vals['naxis1']
+ naxis2 = kw['naxis2'] or instr_vals['naxis2']
+ extver = kw['extver'] or instr_vals['extver']
+ crpix1 = kw['crpix1'] or instr_vals['crpix1']
+ crpix2 = kw['crpix2'] or instr_vals['crpix2']
+ cdelt1 = kw['cdelt1'] or instr_vals['cdelt1']
+ cdelt2 = kw['cdelt2'] or instr_vals['cdelt2']
+ crval1 = kw['crval1'] or instr_vals['crval1']
+ crval2 = kw['crval2'] or instr_vals['crval2']
+
+ keys = ['XTENSION','BITPIX','NAXIS','NAXIS1','NAXIS2',
+ 'EXTNAME','EXTVER','PCOUNT','GCOUNT','CRPIX1',
+ 'CDELT1','CRVAL1','CRPIX2','CDELT2','CRVAL2']
+
+ comments = {'XTENSION': 'Image extension',
+ 'BITPIX': 'IEEE floating point',
+ 'NAXIS': 'Number of image columns',
+ 'NAXIS1': 'Number of image columns',
+ 'NAXIS2': 'Number of image rows',
+ 'EXTNAME': 'WCS distortion array',
+ 'EXTVER': 'Distortion array version number',
+ 'PCOUNT': 'Special data area of size 0',
+ 'GCOUNT': 'One data group',
+ 'CRPIX1': 'Distortion array reference pixel',
+ 'CDELT1': 'Grid step size in first coordinate',
+ 'CRVAL1': 'Image array pixel coordinate',
+ 'CRPIX2': 'Distortion array reference pixel',
+ 'CDELT2': 'Grid step size in second coordinate',
+ 'CRVAL2': 'Image array pixel coordinate'}
+
+ values = {'XTENSION': 'IMAGE',
+ 'BITPIX': -32,
+ 'NAXIS': 2,
+ 'NAXIS1': naxis1,
+ 'NAXIS2': naxis2,
+ 'EXTNAME': 'WCSDVARR',
+ 'EXTVER': extver,
+ 'PCOUNT': 0,
+ 'GCOUNT': 1,
+ 'CRPIX1': crpix1,
+ 'CDELT1': cdelt1,
+ 'CRVAL1': crval1,
+ 'CRPIX2': crpix1,
+ 'CDELT2': cdelt2,
+ 'CRVAL2': crval2
+ }
+
+
+ cdl = pyfits.CardList()
+ for c in keys:
+ cdl.append(pyfits.Card(key=c, value=values[c], comment=comments[c]))
+
+ hdr = pyfits.Header(cards=cdl)
+ return hdr
+
+ def updateDGEOkw(self, hdr):
+ dgfile = self.fobj[0].header['DGEOFILE']
+ hdr.update(key='DGEOFILE', value=dgfile, comment='DGEOFILE used to create WCSDVARR extensions', before='HISTORY')
+ \ No newline at end of file