summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/utils.py200
-rw-r--r--updatewcs/__init__.py98
-rw-r--r--updatewcs/apply_corrections.py41
3 files changed, 91 insertions, 248 deletions
diff --git a/lib/utils.py b/lib/utils.py
index 6f63db0..29ba5f3 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -1,147 +1,5 @@
from __future__ import division # confidence high
-from pytools import parseinput, fileutil
-import pyfits
-import pywcs
-import numpy as np
-import string
-
-def restoreWCS(fnames, wcskey, clobber=False):
- """
- Purpose
- =======
- Reads in a WCS defined with wcskey and saves it as the primary WCS.
- If clobber is False, writes out new files whose names are the original
- names with an attached 3 character string representing _'WCSKEY'_.
- Otherwise overwrites the files. The WCS is restored from the 'SCI'
- extension but the primary WCS of all extensions are updated.
-
- WCS keywords:
- 'CD1_1', 'CD1_2', 'CD2_1', 'CD2_2',
- 'CRVAL*',
- 'CTYPE*',
- 'CRPIX*',
- 'CDELT*',
- 'CUNIT*',
- 'ORIENTAT' - ?
- 'TDDALPHA', 'TDDBETA'
- 'A_x_x', B_x_x' - SIP coefficients
- 'CPERROR*', 'CPDIS*', 'DP*',
-
- `fnames`: a python list of file names, a string of comma separated file names,
- an @file
- `wcskey`: a charater
- Used for one of 26 alternate WCS definitions.
- `clobber`: boolean
- A flag to define if the original files should be overwritten
- """
- files = parseinput.parseinput(fnames)[0]
- for f in files:
- isfits, ftype = fileutil.isFits(f)
- if not isfits or (isfits and ftype == 'waiver'):
- print "RestoreWCS works only with true fits files."
- return
- else:
- if clobber:
- print 'Overwriting original files\n'
- fobj = pyfits.open(f, mode='update')
- name = f
- else:
- fobj = pyfits.open(f)
- name = (f.split('.fits')[0] + '_%s_' + '.fits') %wcskey
- for e in range(len(fobj)):
- try:
- extname = fobj[e].header['EXTNAME'].lower()
- except KeyError:
- continue
- #Restore always from a 'SCI' extension but write it out to 'ERR' and 'DQ'
- if extname == 'sci':
- sciver = fobj[e].header['extver']
- try:
- nwcs = pywcs.WCS(fobj[e].header, fobj=fobj, key=wcskey)
- except:
- print 'utils.restoreWCS: Could not read WCS with key %s in file %s, \
- extension %d' % (wcskey, f, e)
- return #raise
- hwcs = nwcs.to_header()
- if nwcs.wcs.has_pc():
- for c in ['1_1', '1_2', '2_1', '2_2']:
- del hwcs['CD'+c+wcskey]
- elif nwcs.wcs.has_cd():
- for c in ['1_1', '1_2', '2_1', '2_2']:
- hwcs.update(key='CD'+c+wcskey, value=hwcs['PC'+c+wcskey])
- del hwcs['PC'+c]
- for k in hwcs.keys():
- key = k[:-1]
- if key in fobj[e].header.keys():
- fobj[e].header.update(key=key, value = hwcs[k])
- else:
- continue
- if wcskey == 'O' and fobj[e].header.has_key('TDDALPHA'):
- fobj[e].header['TDDALPHA'] = 0.0
- fobj[e].header['TDDBETA'] = 0.0
- if fobj[e].header.has_key('ORIENTAT'):
- cd12 = 'CD1_2%s' % wcskey
- cd22 = 'CD2_2%s' % wcskey
- norient = np.rad2deg(np.arctan2(hwcs[cd12],hwcs[cd22]))
- fobj[e].header.update(key='ORIENTAT', value=norient)
- elif extname in ['err', 'dq', 'sdq']:
- cextver = fobj[e].header['extver']
- if cextver == sciver:
- for k in hwcs.keys():
- key = k[:-1]
- fobj[e].header.update(key=key, value = hwcs[k])
- if fobj[e].header.has_key('ORIENTAT'):
- cd12 = 'CD1_2%s' % wcskey
- cd22 = 'CD2_2%s' % wcskey
- norient = np.rad2deg(np.arctan2(hwcs[cd12],hwcs[cd22]))
- fobj[e].header.update(key='ORIENTAT', value=norient)
- else:
- continue
-
- if not clobber:
- fobj.writeto(name)
- fobj.close()
-
-def archiveWCS(fname, ext, wcskey, wcsname=" ", clobber=False):
- """
- Copy the primary WCS to an alternate WCS
- with wcskey and name WCSNAME.
- """
- assert len(wcskey) == 1
- if wcskey == " " and clobber==False:
- print "Please provide a valid wcskey for this WCS."
- print 'Use "utils.next_wcskey" to obtain a valid wcskey.'
- print 'Or use utils.restoreWCS a specific WCS to the primary WCS.'
- print 'WCS was NOT archived.'
- return
- if (wcskey not in available_wcskeys(pyfits.getheader(fname, ext=ext))) and clobber==False:
- print 'Wcskey %s is already used in this header.' % wcskey
- print 'Use "utils.next_wcskey" to obtain a valid wcskey'
- print 'or use "clobber=True" to overwrite the values.'
- return
-
- f = pyfits.open(fname, mode='update')
- w = pywcs.WCS(f[ext].header, fobj=f)
- hwcs = w.to_header()
- wkey = 'WCSNAME' + wcskey
- f[ext].header.update(key=wkey, value=wcsname)
- if w.wcs.has_pc():
- for c in ['CD1_1', 'CD1_2', 'CD2_1', 'CD2_2']:
- del hwcs[c]
- elif w.wcs.has_cd():
- for c in ['1_1', '1_2', '2_1', '2_2']:
- hwcs.update(key='CD'+c, value=hwcs['PC'+c])
- del hwcs['PC'+c]
- for k in hwcs.keys():
- key = k+wcskey
- f[ext].header.update(key=key, value = hwcs[k])
- norient = np.rad2deg(np.arctan2(hwcs['CD1_2'],hwcs['CD2_2']))
- okey = 'ORIENT%s' % wcskey
- f[ext].header.update(key=okey, value=norient)
- f.close()
-
-
def diff_angles(a,b):
"""
Perform angle subtraction a-b taking into account
@@ -168,61 +26,3 @@ def getBinning(fobj, extver=1):
binned = fobj['SCI', extver].header.get('BINAXIS',1)
return binned
-def wcsnames(header):
- """
- Purpose
- =======
- Return a dictionary of wcskey: WCSNAME pairs
- """
- names = header["WCSNAME*"]
- d = {}
- for c in names:
- d[c.key[-1]] = c.value
- return d
-
-
-def wcskeys(header):
- """
- Purpose
- =======
- Returns a list of characters used in the header for alternate
- WCS description via WCSNAME keyword
-
- `header`: pyfits.Header
- """
- names = header["WCSNAME*"]
- return [key.split('WCSNAME')[1] for key in names.keys()]
-
-def available_wcskeys(header):
- """
- Purpose
- =======
- Returns a list of characters which are not used in the header
- with WCSNAME keyword. Any of them can be used to save a new
- WCS.
-
- `header`: pyfits.Header
- """
- all_keys = list(string.ascii_uppercase)
- used_keys = wcskeys(header)
- try:
- used_keys.remove("")
- except ValueError:
- pass
- [all_keys.remove(key) for key in used_keys]
- return all_keys
-
-def next_wcskey(header):
- """
- Purpose
- =======
- Returns next available character to be used for an alternate WCS
-
- `header`: pyfits.Header
- """
- allkeys = available_wcskeys(header)
- if allkeys != []:
- return allkeys[0]
- else:
- return None
- \ No newline at end of file
diff --git a/updatewcs/__init__.py b/updatewcs/__init__.py
index b69928f..cce9c8a 100644
--- a/updatewcs/__init__.py
+++ b/updatewcs/__init__.py
@@ -2,9 +2,11 @@ from __future__ import division # confidence high
import os
import pyfits
+import numpy as np
+from stwcs import wcsutil
from stwcs.wcsutil import HSTWCS
+import pywcs
-from stwcs import utils
import corrections, makewcs
import dgeo, det2im
from pytools import parseinput, fileutil
@@ -14,7 +16,7 @@ import apply_corrections
__docformat__ = 'restructuredtext'
-__version__ = '0.5'
+__version__ = '0.8'
def updatewcs(input, vacorr=True, tddcorr=True, dgeocorr=True, d2imcorr=True,
checkfiles=True, wcskey=" ", wcsname=" ", clobber=False):
@@ -77,7 +79,7 @@ def updatewcs(input, vacorr=True, tddcorr=True, dgeocorr=True, d2imcorr=True,
tddcorr=tddcorr,dgeocorr=dgeocorr, d2imcorr=d2imcorr)
#restore the original WCS keywords
- utils.restoreWCS(f, wcskey='O', clobber=True)
+ wcsutil.restoreWCS(f, wcskey='O', clobber=True)
makecorr(f, acorr, wkey=wcskey, wname=wcsname, clobber=False)
return files
@@ -106,27 +108,28 @@ def makecorr(fname, allowed_corr, wkey=" ", wname=" ", clobber=False):
f = pyfits.open(fname, mode='update')
#Determine the reference chip and create the reference HSTWCS object
nrefchip, nrefext = getNrefchip(f)
- ref_wcs = HSTWCS(fobj=f, ext=nrefext)
- ref_wcs.readModel(update=True,header=f[nrefext].header)
- ref_wcs.copyWCS(header=f[nrefext].header, wcskey='O', wcsname='OPUS', clobber=True)
+ rwcs = HSTWCS(fobj=f, ext=nrefext)
+ rwcs.readModel(update=True,header=f[nrefext].header)
+ wcsutil.archiveWCS(f, 'O', wcsname='OPUS', ext=nrefext, clobber=True)
if 'DET2IMCorr' in allowed_corr:
det2im.DET2IMCorr.updateWCS(f)
-
+
+ # get a wcskey and wcsname from the first extension header
+ idcname = fileutil.osfn(rwcs.idctab)
+ key, name = getKeyName(f[1].header, wkey, wname, idcname)
+
for i in range(len(f))[1:]:
- # Perhaps all ext headers should be corrected (to be consistent)
extn = f[i]
if extn.header.has_key('extname'):
extname = extn.header['extname'].lower()
if extname == 'sci':
-
sciextver = extn.header['extver']
- ref_wcs.restore(f[nrefext].header, wcskey="O")
-
+ ref_wcs = rwcs.deepcopy()
hdr = extn.header
ext_wcs = HSTWCS(fobj=f, ext=i)
- ext_wcs.copyWCS(header=hdr, wcskey='O', wcsname='OPUS', clobber=True)
+ wcsutil.archiveWCS(f, "O", wcsname="OPUS", ext=[i], clobber=True)
ext_wcs.readModel(update=True,header=hdr)
for c in allowed_corr:
if c != 'DGEOCorr' and c != 'DET2IMCorr':
@@ -134,23 +137,15 @@ def makecorr(fname, allowed_corr, wkey=" ", wname=" ", clobber=False):
kw2update = corr_klass.updateWCS(ext_wcs, ref_wcs)
for kw in kw2update:
hdr.update(kw, kw2update[kw])
-
- if wkey is not None:
- # archive the updated primary WCS
- if wkey == " " :
- idcname = os.path.split(fileutil.osfn(ext_wcs.idctab))[1]
- wname = ''.join(['IDC_',idcname.split('_idc.fits')[0]])
- wkey = getKey(hdr, wname)
- #in this case clobber = true, to allow updatewcs to be run repeatedly
- ext_wcs.copyWCS(header=hdr, wcskey=wkey, wcsname=wname, clobber=True)
- else:
- #clobber is set to False as a warning to users
- ext_wcs.copyWCS(header=hdr, wcskey=wkey, wcsname=wname, clobber=False)
-
+ #if wkey is None, do not archive the primary WCS
+ if key is not None:
+ wcsutil.archiveWCS(f, key, wcsname=name, ext=[i], clobber=True)
elif extname in ['err', 'dq', 'sdq', 'samp', 'time']:
cextver = extn.header['extver']
if cextver == sciextver:
- ext_wcs.copyWCS(header=extn.header, wcskey=" ", wcsname=" ")
+ hdr = f[('SCI',sciextver)].header
+ w = pywcs.WCS(hdr, f)
+ copyWCS(w, extn.header, key, name)
else:
continue
@@ -158,22 +153,49 @@ def makecorr(fname, allowed_corr, wkey=" ", wname=" ", clobber=False):
kw2update = dgeo.DGEOCorr.updateWCS(f)
for kw in kw2update:
f[1].header.update(kw, kw2update[kw])
-
+
f.close()
-def getKey(header, wcsname):
+def getKeyName(hdr, wkey, wname, idcname):
+ if wkey is not None: # archive the primary WCS
+ if wkey == " ":
+ if wname == " " :
+ # get the next available key and use the IDCTABLE name as WCSNAME
+ idcname = os.path.split(idcname)[1]
+ name = ''.join(['IDC_',idcname.split('_idc.fits')[0]])
+ key = wcsutil.getKeyFromName(hdr, name)
+ if not key:
+ key = wcsutil.next_wcskey(hdr)
+ else:
+ #try to get a key from WCSNAME
+ # if not - get the next availabble key
+ name = wname
+ key = wcsutil.getKeyFromName(hdr, wname)
+ if not wkey:
+ key = wcsutil.next_wcskey(hdr)
+ else:
+ key = wkey
+ name = wname
+ return key, name
+
+def copyWCS(w, hdr, wkey, wname):
"""
- If WCSNAME is found in header, return its key, else return
- the next available key. This is used to update a specific WCS
- repeatedly and not generate new keys every time.
+ This is a convenience function to copy a WCS object
+ to a header as a primary WCS. It is used only to copy the
+ WCS of the 'SCI' extension to the headers of 'ERR', 'DQ', 'SDQ',
+ 'TIME' or 'SAMP' extensions.
"""
- wkey = utils.next_wcskey(header)
- names = utils.wcsnames(header)
- for item in names.items():
- if item[1] == wcsname:
- wkey = item[0]
- return wkey
-
+ hwcs = w.to_header()
+
+ if w.wcs.has_cd():
+ wcsutil.pc2cd(hwcs)
+ for k in hwcs.keys():
+ key = k+wkey
+ hdr.update(key=key, value=hwcs[k])
+ norient = np.rad2deg(np.arctan2(hwcs['CD1_2'],hwcs['CD2_2']))
+ okey = 'ORIENT%s' % wkey
+ hdr.update(key=okey, value=norient)
+
def getNrefchip(fobj):
"""
This handles the fact that WFPC2 subarray observations
diff --git a/updatewcs/apply_corrections.py b/updatewcs/apply_corrections.py
index af1a081..4eee126 100644
--- a/updatewcs/apply_corrections.py
+++ b/updatewcs/apply_corrections.py
@@ -48,7 +48,17 @@ def setCorrections(fname, vacorr=True, tddcorr=True, dgeocorr=True, d2imcorr=Tru
if 'MakeWCS' in acorr: acorr.remove('MakeWCS')
if 'CompSIP' in acorr: acorr.remove('CompSIP')
-
+ # A new IDCTAB means all previously computed WCS's are invalid
+ # We are deleting all of them except the original OPUS WCS.
+ if 'MakeWCS' in acorr and newIDCTAB(fname):
+ print "New IDCTAB file detected. This invalidates all WCS's."
+ print "Deleting all previous WCS's"
+ keys = utils.wcskeys(pyfits.getheader(fname, ext=1))
+ if 'O' in keys:
+ keys.remove('O')
+ for key in keys:
+ utils.deleteWCS(fname, key)
+
if 'VACorr' in acorr and vacorr==False: acorr.remove('VACorr')
if 'TDDCorr' in acorr:
tddcorr = applyTDDCorr(fname, tddcorr)
@@ -63,18 +73,16 @@ def setCorrections(fname, vacorr=True, tddcorr=True, dgeocorr=True, d2imcorr=Tru
return acorr
def foundIDCTAB(fname):
- idctab_found = True
try:
idctab = fileutil.osfn(pyfits.getval(fname, 'IDCTAB'))
- if idctab == 'N/A' or idctab == "":
- idctab_found = False
- if os.path.exists(idctab):
- idctab_found = True
- else:
- idctab_found = False
except KeyError:
- idctab_found = False
- return idctab_found
+ return False
+ if idctab == 'N/A' or idctab == "":
+ return False
+ if os.path.exists(idctab):
+ return True
+ else:
+ return False
def applyTDDCorr(fname, utddcorr):
"""
@@ -214,4 +222,17 @@ def applyD2ImCorr(fname, d2imcorr):
print 'D2IMFILE keyword not found in primary header'
applyD2IMCorr = False
return applyD2IMCorr
+
+def newIDCTAB(fname):
+ #When this is called we know there's a kw IDCTAB in the header
+ idctab = fileutil.osfn(pyfits.getval(fname, 'IDCTAB'))
+ try:
+ #check for the presence of IDCTAB in the first extension
+ oldidctab = fileutil.osfn(pyfits.getval(fname, 'IDCTAB', ext=1))
+ except KeyError:
+ return False
+ if idctab == oldidctab:
+ return False
+ else:
+ return True
\ No newline at end of file