def create_output(filename): fileroot, extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if not os.path.exists(fileroot): # We need to create the new file pimg = fits.HDUList() phdu = fits.PrimaryHDU() phdu.header['NDRIZIM'] = 1 pimg.append(phdu) if extn is not None: # Create a MEF file with the specified extname ehdu = fits.ImageHDU(data=arr) ehdu.header['EXTNAME'] = extname[0] ehdu.header['EXTVER'] = extname[1] pimg.append(ehdu) log.info('Creating new output file: %s' % fileroot) pimg.writeto(fileroot) del pimg else: log.info('Updating existing output file: %s' % fileroot) handle = fits.open(fileroot, mode='update', memmap=False) return handle, extname
def create_output(filename): fileroot,extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if not os.path.exists(fileroot): # We need to create the new file pimg = fits.HDUList() phdu = fits.PrimaryHDU() phdu.header['NDRIZIM'] = 1 pimg.append(phdu) if extn is not None: # Create a MEF file with the specified extname ehdu = fits.ImageHDU(data=arr) ehdu.header['EXTNAME'] = extname[0] ehdu.header['EXTVER'] = extname[1] pimg.append(ehdu) log.info('Creating new output file: %s' % fileroot) pimg.writeto(fileroot) del pimg else: log.info('Updating existing output file: %s' % fileroot) handle = fits.open(fileroot, mode='update') return handle,extname
def getHeaderHandle(self): """ Sets up the PyFITS image handle and Primary header as self.image_handle and self.header. When Pattern being used for output product, filename will be set to None and this returns None for header and image_handle. """ _numsci = 0 if self.name: _handle = fileutil.openImage(self.name,mode='readonly',memmap=self.pars['memmap']) _fname,_extn = fileutil.parseFilename(self.name) _hdr = _handle['PRIMARY'].header.copy() # Count number of SCI extensions for _fext in _handle: if 'extname' in _fext.header and _fext.header['extname'] == 'SCI': _numsci += 1 if _extn and _extn > 0: # Append correct extension/chip/group header to PRIMARY... for _card in fileutil.getExtn(_handle,_extn).header.ascard: _hdr.ascard.append(_card) else: # Default to None _handle = None _hdr = None # Set attribute to point to these products self.image_handle = None self.header = _hdr self.nmembers = _numsci return _handle
def getDGEOArrays(self): """ Return numpy objects for the distortion correction image arrays. If no DGEOFILE is specified, it will return empty 2x2 arrays. """ # Instantiate array objects for distortion correction image arrays if self.xgeoim == '': # No distortion image specified. # Defaulting to empty 2x2 array. xgdim = ygdim = 2 _pxg = np.zeros((ygdim,xgdim),dtype=np.float32) _pyg = np.zeros((ygdim,xgdim),dtype=np.float32) else: # Open distortion correction FITS file _xgfile = fileutil.openImage(self.xgeoim) #_xgfile.info() # Access the extensions which correspond to this Exposure _xgname,_xgext = fileutil.parseFilename(self.xgeoim) _ygname,_ygext = fileutil.parseFilename(self.ygeoim) _pxgext = fileutil.getExtn(_xgfile,extn=_xgext) _pygext = fileutil.getExtn(_xgfile,extn=_ygext) # Copy out the numpy objects for output _ltv1 = int(self.geometry.wcs.offset_x) _ltv2 = int(self.geometry.wcs.offset_y) if _ltv1 != 0. or _ltv2 != 0.: # subarray section only _pxg = _pxgext.data[_ltv2:_ltv2+self.naxis2,_ltv1:_ltv1+self.naxis1].copy() _pyg = _pygext.data[_ltv2:_ltv2+self.naxis2,_ltv1:_ltv1+self.naxis1].copy() else: # full array _pxg = _pxgext.data.copy() _pyg = _pygext.data.copy() # Close file handles now... _xgfile.close() del _xgfile return _pxg,_pyg
def get_data(filename): fileroot,extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if os.path.exists(fileroot): handle = fileutil.openImage(filename) data = handle[extname].data handle.close() else: data = None return data
def get_data(filename): fileroot, extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if os.path.exists(fileroot): handle = fileutil.openImage(filename, memmap=False) data = handle[extname].data handle.close() else: data = None return data
def generate_headerlet(outwcs, template, wcsname, outname=None): """ Create a headerlet based on the updated HSTWCS object This function uses 'template' as the basis for the headerlet. This file can either be the original wcspars['refimage'] or wcspars['coeffsfile'], in this order of preference. If 'template' is None, then a simple Headerlet will be generated with a single SIPWCS extension and no distortion """ # Create header object from HSTWCS object siphdr = True if outwcs.sip is None: siphdr = False outwcs_hdr = outwcs.wcs2header(sip2hdr=siphdr) outwcs_hdr['NPIX1'] = outwcs._naxis1 outwcs_hdr['NPIX2'] = outwcs._naxis2 # create headerlet object in memory; either from a file or from scratch if template is not None and siphdr: print('Creating headerlet from template...') fname, extn = fileutil.parseFilename(template) extnum = fileutil.parseExtn(extn) extname = ('sipwcs', extnum[1]) hdrlet = headerlet.createHeaderlet(fname, wcsname) # update hdrlet with header values from outwcs for kw in outwcs_hdr.items(): hdrlet[extname].header[kw[0]] = kw[1] hdrlet[extname].header['WCSNAME'] = wcsname else: print('Creating headerlet from scratch...') hdrlet = fits.HDUList() hdrlet.append(fits.PrimaryHDU()) siphdr = fits.ImageHDU(header=outwcs_hdr) siphdr.header['EXTNAME'] = 'SIPWCS' siphdr.header['WCSNAME'] = wcsname hdrlet.append(siphdr) # Write out header to a file as the final product if outname is not None: if outname.find('_hdr.fits') < 0: outname += '_hdr.fits' if os.path.exists(outname): print('Overwrite existing file "%s"' % outname) os.remove(outname) hdrlet.writeto(outname) print('Wrote out headerlet :', outname)
def generate_headerlet(outwcs,template,wcsname,outname=None): """ Create a headerlet based on the updated HSTWCS object This function uses 'template' as the basis for the headerlet. This file can either be the original wcspars['refimage'] or wcspars['coeffsfile'], in this order of preference. If 'template' is None, then a simple Headerlet will be generated with a single SIPWCS extension and no distortion """ # Create header object from HSTWCS object siphdr = True if outwcs.sip is None: siphdr = False outwcs_hdr = outwcs.wcs2header(sip2hdr=siphdr) outwcs_hdr['NPIX1'] = outwcs._naxis1 outwcs_hdr['NPIX2'] = outwcs._naxis2 # create headerlet object in memory; either from a file or from scratch if template is not None and siphdr: print('Creating headerlet from template...') fname,extn = fileutil.parseFilename(template) extnum = fileutil.parseExtn(extn) extname = ('sipwcs',extnum[1]) hdrlet = headerlet.createHeaderlet(fname,wcsname) # update hdrlet with header values from outwcs for kw in outwcs_hdr.items(): hdrlet[extname].header[kw[0]] = kw[1] hdrlet[extname].header['WCSNAME'] = wcsname else: print('Creating headerlet from scratch...') hdrlet = fits.HDUList() hdrlet.append(fits.PrimaryHDU()) siphdr = fits.ImageHDU(header=outwcs_hdr) siphdr.header['EXTNAME'] = 'SIPWCS' siphdr.header['WCSNAME'] = wcsname hdrlet.append(siphdr) # Write out header to a file as the final product if outname is not None: if outname.find('_hdr.fits') < 0: outname += '_hdr.fits' if os.path.exists(outname): print('Overwrite existing file "%s"'%outname) os.remove(outname) hdrlet.writeto(outname) print('Wrote out headerlet :',outname)
def convertImageToSFITS(fname): """ Convert the input filename (possibly with extensions already specified) into a separate simple FITS file for each SCI extension. If fname refers to a simple FITS file already, list will only contain fname. """ flist = [] # Extract any extension specifications rootname, extn = fileutil.parseFilename(fname) if extn == None: # Check to see if file is multi-extension fimg = fileutil.openImage(fname) if len(fimg) > 1: # We have multiextension FITS, so write out # each SCI extension as a separate simple # FITS file. for hdu in fimg: if 'extname' in hdu.header and hdu.header['extname'] == 'SCI': extname = hdu.header['extname'].lower() + str( hdu.header['extver']) new_fname = rootname[:rootname.rfind( '.fits')] + '_extract_' + extname + '.fits' removeFile(new_fname) flist.append([new_fname, fname]) phdu = pyfits.PrimaryHDU(header=hdu.header, data=hdu.data) phdu.writeto(new_fname) del phdu else: # We already have a simple FITS, just record its name flist.append([None, fname]) fimg.close() del fimg else: # We have an image with a SCI extension specified split_extn = extn.split(',') extname = str(split_extn[0]) + str(split_extn[1]) new_fname = rootname[:rootname. rfind('.fits')] + '_extract_' + extname + '.fits' removeFile(new_fname) iraf.imcopy(fname, new_fname, verbose=no) flist.append([new_fname, fname]) return flist
def buildName(fname, keepext=no, coord_suffix='.coord'): """ For a given filename, build filename for the coords file. """ froot, fext = fileutil.parseFilename(fname) froot_name = froot[:froot.rfind('.')] if keepext == no: fcoord_name = froot_name + coord_suffix else: if fext != None: fext = fext.replace(',', '') else: fext = '' fcoord_name = froot_name + '_' + fext + coord_suffix removeFile(fcoord_name) return fcoord_name
def parseSingleInput(f=None, ext=None): if isinstance(f, str): # create an HSTWCS object from a filename if ext is not None: filename = f if isinstance(ext, tuple): if ext[0] == '': extnum = ext[1] # handle ext=('',1) else: extnum = ext else: extnum = int(ext) elif ext is None: filename, ext = fileutil.parseFilename(f) ext = fileutil.parseExtn(ext) if ext[0] == '': extnum = int(ext[1]) # handle ext=('',extnum) else: extnum = ext phdu = fits.open(filename) hdr0 = phdu[0].header try: ehdr = phdu[extnum].header except (IndexError, KeyError) as e: raise e.__class__('Unable to get extension %s.' % extnum) elif isinstance(f, fits.HDUList): phdu = f if ext is None: extnum = 0 else: extnum = ext ehdr = f[extnum].header hdr0 = f[0].header filename = hdr0.get('FILENAME', "") else: raise ValueError('Input must be a file name string or a' '`astropy.io.fits.HDUList` object') return filename, hdr0, ehdr, phdu
def findWCSExtn(filename): """ Return new filename with extension that points to an extension with a valid WCS. Returns ======= extnum : str, None Value of extension name as a string either as provided by the user or based on the extension number for the first extension which contains a valid HSTWCS object. Returns None if no extension can be found with a valid WCS. Notes ===== The return value from this function can be used as input to create another HSTWCS with the syntax:: `HSTWCS('{}[{}]'.format(filename,extnum)) """ rootname,extroot = fileutil.parseFilename(filename) extnum = None if extroot is None: fimg = fits.open(rootname, memmap=False) for i,extn in enumerate(fimg): if 'crval1' in extn.header: refwcs = wcsutil.HSTWCS('{}[{}]'.format(rootname,i)) if refwcs.wcs.has_cd(): extnum = '{}'.format(i) break fimg.close() else: try: refwcs = wcsutil.HSTWCS(filename) if refwcs.wcs.has_cd(): extnum = extroot except: extnum = None return extnum
def findWCSExtn(filename): """ Return new filename with extension that points to an extension with a valid WCS. Returns ======= extnum : str, None Value of extension name as a string either as provided by the user or based on the extension number for the first extension which contains a valid HSTWCS object. Returns None if no extension can be found with a valid WCS. Notes ===== The return value from this function can be used as input to create another HSTWCS with the syntax:: `HSTWCS('{}[{}]'.format(filename,extnum)) """ rootname, extroot = fileutil.parseFilename(filename) extnum = None if extroot is None: fimg = fits.open(rootname, memmap=False) for i, extn in enumerate(fimg): if 'crval1' in extn.header: refwcs = wcsutil.HSTWCS('{}[{}]'.format(rootname, i)) if refwcs.wcs.has_cd(): extnum = '{}'.format(i) break fimg.close() else: try: refwcs = wcsutil.HSTWCS(filename) if refwcs.wcs.has_cd(): extnum = extroot except: extnum = None return extnum
def verifyRefimage(refimage): """ Verify that the value of refimage specified by the user points to an extension with a proper WCS defined. It starts by making sure an extension gets specified by the user when using a MEF file. The final check comes by looking for a CD matrix in the WCS object itself. If either test fails, it returns a value of False. """ valid = True # start by trying to see whether the code can even find the file if is_blank(refimage): return True if isinstance(refimage, astropy.wcs.WCS): return True refroot, extroot = fileutil.parseFilename(refimage) if not os.path.exists(refroot): return False # if a MEF has been specified, make sure extension contains a valid WCS if valid: if extroot is None: extn = findWCSExtn(refimage) if extn is None: valid = False else: valid = True else: # check for CD matrix in WCS object refwcs = wcsutil.HSTWCS(refimage) if not refwcs.wcs.has_cd(): valid = False else: valid = True del refwcs return valid
def verifyRefimage(refimage): """ Verify that the value of refimage specified by the user points to an extension with a proper WCS defined. It starts by making sure an extension gets specified by the user when using a MEF file. The final check comes by looking for a CD matrix in the WCS object itself. If either test fails, it returns a value of False. """ valid = True # start by trying to see whether the code can even find the file if is_blank(refimage): valid=True return valid refroot,extroot = fileutil.parseFilename(refimage) if not os.path.exists(refroot): valid = False return valid # if a MEF has been specified, make sure extension contains a valid WCS if valid: if extroot is None: extn = findWCSExtn(refimage) if extn is None: valid = False else: valid = True else: # check for CD matrix in WCS object refwcs = wcsutil.HSTWCS(refimage) if not refwcs.wcs.has_cd(): valid = False else: valid = True del refwcs return valid
def run_blot(imageObjectList, output_wcs, paramDict, wcsmap=wcs_functions.WCSMap): """ run_blot(imageObjectList, output_wcs, paramDict, wcsmap=wcs_functions.WCSMap) Perform the blot operation on the list of images. """ # Insure that input imageObject is a list if not isinstance(imageObjectList, list): imageObjectList = [imageObjectList] # # Setup the versions info dictionary for output to PRIMARY header # The keys will be used as the name reported in the header, as-is # _versions = { 'AstroDrizzle': __version__, 'PyFITS': util.__fits_version__, 'Numpy': util.__numpy_version__ } _hdrlist = [] for img in imageObjectList: for chip in img.returnAllChips(extname=img.scienceExt): print(' Blot: creating blotted image: ', chip.outputNames['data']) #### Check to see what names need to be included here for use in _hdrlist chip.outputNames['driz_version'] = _versions['AstroDrizzle'] outputvals = chip.outputNames.copy() outputvals.update(img.outputValues) outputvals['blotnx'] = chip.wcs.naxis1 outputvals['blotny'] = chip.wcs.naxis2 _hdrlist.append(outputvals) plist = outputvals.copy() plist.update(paramDict) # PyFITS can be used here as it will always operate on # output from PyDrizzle (which will always be a FITS file) # Open the input science file medianPar = 'outMedian' outMedianObj = img.getOutputName(medianPar) if img.inmemory: outMedian = img.outputNames[medianPar] _fname, _sciextn = fileutil.parseFilename(outMedian) _inimg = outMedianObj else: outMedian = outMedianObj _fname, _sciextn = fileutil.parseFilename(outMedian) _inimg = fileutil.openImage(_fname, memmap=False) # Return the PyFITS HDU corresponding to the named extension _scihdu = fileutil.getExtn(_inimg, _sciextn) _insci = _scihdu.data.copy() _inimg.close() del _inimg, _scihdu _outsci = do_blot(_insci, output_wcs, chip.wcs, chip._exptime, coeffs=paramDict['coeffs'], interp=paramDict['blot_interp'], sinscl=paramDict['blot_sinscl'], wcsmap=wcsmap) # Apply sky subtraction and unit conversion to blotted array to # match un-modified input array if paramDict['blot_addsky']: skyval = chip.computedSky else: skyval = paramDict['blot_skyval'] _outsci /= chip._conversionFactor if skyval is not None: _outsci += skyval log.info('Applying sky value of %0.6f to blotted image %s' % (skyval, chip.outputNames['data'])) # Write output Numpy objects to a PyFITS file # Blotting only occurs from a drizzled SCI extension # to a blotted SCI extension... _outimg = outputimage.OutputImage(_hdrlist, paramDict, build=False, wcs=chip.wcs, blot=True) _outimg.outweight = None _outimg.outcontext = None outimgs = _outimg.writeFITS(plist['data'], _outsci, None, versions=_versions, blend=False, virtual=img.inmemory) img.saveVirtualOutputs(outimgs) #_buildOutputFits(_outsci,None,plist['outblot']) _hdrlist = [] del _outsci del _outimg
def run(configObj, wcsmap=None): """ Interface for running `wdrizzle` from TEAL or Python command-line. This code performs all file ``I/O`` to set up the use of the drizzle code for a single exposure to replicate the functionality of the original `wdrizzle`. """ # Insure all output filenames specified have .fits extensions if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits' if not util.is_blank( configObj['outweight']) and configObj['outweight'][-5:] != '.fits': configObj['outweight'] += '.fits' if not util.is_blank(configObj['outcontext'] ) and configObj['outcontext'][-5:] != '.fits': configObj['outcontext'] += '.fits' # Keep track of any files we need to open in_sci_handle = None in_wht_handle = None out_sci_handle = None out_wht_handle = None out_con_handle = None _wcskey = configObj['wcskey'] if util.is_blank(_wcskey): _wcskey = ' ' scale_pars = configObj['Data Scaling Parameters'] user_wcs_pars = configObj['User WCS Parameters'] # Open the SCI (and WHT?) image # read file to get science array insci = get_data(configObj['input']) expin = fileutil.getKeyword(configObj['input'], scale_pars['expkey']) in_sci_phdr = fits.getheader(fileutil.parseFilename(configObj['input'])[0], memmap=False) # we need to read in the input WCS input_wcs = stwcs.wcsutil.HSTWCS(configObj['input'], wcskey=_wcskey) if not util.is_blank(configObj['inweight']): inwht = get_data(configObj['inweight']).astype(np.float32) else: # Generate a default weight map of all good pixels inwht = np.ones(insci.shape, dtype=insci.dtype) output_exists = False outname = fileutil.osfn(fileutil.parseFilename(configObj['outdata'])[0]) if os.path.exists(outname): output_exists = True # Output was specified as a filename, so open it in 'update' mode outsci = get_data(configObj['outdata']) if output_exists: # we also need to read in the output WCS from pre-existing output output_wcs = stwcs.wcsutil.HSTWCS(configObj['outdata']) out_sci_hdr = fits.getheader(outname, memmap=False) outexptime = out_sci_hdr['DRIZEXPT'] if 'ndrizim' in out_sci_hdr: uniqid = out_sci_hdr['ndrizim'] + 1 else: uniqid = 1 else: # otherwise, define the output WCS either from user pars or refimage if util.is_blank(configObj['User WCS Parameters']['refimage']): # Define a WCS based on user provided WCS values # NOTE: # All parameters must be specified, not just one or a few if not util.is_blank(user_wcs_pars['outscale']): output_wcs = wcs_functions.build_hstwcs( user_wcs_pars['raref'], user_wcs_pars['decref'], user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'], int(user_wcs_pars['outnx']), int(user_wcs_pars['outny']), user_wcs_pars['outscale'], user_wcs_pars['orient']) else: # Define default WCS based on input image applydist = True if input_wcs.sip is None or input_wcs.instrument == 'DEFAULT': applydist = False output_wcs = stwcs.distortion.utils.output_wcs( [input_wcs], undistort=applydist) else: refimage = configObj['User WCS Parameters']['refimage'] refroot, extroot = fileutil.parseFilename(refimage) if extroot is None: fimg = fits.open(refroot, memmap=False) for i, extn in enumerate(fimg): if 'CRVAL1' in extn.header: # Key on CRVAL1 for valid WCS refwcs = stwcs.wcsutil.HSTWCS('{}[{}]'.format( refroot, i)) if refwcs.wcs.has_cd(): extroot = i break fimg.close() # try to find extension with valid WCS refimage = "{}[{}]".format(refroot, extroot) # Define the output WCS based on a user specified reference image WCS output_wcs = stwcs.wcsutil.HSTWCS(refimage) # Initialize values used for combining results outexptime = 0.0 uniqid = 1 # Set up the output data array and insure that the units for that array is 'cps' if outsci is None: # Define a default blank array based on definition of output_wcs outsci = np.empty(output_wcs.array_shape, dtype=np.float32) outsci.fill(np.nan) else: # Convert array to units of 'cps', if needed if outexptime != 0.0: np.divide(outsci, outexptime, outsci) outsci = outsci.astype(np.float32) # Now update output exposure time for additional input file outexptime += expin outwht = None if not util.is_blank(configObj['outweight']): outwht = get_data(configObj['outweight']) if outwht is None: outwht = np.zeros(output_wcs.array_shape, dtype=np.float32) else: outwht = outwht.astype(np.float32) outcon = None keep_con = False if not util.is_blank(configObj['outcontext']): outcon = get_data(configObj['outcontext']) keep_con = True if outcon is None: outcon = np.zeros((1, ) + output_wcs.array_shape, dtype=np.int32) else: outcon = outcon.astype(np.int32) planeid = int((uniqid - 1) / 32) # Add a new plane to the context image if planeid overflows while outcon.shape[0] <= planeid: plane = np.zeros_like(outcon[0]) outcon = np.append(outcon, plane, axis=0) # Interpret wt_scl parameter if configObj['wt_scl'] == 'exptime': wt_scl = expin elif configObj['wt_scl'] == 'expsq': wt_scl = expin * expin else: wt_scl = float(configObj['wt_scl']) # Interpret coeffs parameter to determine whether to apply coeffs or not undistort = True if not configObj[ 'coeffs'] or input_wcs.sip is None or input_wcs.instrument == 'DEFAULT': undistort = False # turn off use of coefficients if undistort is False (coeffs == False) if not undistort: input_wcs.sip = None input_wcs.cpdis1 = None input_wcs.cpdis2 = None input_wcs.det2im = None wcslin = distortion.utils.output_wcs([input_wcs], undistort=undistort) # Perform actual drizzling now... _vers = do_driz(insci, input_wcs, inwht, output_wcs, outsci, outwht, outcon, expin, scale_pars['in_units'], wt_scl, wcslin_pscale=wcslin.pscale, uniqid=uniqid, pixfrac=configObj['pixfrac'], kernel=configObj['kernel'], fillval=scale_pars['fillval'], stepsize=configObj['stepsize'], wcsmap=None) out_sci_handle, outextn = create_output(configObj['outdata']) if not output_exists: # Also, define default header based on input image Primary header out_sci_handle[outextn].header = in_sci_phdr.copy() # Update header of output image with exptime used to scale the output data # if out_units is not counts, this will simply be a value of 1.0 # the keyword 'exptime' will always contain the total exposure time # of all input image regardless of the output units out_sci_handle[outextn].header['EXPTIME'] = outexptime # create CTYPE strings ctype1 = input_wcs.wcs.ctype[0] ctype2 = input_wcs.wcs.ctype[1] if ctype1.find('-SIP'): ctype1 = ctype1.replace('-SIP', '') if ctype2.find('-SIP'): ctype2 = ctype2.replace('-SIP', '') # Update header with WCS keywords out_sci_handle[outextn].header['ORIENTAT'] = output_wcs.orientat out_sci_handle[outextn].header['CD1_1'] = output_wcs.wcs.cd[0][0] out_sci_handle[outextn].header['CD1_2'] = output_wcs.wcs.cd[0][1] out_sci_handle[outextn].header['CD2_1'] = output_wcs.wcs.cd[1][0] out_sci_handle[outextn].header['CD2_2'] = output_wcs.wcs.cd[1][1] out_sci_handle[outextn].header['CRVAL1'] = output_wcs.wcs.crval[0] out_sci_handle[outextn].header['CRVAL2'] = output_wcs.wcs.crval[1] out_sci_handle[outextn].header['CRPIX1'] = output_wcs.wcs.crpix[0] out_sci_handle[outextn].header['CRPIX2'] = output_wcs.wcs.crpix[1] out_sci_handle[outextn].header['CTYPE1'] = ctype1 out_sci_handle[outextn].header['CTYPE2'] = ctype2 out_sci_handle[outextn].header['VAFACTOR'] = 1.0 if scale_pars['out_units'] == 'counts': np.multiply(outsci, outexptime, outsci) out_sci_handle[outextn].header['DRIZEXPT'] = outexptime else: out_sci_handle[outextn].header['DRIZEXPT'] = 1.0 # Update header keyword NDRIZIM to keep track of how many images have # been combined in this product so far out_sci_handle[outextn].header['NDRIZIM'] = uniqid # define keywords to be written out to product header drizdict = outputimage.DRIZ_KEYWORDS.copy() # Update drizdict with current values drizdict['VER']['value'] = _vers[:44] drizdict['DATA']['value'] = configObj['input'][:64] drizdict['DEXP']['value'] = expin drizdict['OUDA']['value'] = configObj['outdata'][:64] drizdict['OUWE']['value'] = configObj['outweight'][:64] drizdict['OUCO']['value'] = configObj['outcontext'][:64] drizdict['MASK']['value'] = configObj['inweight'][:64] drizdict['WTSC']['value'] = wt_scl drizdict['KERN']['value'] = configObj['kernel'] drizdict['PIXF']['value'] = configObj['pixfrac'] drizdict['OUUN']['value'] = scale_pars['out_units'] drizdict['FVAL']['value'] = scale_pars['fillval'] drizdict['WKEY']['value'] = configObj['wcskey'] outputimage.writeDrizKeywords(out_sci_handle[outextn].header, uniqid, drizdict) # add output array to output file out_sci_handle[outextn].data = outsci out_sci_handle.close() if not util.is_blank(configObj['outweight']): out_wht_handle, outwhtext = create_output(configObj['outweight']) out_wht_handle[outwhtext].header = out_sci_handle[outextn].header.copy( ) out_wht_handle[outwhtext].data = outwht out_wht_handle.close() if keep_con: out_con_handle, outconext = create_output(configObj['outcontext']) out_con_handle[outconext].data = outcon out_con_handle.close()
def tran(inimage, outimage, direction='forward', x=None, y=None, coordfile=None, colnames=None, separator=None, precision=6, output=None, verbose=True): """ Primary interface to perform coordinate transformations in pixel coordinates between 2 images using STWCS and full distortion models read from each image's header. """ single_coord = False if coordfile is None: if isinstance(x, np.ndarray): xlist = x.tolist() ylist = y.tolist() elif not isinstance(x, list): xlist = [x] ylist = [y] single_coord = True else: xlist = x ylist = y else: if colnames in util.blank_list: colnames = ['c1', 'c2'] # Determine columns which contain pixel positions cols = util.parse_colnames(colnames, coordfile) # read in columns from input coordinates file xyvals = np.loadtxt(coordfile, usecols=cols, delimiter=separator) if xyvals.ndim == 1: # only 1 entry in coordfile xlist = [xyvals[0].copy()] ylist = [xyvals[1].copy()] else: xlist = xyvals[:, 0].copy() ylist = xyvals[:, 1].copy() # start by reading in WCS+distortion info for each image im1wcs = wcsutil.HSTWCS(inimage) if im1wcs.wcs.is_unity(): print("####\nNo valid input WCS found in '{}'." "\n Results may be invalid.\n####\n".format(inimage)) if util.is_blank(outimage): fname, fextn = fileutil.parseFilename(inimage) numsci = fileutil.countExtn(fname) chips = [ wcsutil.HSTWCS(fname, ext=('sci', e + 1)) for e in range(numsci) ] if len(chips) == 0: chips = [im1wcs] im2wcs = distortion.utils.output_wcs(chips) else: im2wcs = wcsutil.HSTWCS(outimage) if im2wcs.wcs.is_unity(): print("####\nNo valid output WCS found in '{}'." "\n Results may be invalid.\n####\n".format(outimage)) # Setup the transformation p2p = wcs_functions.WCSMap(im1wcs, im2wcs) if direction[0].lower() == 'f': outx, outy = p2p.forward(xlist, ylist) else: outx, outy = p2p.backward(xlist, ylist) if isinstance(outx, np.ndarray): outx = outx.tolist() outy = outy.tolist() # add formatting based on precision here... xstr = [] ystr = [] for ox, oy in zip(outx, outy): xstr.append('{0:.{1}f}'.format(ox, precision)) ystr.append('{0:.{1}f}'.format(oy, precision)) if verbose: print('# Coordinate transformations for ', inimage) print('# X(in) Y(in) X(out) Y(out)\n') for xs, ys, a, b in zip(xlist, ylist, xstr, ystr): print("%.4f %.4f %s %s" % (xs, ys, a, b)) # Create output file, if specified if output: with open(output, mode='w') as f: f.write("# Coordinates converted from %s\n" % inimage) for xs, ys in zip(xstr, ystr): f.write('%s %s\n' % (xs, ys)) print('Wrote out results to: ', output) if single_coord: outx = outx[0] outy = outy[0] return outx, outy
def tran(inimage, outimage, direction='forward', x=None, y=None, coords=None, coordfile=None, colnames=None, separator=None, precision=6, output=None, verbose=True): """ Primary interface to perform coordinate transformations in pixel coordinates between 2 images using STWCS and full distortion models read from each image's header. """ single_coord = False # Only use value provided in `coords` if nothing has been specified for coordfile if coords is not None and coordfile is None: coordfile = coords warnings.simplefilter('always', DeprecationWarning) warnings.warn( "Please update calling code to pass in `coordfile` instead of `coords`.", category=DeprecationWarning) warnings.simplefilter('default', DeprecationWarning) if coordfile is not None: if colnames in util.blank_list: colnames = ['c1', 'c2'] # Determine columns which contain pixel positions cols = util.parse_colnames(colnames, coordfile) # read in columns from input coordinates file xyvals = np.loadtxt(coordfile, usecols=cols, delimiter=separator) if xyvals.ndim == 1: # only 1 entry in coordfile xlist = [xyvals[0].copy()] ylist = [xyvals[1].copy()] else: xlist = xyvals[:, 0].copy() ylist = xyvals[:, 1].copy() del xyvals else: if isinstance(x, np.ndarray): xlist = x.tolist() ylist = y.tolist() elif not isinstance(x, list): xlist = [x] ylist = [y] single_coord = True else: xlist = x ylist = y # start by reading in WCS+distortion info for each image im1wcs = wcsutil.HSTWCS(inimage) if im1wcs.wcs.is_unity(): print( "####\nNo valid input WCS found in {}.\n Results may be invalid.\n####\n" .format(inimage)) if util.is_blank(outimage): fname, fextn = fileutil.parseFilename(inimage) numsci = fileutil.countExtn(fname) chips = [] for e in range(1, numsci + 1): chips.append(wcsutil.HSTWCS(fname, ext=('sci', e))) if len(chips) == 0: chips = [im1wcs] im2wcs = distortion.utils.output_wcs(chips) else: im2wcs = wcsutil.HSTWCS(outimage) if im2wcs.wcs.is_unity(): print( "####\nNo valid output WCS found in {}.\n Results may be invalid.\n####\n" .format(outimage)) # Setup the transformation p2p = wcs_functions.WCSMap(im1wcs, im2wcs) if direction[0].lower() == 'f': outx, outy = p2p.forward(xlist, ylist) else: outx, outy = p2p.backward(xlist, ylist) if isinstance(outx, np.ndarray): outx = outx.tolist() outy = outy.tolist() # add formatting based on precision here... xstr = [] ystr = [] fmt = "%." + repr(precision) + "f" for ox, oy in zip(outx, outy): xstr.append(fmt % ox) ystr.append(fmt % oy) if verbose or (not verbose and util.is_blank(output)): print('# Coordinate transformations for ', inimage) print('# X(in) Y(in) X(out) Y(out)\n') for xs, ys, a, b in zip(xlist, ylist, xstr, ystr): print("%.4f %.4f %s %s" % (xs, ys, a, b)) # Create output file, if specified if output: f = open(output, mode='w') f.write("# Coordinates converted from %s\n" % inimage) for xs, ys in zip(xstr, ystr): f.write('%s %s\n' % (xs, ys)) f.close() print('Wrote out results to: ', output) if single_coord: outx = outx[0] outy = outy[0] return outx, outy
def getTemplates(fname,extlist): # Obtain default headers for output file # If the output file already exists, use it # If not, use an input file for this information. # # NOTE: Returns 'pyfits.Header' objects, not HDU objects! # if fname == None: print('No data files for creating FITS output.') raise Exception froot,fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot,mode='readonly') prihdr = pyfits.Header(cards=ftemplate['PRIMARY'].header.ascard.copy()) del prihdr['pcount'] del prihdr['gcount'] if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) else: extnum = (extlist[0],fnum) scihdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr.update('extver',1) if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) errhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr.update('extver',1) if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) dqhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr.update('extver',1) else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate # Now, safeguard against having BSCALE and BZERO try: del scihdr['bscale'] del scihdr['bzero'] del errhdr['bscale'] del errhdr['bzero'] del dqhdr['bscale'] del dqhdr['bzero'] except: # If these don't work, they didn't exist to start with... pass # At this point, check errhdr and dqhdr to make sure they # have all the requisite keywords (as listed in updateDTHKeywords). # Simply copy them from scihdr if they don't exist... if errhdr != None and dqhdr != None: for keyword in DTH_KEYWORDS: if keyword not in errhdr: errhdr.update(keyword,scihdr[keyword]) if keyword not in dqhdr: dqhdr.update(keyword,scihdr[keyword]) return prihdr,scihdr,errhdr,dqhdr
def runDriz(self,pixfrac=1.0,kernel='turbo',fillval='INDEF'): """ Runs the 'drizzle' algorithm on this specific chip to create a numpy object of the undistorted image. The resulting drizzled image gets returned as a numpy object. """ # # Perform drizzling... # _wcs = self.geometry.wcs _wcsout = self.product_wcs # Rigorously compute the orientation changes from WCS # information using algorithm provided by R. Hook from WDRIZZLE. abxt,cdyt = drutil.wcsfit(self.geometry, self.product_wcs) # Compute the rotation and shifts between input and reference WCS. xsh = abxt[2] ysh = cdyt[2] rot = fileutil.RADTODEG(np.arctan2(abxt[1],cdyt[0])) scale = self.product_wcs.pscale / self.geometry.wcslin.pscale # Now, trim the final output to only match this chip _out_naxis1,_out_naxis2 = self.chip_shape # # Insure that the coeffs file was created # if not os.path.exists(self.coeffs): self.writeCoeffs() # A image buffer needs to be setup for converting the input # arrays (sci and wht) from FITS format to native format # with respect to byteorder and byteswapping. # This buffer should be reused for each input. # _outsci = np.zeros((_out_naxis2,_out_naxis1),dtype=np.float32) _outwht = np.zeros((_out_naxis2,_out_naxis1),dtype=np.float32) _inwcs = np.zeros([8],dtype=np.float64) # Only one chip will ever be drizzled using this method, so # the context image will only ever contain 1 bit-plane _outctx = np.zeros((_out_naxis2,_out_naxis1),dtype=np.int32) # Read in the distortion correction arrays, if specifij8cw08n4q_raw.fitsed _pxg,_pyg = self.getDGEOArrays() # Open the SCI image _expname = self.name _handle = fileutil.openImage(_expname,mode='readonly',memmap=0) _fname,_extn = fileutil.parseFilename(_expname) _sciext = fileutil.getExtn(_handle,extn=_extn) # Make a local copy of SCI array and WCS info #_insci = _sciext.data.copy() _inwcs = drutil.convertWCS(wcsutil.WCSObject(_fname,header=_sciext.header),_inwcs) # Compute what plane of the context image this input would # correspond to: _planeid = 1 # Select which mask needs to be read in for drizzling _inwht = np.ones((self.naxis2,self.naxis1),dtype=np.float32) # Default case: wt_scl = exptime _wtscl = self.exptime # Set additional parameters needed by 'drizzle' _expin = self.exptime #_in_un = 'counts' #_shift_fr = 'output' #_shift_un = 'output' _uniqid = 1 ystart = 0 nmiss = 0 nskip = 0 _vers = '' # # This call to 'arrdriz.tdriz' uses the F2C syntax # _dny = self.naxis2 # Call 'drizzle' to perform image combination _vers,nmiss,nskip = arrdriz.tdriz(_sciext.data.copy(),_inwht, _outsci, _outwht, _outctx, _uniqid, ystart, 1, 1, _dny, xsh,ysh, 'output','output', rot,scale, self.xsh2,self.ysh2, 1.0, 1.0, 0.0, 'output', _pxg,_pyg, 'center', pixfrac, kernel, self.coeffs, 'counts', _expin,_wtscl, fillval, _inwcs, nmiss, nskip, 1,0.,0.) # # End of F2C syntax # if nmiss > 0: print('! Warning, ',nmiss,' points were outside the output image.') if nskip > 0: print('! Note, ',nskip,' input lines were skipped completely.') # Close image handle _handle.close() del _handle,_fname,_extn,_sciext del _inwht del _pxg,_pyg del _outwht,_outctx return _outsci
def updateShifts(tabname, shiftfile, mode='replace', clean=no): """ Update an ASN table with shifts provided in shiftfile. The 'units', 'frame', and 'reference' will all be derived from the shiftfile itself, with defaults set by 'readShiftFile'. If 'clean' == yes, then remove the shiftfile and any reference WCS file after they have been used to update the ASN table. """ # Read in the shifts from the shiftfile sdict = asnutil.ShiftFile(shiftfile) # Apply user-specified values # Values from shiftfile ALWAYS take precedence if 'units' in sdict: _units = sdict['units'] else: _units = None if 'frame' in sdict: _frame = sdict['frame'] else: _frame = None _reference = sdict['refimage'] if _frame == 'output' and _reference == None: # No reference frame specified, yet shifts given in # output units, so raise an Exception print("No reference image provided for shifts given in output units!") raise ValueError # Extract list of rootnames from ASN table ftab = pyfits.open(tabname) fnames = ftab[1].data.field('memname') ftab.close() del ftab # For each rootname in ASN table, apply shifts from shiftfile for mname in fnames: _lname = mname.lower() for key in sdict.keys(): # Is this key the one that goes with 'mname'? if key.find(_lname) > -1: _s = sdict[key] updateAsnTable(tabname, mname, xsh=_s[0], ysh=_s[1], rot=_s[2], scale=_s[3], form=sdict['form'], frame=_frame, units=_units, output=_reference, mode=mode) # If we have a new reference image, update header keyword to point # to appended WCS object if _reference != None: # Append reference WCS to ASN table whdu = wcsutil.WCSObject(_reference) whdu.createReferenceWCS(tabname, overwrite=no) # Now update ASN header to point to new reference WCS ftab = pyfits.open(tabname, mode='update') ftab['primary'].header.update('refimage', tabname + "[wcs]") ftab.close() del ftab del whdu # If user specifies, remove shiftfile and reference WCS # after it has been appended to ASN table. if clean == yes: os.remove(shiftfile) if _reference != None: _refname, _refextn = fileutil.parseFilename(_reference) os.remove(_refname)
def writeSingleFITS(data,wcs,output,template,clobber=True,verbose=True): """ Write out a simple FITS file given a numpy array and the name of another FITS file to use as a template for the output image header. """ outname,outextn = fileutil.parseFilename(output) outextname,outextver = fileutil.parseExtn(outextn) if fileutil.findFile(outname): if clobber: log.info('Deleting previous output product: %s' % outname) fileutil.removeFile(outname) else: log.warning('Output file %s already exists and overwrite not ' 'specified!' % outname) log.error('Quitting... Please remove before resuming operations.') raise IOError # Now update WCS keywords with values from provided WCS if hasattr(wcs.sip,'a_order'): siphdr = True else: siphdr = False wcshdr = wcs.wcs2header(sip2hdr=siphdr) if template is not None: # Get default headers from multi-extension FITS file # If input data is not in MEF FITS format, it will return 'None' # NOTE: These are HEADER objects, not HDUs (prihdr,scihdr,errhdr,dqhdr),newtab = getTemplates(template,EXTLIST) if scihdr is None: scihdr = fits.Header() indx = 0 for c in prihdr.cards: if c.keyword not in ['INHERIT','EXPNAME']: indx += 1 else: break for i in range(indx,len(prihdr)): scihdr.append(prihdr.cards[i]) for i in range(indx, len(prihdr)): del prihdr[indx] else: scihdr = fits.Header() prihdr = fits.Header() # Start by updating PRIMARY header keywords... prihdr.set('EXTEND', value=True, after='NAXIS') prihdr['FILENAME'] = outname if outextname == '': outextname = 'sci' if outextver == 0: outextver = 1 scihdr['EXTNAME'] = outextname.upper() scihdr['EXTVER'] = outextver for card in wcshdr.cards: scihdr[card.keyword] = (card.value, card.comment) # Create PyFITS HDUList for all extensions outhdu = fits.HDUList() # Setup primary header as an HDU ready for appending to output FITS file prihdu = fits.PrimaryHDU(header=prihdr) scihdu = fits.ImageHDU(header=scihdr,data=data) outhdu.append(prihdu) outhdu.append(scihdu) outhdu.writeto(outname) if verbose: print('Created output image: %s' % outname)
def run_blot(imageObjectList,output_wcs,paramDict,wcsmap=wcs_functions.WCSMap): """ run_blot(imageObjectList, output_wcs, paramDict, wcsmap=wcs_functions.WCSMap) Perform the blot operation on the list of images. """ # Insure that input imageObject is a list if not isinstance(imageObjectList, list): imageObjectList = [imageObjectList] # # Setup the versions info dictionary for output to PRIMARY header # The keys will be used as the name reported in the header, as-is # _versions = {'AstroDrizzle':__version__, 'PyFITS':util.__fits_version__, 'Numpy':util.__numpy_version__} _hdrlist = [] for img in imageObjectList: for chip in img.returnAllChips(extname=img.scienceExt): print(' Blot: creating blotted image: ',chip.outputNames['data']) #### Check to see what names need to be included here for use in _hdrlist chip.outputNames['driz_version'] = _versions['AstroDrizzle'] outputvals = chip.outputNames.copy() outputvals.update(img.outputValues) outputvals['blotnx'] = chip.wcs.naxis1 outputvals['blotny'] = chip.wcs.naxis2 _hdrlist.append(outputvals) plist = outputvals.copy() plist.update(paramDict) # PyFITS can be used here as it will always operate on # output from PyDrizzle (which will always be a FITS file) # Open the input science file medianPar = 'outMedian' outMedianObj = img.getOutputName(medianPar) if img.inmemory: outMedian = img.outputNames[medianPar] _fname,_sciextn = fileutil.parseFilename(outMedian) _inimg = outMedianObj else: outMedian = outMedianObj _fname,_sciextn = fileutil.parseFilename(outMedian) _inimg = fileutil.openImage(_fname) # Return the PyFITS HDU corresponding to the named extension _scihdu = fileutil.getExtn(_inimg,_sciextn) _insci = _scihdu.data.copy() _inimg.close() del _inimg, _scihdu _outsci = do_blot(_insci, output_wcs, chip.wcs, chip._exptime, coeffs=paramDict['coeffs'], interp=paramDict['blot_interp'], sinscl=paramDict['blot_sinscl'], wcsmap=wcsmap) # Apply sky subtraction and unit conversion to blotted array to # match un-modified input array if paramDict['blot_addsky']: skyval = chip.computedSky else: skyval = paramDict['blot_skyval'] _outsci /= chip._conversionFactor _outsci += skyval log.info('Applying sky value of %0.6f to blotted image %s'% (skyval,chip.outputNames['data'])) # Write output Numpy objects to a PyFITS file # Blotting only occurs from a drizzled SCI extension # to a blotted SCI extension... _outimg = outputimage.OutputImage(_hdrlist, paramDict, build=False, wcs=chip.wcs, blot=True) _outimg.outweight = None _outimg.outcontext = None outimgs = _outimg.writeFITS(plist['data'],_outsci,None, versions=_versions,blend=False, virtual=img.inmemory) img.saveVirtualOutputs(outimgs) #_buildOutputFits(_outsci,None,plist['outblot']) _hdrlist = [] del _outsci del _outimg
def run(configObj, wcsmap=None): """ Interface for running `wdrizzle` from TEAL or Python command-line. This code performs all file ``I/O`` to set up the use of the drizzle code for a single exposure to replicate the functionality of the original `wdrizzle`. """ # Insure all output filenames specified have .fits extensions if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits' if not util.is_blank(configObj['outweight']) and configObj['outweight'][-5:] != '.fits': configObj['outweight'] += '.fits' if not util.is_blank(configObj['outcontext']) and configObj['outcontext'][-5:] != '.fits': configObj['outcontext'] += '.fits' # Keep track of any files we need to open in_sci_handle = None in_wht_handle = None out_sci_handle = None out_wht_handle = None out_con_handle = None _wcskey = configObj['wcskey'] if util.is_blank(_wcskey): _wcskey = ' ' scale_pars = configObj['Data Scaling Parameters'] user_wcs_pars = configObj['User WCS Parameters'] # Open the SCI (and WHT?) image # read file to get science array insci = get_data(configObj['input']) expin = fileutil.getKeyword(configObj['input'],scale_pars['expkey']) in_sci_phdr = fits.getheader(fileutil.parseFilename(configObj['input'])[0]) # we need to read in the input WCS input_wcs = stwcs.wcsutil.HSTWCS(configObj['input'],wcskey=_wcskey) if not util.is_blank(configObj['inweight']): inwht = get_data(configObj['inweight']).astype(np.float32) else: # Generate a default weight map of all good pixels inwht = np.ones(insci.shape,dtype=insci.dtype) output_exists = False outname = fileutil.osfn(fileutil.parseFilename(configObj['outdata'])[0]) if os.path.exists(outname): output_exists = True # Output was specified as a filename, so open it in 'update' mode outsci = get_data(configObj['outdata']) if output_exists: # we also need to read in the output WCS from pre-existing output output_wcs = stwcs.wcsutil.HSTWCS(configObj['outdata']) out_sci_hdr = fits.getheader(outname) outexptime = out_sci_hdr['DRIZEXPT'] if 'ndrizim' in out_sci_hdr: uniqid = out_sci_hdr['ndrizim']+1 else: uniqid = 1 else: # otherwise, define the output WCS either from user pars or refimage if util.is_blank(configObj['User WCS Parameters']['refimage']): # Define a WCS based on user provided WCS values # NOTE: # All parameters must be specified, not just one or a few if not util.is_blank(user_wcs_pars['outscale']): output_wcs = wcs_functions.build_hstwcs( user_wcs_pars['raref'], user_wcs_pars['decref'], user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'], user_wcs_pars['outnx'], user_wcs_pars['outny'], user_wcs_pars['outscale'], user_wcs_pars['orient'] ) else: # Define default WCS based on input image applydist = True if input_wcs.sip is None or input_wcs.instrument=='DEFAULT': applydist = False output_wcs = stwcs.distortion.utils.output_wcs([input_wcs],undistort=applydist) else: refimage = configObj['User WCS Parameters']['refimage'] refroot,extroot = fileutil.parseFilename(refimage) if extroot is None: fimg = fits.open(refroot) for i,extn in enumerate(fimg): if 'CRVAL1' in extn.header: # Key on CRVAL1 for valid WCS refwcs = wcsutil.HSTWCS('{}[{}]'.format(refroot,i)) if refwcs.wcs.has_cd(): extroot = i break fimg.close() # try to find extension with valid WCS refimage = "{}[{}]".format(refroot,extroot) # Define the output WCS based on a user specified reference image WCS output_wcs = stwcs.wcsutil.HSTWCS(refimage) # Initialize values used for combining results outexptime = 0.0 uniqid = 1 # Set up the output data array and insure that the units for that array is 'cps' if outsci is None: # Define a default blank array based on definition of output_wcs #outsci = np.zeros((output_wcs._naxis2,output_wcs._naxis1),dtype=np.float32) outsci = np.empty((output_wcs._naxis2,output_wcs._naxis1),dtype=np.float32) outsci.fill(np.nan) else: # Convert array to units of 'cps', if needed if outexptime != 0.0: np.divide(outsci, outexptime, outsci) outsci = outsci.astype(np.float32) # Now update output exposure time for additional input file outexptime += expin outwht = None if not util.is_blank(configObj['outweight']): outwht = get_data(configObj['outweight']) if outwht is None: outwht = np.zeros((output_wcs._naxis2,output_wcs._naxis1),dtype=np.float32) else: outwht = outwht.astype(np.float32) outcon = None keep_con = False if not util.is_blank(configObj['outcontext']): outcon = get_data(configObj['outcontext']) keep_con = True if outcon is None: outcon = np.zeros((1,output_wcs._naxis2,output_wcs._naxis1),dtype=np.int32) else: outcon = outcon.astype(np.int32) planeid = int((uniqid - 1)/ 32) # Add a new plane to the context image if planeid overflows while outcon.shape[0] <= planeid: plane = np.zeros_like(outcon[0]) outcon = np.append(outcon, plane, axis=0) # Interpret wt_scl parameter if configObj['wt_scl'] == 'exptime': wt_scl = expin elif configObj['wt_scl'] == 'expsq': wt_scl = expin*expin else: wt_scl = float(configObj['wt_scl']) # Interpret coeffs parameter to determine whether to apply coeffs or not undistort = True if not configObj['coeffs'] or input_wcs.sip is None or input_wcs.instrument == 'DEFAULT': undistort = False # turn off use of coefficients if undistort is False (coeffs == False) if not undistort: input_wcs.sip = None input_wcs.cpdis1 = None input_wcs.cpdis2 = None input_wcs.det2im = None wcslin = distortion.utils.output_wcs([input_wcs],undistort=undistort) # Perform actual drizzling now... _vers = do_driz(insci, input_wcs, inwht, output_wcs, outsci, outwht, outcon, expin, scale_pars['in_units'], wt_scl, wcslin_pscale=wcslin.pscale ,uniqid=uniqid, pixfrac=configObj['pixfrac'], kernel=configObj['kernel'], fillval=scale_pars['fillval'], stepsize=configObj['stepsize'], wcsmap=None) out_sci_handle,outextn = create_output(configObj['outdata']) if not output_exists: # Also, define default header based on input image Primary header out_sci_handle[outextn].header = in_sci_phdr.copy() # Update header of output image with exptime used to scale the output data # if out_units is not counts, this will simply be a value of 1.0 # the keyword 'exptime' will always contain the total exposure time # of all input image regardless of the output units out_sci_handle[outextn].header['EXPTIME'] = outexptime # create CTYPE strings ctype1 = input_wcs.wcs.ctype[0] ctype2 = input_wcs.wcs.ctype[1] if ctype1.find('-SIP'): ctype1 = ctype1.replace('-SIP','') if ctype2.find('-SIP'): ctype2 = ctype2.replace('-SIP','') # Update header with WCS keywords out_sci_handle[outextn].header['ORIENTAT'] = output_wcs.orientat out_sci_handle[outextn].header['CD1_1'] = output_wcs.wcs.cd[0][0] out_sci_handle[outextn].header['CD1_2'] = output_wcs.wcs.cd[0][1] out_sci_handle[outextn].header['CD2_1'] = output_wcs.wcs.cd[1][0] out_sci_handle[outextn].header['CD2_2'] = output_wcs.wcs.cd[1][1] out_sci_handle[outextn].header['CRVAL1'] = output_wcs.wcs.crval[0] out_sci_handle[outextn].header['CRVAL2'] = output_wcs.wcs.crval[1] out_sci_handle[outextn].header['CRPIX1'] = output_wcs.wcs.crpix[0] out_sci_handle[outextn].header['CRPIX2'] = output_wcs.wcs.crpix[1] out_sci_handle[outextn].header['CTYPE1'] = ctype1 out_sci_handle[outextn].header['CTYPE2'] = ctype2 out_sci_handle[outextn].header['VAFACTOR'] = 1.0 if scale_pars['out_units'] == 'counts': np.multiply(outsci, outexptime, outsci) out_sci_handle[outextn].header['DRIZEXPT'] = outexptime else: out_sci_handle[outextn].header['DRIZEXPT'] = 1.0 # Update header keyword NDRIZIM to keep track of how many images have # been combined in this product so far out_sci_handle[outextn].header['NDRIZIM'] = uniqid #define keywords to be written out to product header drizdict = outputimage.DRIZ_KEYWORDS.copy() # Update drizdict with current values drizdict['VER']['value'] = _vers[:44] drizdict['DATA']['value'] = configObj['input'][:64] drizdict['DEXP']['value'] = expin drizdict['OUDA']['value'] = configObj['outdata'][:64] drizdict['OUWE']['value'] = configObj['outweight'][:64] drizdict['OUCO']['value'] = configObj['outcontext'][:64] drizdict['MASK']['value'] = configObj['inweight'][:64] drizdict['WTSC']['value'] = wt_scl drizdict['KERN']['value'] = configObj['kernel'] drizdict['PIXF']['value'] = configObj['pixfrac'] drizdict['OUUN']['value'] = scale_pars['out_units'] drizdict['FVAL']['value'] = scale_pars['fillval'] drizdict['WKEY']['value'] = configObj['wcskey'] outputimage.writeDrizKeywords(out_sci_handle[outextn].header,uniqid,drizdict) # add output array to output file out_sci_handle[outextn].data = outsci out_sci_handle.close() if not util.is_blank(configObj['outweight']): out_wht_handle,outwhtext = create_output(configObj['outweight']) out_wht_handle[outwhtext].header = out_sci_handle[outextn].header.copy() out_wht_handle[outwhtext].data = outwht out_wht_handle.close() if keep_con: out_con_handle,outconext = create_output(configObj['outcontext']) out_con_handle[outconext].data = outcon out_con_handle.close()
def writeSingleFITS(data, wcs, output, template, clobber=True, verbose=True, rules_file=None): """ Write out a simple FITS file given a numpy array and the name of another FITS file to use as a template for the output image header. """ outname, outextn = fileutil.parseFilename(output) outextname, outextver = fileutil.parseExtn(outextn) if fileutil.findFile(outname): if clobber: log.info('Deleting previous output product: %s' % outname) fileutil.removeFile(outname) else: log.warning('Output file %s already exists and overwrite not ' 'specified!' % outname) log.error('Quitting... Please remove before resuming operations.') raise IOError # Now update WCS keywords with values from provided WCS if hasattr(wcs.sip, 'a_order'): siphdr = True else: siphdr = False wcshdr = wcs.wcs2header(sip2hdr=siphdr) if template is not None: # Get default headers from multi-extension FITS file # If input data is not in MEF FITS format, it will return 'None' # NOTE: These are HEADER objects, not HDUs (prihdr, scihdr, errhdr, dqhdr), newtab = getTemplates(template, EXTLIST, rules_file=rules_file) if scihdr is None: scihdr = fits.Header() indx = 0 for c in prihdr.cards: if c.keyword not in ['INHERIT', 'EXPNAME']: indx += 1 else: break for i in range(indx, len(prihdr)): scihdr.append(prihdr.cards[i]) for i in range(indx, len(prihdr)): del prihdr[indx] else: scihdr = fits.Header() prihdr = fits.Header() # Start by updating PRIMARY header keywords... prihdr.set('EXTEND', value=True, after='NAXIS') prihdr['FILENAME'] = outname if outextname == '': outextname = 'sci' if outextver == 0: outextver = 1 scihdr['EXTNAME'] = outextname.upper() scihdr['EXTVER'] = outextver scihdr.update(wcshdr) # Create PyFITS HDUList for all extensions outhdu = fits.HDUList() # Setup primary header as an HDU ready for appending to output FITS file prihdu = fits.PrimaryHDU(header=prihdr) scihdu = fits.ImageHDU(header=scihdr, data=data) outhdu.append(prihdu) outhdu.append(scihdu) outhdu.writeto(outname) if verbose: print('Created output image: %s' % outname)
def getSingleTemplate(fname, extlist=['SCI', 'ERR', 'DQ']): """ # Obtain default headers for output file based on a single input file # (Copied from outputimage module.) # Returns ------- headers : tuple of `astropy.io.fits.Header` objects, not HDU objects! headers """ if fname is None: raise ValueError('No data files for creating FITS output.') froot,fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot,mode='readonly') prihdr = ftemplate['PRIMARY'].header.copy() try: del prihdr['pcount'] del prihdr['gcount'] except KeyError: pass if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) else: extnum = (extlist[0],fnum) #scihdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr = fits.Header(ftemplate[extnum].header.copy()) #scihdr.update('extver',1) extnum_sci = extnum # Extract the header for additional extensions if len(extlist) > 1 and extlist[1] not in [None,'',' ','INDEF','None']: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) else: extnum = extnum_sci #errhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr = fits.Header(ftemplate[extnum].header.copy()) #errhdr.update('extver',1) errhdr['bunit'] = 'UNITLESS' if len(extlist) > 2 and extlist[2] not in [None,'',' ','INDEF','None']: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) else: extnum = extnum_sci #dqhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr = fits.Header(ftemplate[extnum].header.copy()) #dqhdr.update('extver',1) dqhdr['bunit'] = 'UNITLESS' else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate return prihdr, scihdr, errhdr, dqhdr
def __init__(self,expname, handle=None, dqname=None, idckey=None, new=no,wcs=None,mask=None,pa_key=None, parity=None, idcdir=None, rot=None, extver=1, exptime=None, ref_pscale=1.0, binned=1, mt_wcs=None, group_indx = None): # This name should be formatted for use in image I/O self.name = fileutil.osfn(expname) # osfn() will expand '.' unnecessarily, potentially # creating a string-length problem for 'drizzle', which # is limited to strings of 80 chars. _path,_name = os.path.split(self.name) # if path for this filename is the same as the current dir, # then there is no need to pass along the path. if _path == os.getcwd(): self.name = _name # Keep track of any associated mask file created for # this exposure from its DQ file, or other mask file. _fname,_extn = fileutil.parseFilename(expname) _open = False # Make sure we have an open file handle to use for getting the # header and data arrays. if not handle and not new: handle = fileutil.openImage(expname) _open = True # If no extension was specified, try to interrogate the file # to find whether the SCI array is in the Primary # (as in Simple FITS) or first extension (as in MEF). if handle and _extn == None: if handle[0].data == None: # Primary extension specified and no data present. # Try looking for data in next extension. if len(handle) > 1 and handle[1].data != None: _extn = 1 expname += '[1]' else: raise IOError("No valid image data in %s.\n"%expname) else: _extn = 0 self.dgeoname = None self.xgeoim = "" self.ygeoim = "" self.exptime = exptime self.group_indx = group_indx if not new: # Read in a copy of the header for this exposure/group/extension _header = fileutil.getHeader(expname,handle=handle) _chip = drutil.getChipId(_header) self.chip = str(_chip) # Keep track of any distortion correction images provided # for this chip self.dgeoname = fileutil.getKeyword(expname,'DGEOFILE',handle=handle) self.xgeoim,self.ygeoim = self.getDGEOExtn() if self.exptime == None: self.exptime = float(_header['EXPTIME']) if self.exptime == 0.: self.exptime = 1.0 # # Extract photometric transformation keywords # If they do not exist, use default values of 0 and 1 # self.plam = float(fileutil.getKeyword(expname,'PHOTPLAM',handle=handle)) / 10. if self.plam == None: # Setup a default value in case this keyword does not exist self.plam = 555. self.photzpt = float(fileutil.getKeyword(expname,'PHOTZPT',handle=handle)) if self.photzpt == None: self.photzpt = 0.0 self.photflam = float(fileutil.getKeyword(expname,'PHOTFLAM',handle=handle)) if self.photflam == None: self.photflam = 1.0 # Read in date-obs from primary header if _header: if 'date-obs' in _header: self.dateobs = _header['date-obs'] elif 'date_obs' in _header: self.dateobs = _header['date_obs'] else: self.dateobs = None else: self.dateobs = None # Initialize the value of BUNIT based on the header information, if # the header has the keyword if 'BUNIT' in _header and _header['BUNIT'].find('ergs') < 0: self.bunit = _header['BUNIT'] else: self.bunit = 'ELECTRONS' else: _chip = 1 _header = None self.chip = str(_chip) # Set a default value for pivot wavelength self.plam = 555. self.photzpt = 0.0 self.photflam = 1.0 self.dateobs = None if self.exptime == None: self.exptime = 1. self.parity = parity self.header = _header self.extver = extver # Create a pointer to the mask file's data array # and the name of the original input DQ file self.maskname = None self.singlemaskname = None self.masklist = None if mask != None: # Specifies filenames to be used if created. self.maskname = mask[0] self.singlemaskname = mask[1] self.masklist = mask[2] self.dqname = dqname # Remember the name of the coeffs file generated for this chip self.coeffs = self.buildCoeffsName() # Read the name of idcfile from image header if not explicitly # provided by user. if idckey != None and idckey.lower() != 'wcs': _indx = expname.find('[') if _indx > -1: _idc_fname = expname[:_indx]+'[0]' else: _idc_fname = expname+'[0]' idcfile, idctype = drutil.getIDCFile(self.header,keyword=idckey, directory=idcdir) else: idcfile = None idctype = None if (idckey != None) and (idckey.lower() == 'header'): idckey = idctype # Get distortion model and WCS info. self.geometry = ObsGeometry(expname, idcfile, idckey=idckey, chip=_chip, new=new, header=self.header, pa_key=pa_key, rot=rot, date=self.dateobs, ref_pscale=ref_pscale, binned=binned, mt_wcs=mt_wcs) # Remember the name and type of the IDC file used... self.idcfile = idcfile self.idctype = idctype # Remember the names of the filters used for the exposure self.filters = self.geometry.filter1+','+self.geometry.filter2 # Define shape here... # nx,ny,pixel scale # if wcs != None: # We have been passed a WCS to use self.geometry.wcs = wcs self.geometry.model.pscale = wcs.pscale if expname != None: self.geometry.wcs.rootname = expname self.naxis1 = self.geometry.wcs.naxis1 self.naxis2 = self.geometry.wcs.naxis2 self.pscale = self.geometry.wcs.pscale self.shape = (self.naxis1,self.naxis2,self.pscale) # Keep track of the positions of the corners of the exposure # both for the RAW image and the # distortion-corrected, unscaled, unrotated image self.corners = {'raw':np.zeros((4,2),dtype=np.float64),'corrected':np.zeros((4,2),dtype=np.float64)} self.setCorners() # Generate BLOT output name specific to this Exposure _blot_extn = '_sci'+repr(extver)+'_blt.fits' self.outblot = fileutil.buildNewRootname(self.name,extn=_blot_extn) # Keep track of undistorted frame's position relative to metachip # Zero-point offset for chip relative to meta-chip product # These values get computed using 'setSingleOffsets' from 'writeCoeffs' # to insure that the final XDELTA/YDELTA values have been computed. self.product_wcs = self.geometry.wcslin self.xzero = 0. self.yzero = 0. self.chip_shape = (0.,0.) self.xsh2 = 0. self.ysh2 = 0. if _open: handle.close() del handle
def _update(image,idctab,nimsets,apply_tdd=False, quiet=None,instrument=None,prepend=None,nrchip=None, nrext=None): tdd_xyref = {1: [2048, 3072], 2:[2048, 1024]} _prepend = prepend _dqname = None # Make a copy of the header for keyword access # This copy includes both Primary header and # extension header hdr = fileutil.getHeader(image) # Try to get the instrument if we don't have it already instrument = readKeyword(hdr,'INSTRUME') binned = 1 # Read in any specified OFFTAB, if present (WFPC2) offtab = readKeyword(hdr,'OFFTAB') dateobs = readKeyword(hdr,'DATE-OBS') if not quiet: print("OFFTAB, DATE-OBS: ",offtab,dateobs) print("-Updating image ",image) if not quiet: print("-Reading IDCTAB file ",idctab) # Get telescope orientation from image header # If PA_V# is not present of header, try to get it from the spt file pvt = readKeyword(hdr,'PA_V3') if pvt == None: sptfile = fileutil.buildNewRootname(image, extn='_spt.fits') if os.path.exists(sptfile): spthdr = fileutil.getHeader(sptfile) pvt = readKeyword(spthdr,'PA_V3') if pvt != None: pvt = float(pvt) else: print('PA_V3 keyword not found, WCS cannot be updated. Quitting ...') raise ValueError # Find out about instrument, detector & filters detector = readKeyword(hdr,'DETECTOR') Nrefchip=1 if instrument == 'WFPC2': filter1 = readKeyword(hdr,'FILTNAM1') filter2 = readKeyword(hdr,'FILTNAM2') mode = readKeyword(hdr,'MODE') if os.path.exists(fileutil.buildNewRootname(image, extn='_c1h.fits')): _dqname = fileutil.buildNewRootname(image, extn='_c1h.fits') dqhdr = pyfits.getheader(_dqname,1) dqext = readKeyword(dqhdr, 'EXTNAME') if mode == 'AREA': binned = 2 Nrefchip=nrchip elif instrument == 'NICMOS': filter1 = readKeyword(hdr,'FILTER') filter2 = None elif instrument == 'WFC3': filter1 = readKeyword(hdr,'FILTER') filter2 = None # use value of 'BINAXIS' keyword to set binning value for WFC3 data binned = readKeyword(hdr,'BINAXIS1') else: filter1 = readKeyword(hdr,'FILTER1') filter2 = readKeyword(hdr,'FILTER2') if filter1 == None or filter1.strip() == '': filter1 = 'CLEAR' else: filter1 = filter1.strip() if filter2 == None or filter2.strip() == '': filter2 = 'CLEAR' else: filter2 = filter2.strip() if filter1.find('CLEAR') == 0: filter1 = 'CLEAR' if filter2.find('CLEAR') == 0: filter2 = 'CLEAR' # Set up parity matrix for chip if instrument == 'WFPC2' or instrument =='STIS' or instrument == 'NICMOS': parity = PARITY[instrument] elif detector in PARITY: parity = PARITY[detector] else: raise ValueError('Detector ',detector, ' Not supported at this time. Exiting...') # Get the VAFACTOR keyword if it exists, otherwise set to 1.0 # we also need the reference pointing position of the target # as this is where _va_key = readKeyword(hdr,'VAFACTOR') if _va_key != None: VA_fac = float(_va_key) else: VA_fac=1.0 if not quiet: print('VA factor: ',VA_fac) #ra_targ = float(readKeyword(hdr,'RA_TARG')) #dec_targ = float(readKeyword(hdr,'DEC_TARG')) # Get the chip number _c = readKeyword(hdr,'CAMERA') _s = readKeyword(hdr,'CCDCHIP') _d = readKeyword(hdr,'DETECTOR') if _c != None and str(_c).isdigit(): chip = int(_c) elif _s == None and _d == None: chip = 1 else: if _s: chip = int(_s) elif str(_d).isdigit(): chip = int(_d) else: chip = 1 # For the ACS/WFC case the chip number doesn't match the image # extension nr = 1 if (instrument == 'ACS' and detector == 'WFC') or (instrument == 'WFC3' and detector == 'UVIS'): if nimsets > 1: Nrefchip = 2 else: Nrefchip = chip elif instrument == 'NICMOS': Nrefchip = readKeyword(hdr,'CAMERA') elif instrument == 'WFPC2': nr = nrext else: if nimsets > 1: nr = Nrefchip if not quiet: print("-PA_V3 : ",pvt," CHIP #",chip) # Extract the appropriate information from the IDCTAB #fx,fy,refpix,order=fileutil.readIDCtab(idctab,chip=chip,direction='forward', # filter1=filter1,filter2=filter2,offtab=offtab,date=dateobs) idcmodel = models.IDCModel(idctab, chip=chip, direction='forward', date=dateobs, filter1=filter1, filter2=filter2, offtab=offtab, binned=binned, tddcorr=apply_tdd) fx = idcmodel.cx fy = idcmodel.cy refpix = idcmodel.refpix order = idcmodel.norder # Determine whether to perform time-dependent correction # Construct matrices neded to correct the zero points for TDD if apply_tdd: #alpha,beta = mutil.compute_wfc_tdd_coeffs(dateobs,skew_coeffs) alpha = refpix['TDDALPHA'] beta = refpix['TDDBETA'] tdd = N.array([[beta, alpha], [alpha, -beta]]) mrotp = fileutil.buildRotMatrix(2.234529)/2048. else: alpha = 0.0 beta = 0.0 # Get the original image WCS Old=wcsutil.WCSObject(image,prefix=_prepend) # Reset the WCS keywords to original archived values. Old.restore() # # Look for any subarray offset # ltv1,ltv2 = drutil.getLTVOffsets(image) # # If reference point is not centered on distortion model # shift coefficients to be applied relative to observation # reference position # offsetx = Old.crpix1 - ltv1 - refpix['XREF'] offsety = Old.crpix2 - ltv2 - refpix['YREF'] shiftx = refpix['XREF'] + ltv1 shifty = refpix['YREF'] + ltv2 if ltv1 != 0. or ltv2 != 0.: ltvoffx = ltv1 + offsetx ltvoffy = ltv2 + offsety offshiftx = offsetx + shiftx offshifty = offsety + shifty else: ltvoffx = 0. ltvoffy = 0. offshiftx = 0. offshifty = 0. if ltv1 != 0. or ltv2 != 0.: fx,fy = idcmodel.shift(idcmodel.cx,idcmodel.cy,offsetx,offsety) # Extract the appropriate information for reference chip ridcmodel = models.IDCModel(idctab, chip=Nrefchip, direction='forward', date=dateobs, filter1=filter1, filter2=filter2, offtab=offtab, binned=binned, tddcorr=apply_tdd) rfx = ridcmodel.cx rfy = ridcmodel.cy rrefpix = ridcmodel.refpix rorder = ridcmodel.norder """ rfx,rfy,rrefpix,rorder=mutil.readIDCtab(idctab,chip=Nrefchip, direction='forward', filter1=filter1,filter2=filter2,offtab=offtab, date=dateobs,tddcorr=apply_tdd) """ # Create the reference image name rimage = image.split('[')[0]+"[sci,%d]" % nr if not quiet: print("Reference image: ",rimage) # Create the tangent plane WCS on which the images are defined # This is close to that of the reference chip R=wcsutil.WCSObject(rimage) R.write_archive(rimage) R.restore() # Reacd in declination of target (for computing orientation at aperture) # Note that this is from the reference image #dec = float(fileutil.getKeyword(rimage,'CRVAL2')) #crval1 = float(fileutil.getKeyword(rimage,'CRVAL1')) #crval1 = float(R.crval1) #crval2 = dec dec = float(R.crval2) # Get an approximate reference position on the sky rref = (rrefpix['XREF']+ltvoffx, rrefpix['YREF']+ltvoffy) crval1,crval2=R.xy2rd(rref) if apply_tdd: # Correct zero points for TDD tddscale = (R.pscale/fx[1][1]) rxy0 = N.array([[tdd_xyref[Nrefchip][0]-2048.],[ tdd_xyref[Nrefchip][1]-2048.]]) xy0 = N.array([[tdd_xyref[chip][0]-2048.], [tdd_xyref[chip][1]-2048.]]) rv23_corr = N.dot(mrotp,N.dot(tdd,rxy0))*tddscale v23_corr = N.dot(mrotp,N.dot(tdd,xy0))*tddscale else: rv23_corr = N.array([[0],[0]]) v23_corr = N.array([[0],[0]]) # Convert the PA_V3 orientation to the orientation at the aperture # This is for the reference chip only - we use this for the # reference tangent plane definition # It has the same orientation as the reference chip v2ref = rrefpix['V2REF'] + rv23_corr[0][0]*0.05 v3ref = rrefpix['V3REF'] - rv23_corr[1][0]*0.05 v2 = refpix['V2REF'] + v23_corr[0][0]*0.05 v3 = refpix['V3REF'] - v23_corr[1][0] *0.05 pv = wcsutil.troll(pvt,dec,v2ref,v3ref) # Add the chip rotation angle if rrefpix['THETA']: pv += rrefpix['THETA'] # Set values for the rest of the reference WCS R.crval1=crval1 R.crval2=crval2 R.crpix1=0.0 + offshiftx R.crpix2=0.0 + offshifty R_scale=rrefpix['PSCALE']/3600.0 R.cd11=parity[0][0] * cos(pv*pi/180.0)*R_scale R.cd12=parity[0][0] * -sin(pv*pi/180.0)*R_scale R.cd21=parity[1][1] * sin(pv*pi/180.0)*R_scale R.cd22=parity[1][1] * cos(pv*pi/180.0)*R_scale ##print R R_cdmat = N.array([[R.cd11,R.cd12],[R.cd21,R.cd22]]) if not quiet: print(" Reference Chip Scale (arcsec/pix): ",rrefpix['PSCALE']) # Offset and angle in V2/V3 from reference chip to # new chip(s) - converted to reference image pixels off = sqrt((v2-v2ref)**2 + (v3-v3ref)**2)/(R_scale*3600.0) # Here we must include the PARITY if v3 == v3ref: theta=0.0 else: theta = atan2(parity[0][0]*(v2-v2ref),parity[1][1]*(v3-v3ref)) if rrefpix['THETA']: theta += rrefpix['THETA']*pi/180.0 dX=(off*sin(theta)) + offshiftx dY=(off*cos(theta)) + offshifty # Check to see whether we are working with GEIS or FITS input _fname,_iextn = fileutil.parseFilename(image) if _fname.find('.fits') < 0: # Input image is NOT a FITS file, so # build a FITS name for it's copy. _fitsname = fileutil.buildFITSName(_fname) else: _fitsname = None # Create a new instance of a WCS if _fitsname == None: _new_name = image else: _new_name = _fitsname+'['+str(_iextn)+']' #New=wcsutil.WCSObject(_new_name,new=yes) New = Old.copy() # Calculate new CRVALs and CRPIXs New.crval1,New.crval2=R.xy2rd((dX,dY)) New.crpix1=refpix['XREF'] + ltvoffx New.crpix2=refpix['YREF'] + ltvoffy # Account for subarray offset # Angle of chip relative to chip if refpix['THETA']: dtheta = refpix['THETA'] - rrefpix['THETA'] else: dtheta = 0.0 # Create a small vector, in reference image pixel scale # There is no parity effect here ??? delXX=fx[1,1]/R_scale/3600. delYX=fy[1,1]/R_scale/3600. delXY=fx[1,0]/R_scale/3600. delYY=fy[1,0]/R_scale/3600. # Convert to radians rr=dtheta*pi/180.0 # Rotate the vectors dXX= cos(rr)*delXX - sin(rr)*delYX dYX= sin(rr)*delXX + cos(rr)*delYX dXY= cos(rr)*delXY - sin(rr)*delYY dYY= sin(rr)*delXY + cos(rr)*delYY # Transform to sky coordinates a,b=R.xy2rd((dX+dXX,dY+dYX)) c,d=R.xy2rd((dX+dXY,dY+dYY)) # Calculate the new CDs and convert to degrees New.cd11=diff_angles(a,New.crval1)*cos(New.crval2*pi/180.0) New.cd12=diff_angles(c,New.crval1)*cos(New.crval2*pi/180.0) New.cd21=diff_angles(b,New.crval2) New.cd22=diff_angles(d,New.crval2) # Apply the velocity aberration effect if applicable if VA_fac != 1.0: # First shift the CRVALs apart # New.crval1 = ra_targ + VA_fac*(New.crval1 - ra_targ) # New.crval2 = dec_targ + VA_fac*(New.crval2 - dec_targ) # First shift the CRVALs apart # This is now relative to the reference chip, not the # target position. New.crval1 = R.crval1 + VA_fac*diff_angles(New.crval1, R.crval1) New.crval2 = R.crval2 + VA_fac*diff_angles(New.crval2, R.crval2) # and scale the CDs New.cd11 = New.cd11*VA_fac New.cd12 = New.cd12*VA_fac New.cd21 = New.cd21*VA_fac New.cd22 = New.cd22*VA_fac New_cdmat = N.array([[New.cd11,New.cd12],[New.cd21,New.cd22]]) # Store new one # archive=yes specifies to also write out archived WCS keywords # overwrite=no specifies do not overwrite any pre-existing archived keywords New.write(fitsname=_new_name,overwrite=no,quiet=quiet,archive=yes) if _dqname: _dq_iextn = _iextn.replace('sci', dqext.lower()) _new_dqname = _dqname +'['+_dq_iextn+']' dqwcs = wcsutil.WCSObject(_new_dqname) dqwcs.write(fitsname=_new_dqname, wcs=New,overwrite=no,quiet=quiet, archive=yes) """ Convert distortion coefficients into SIP style values and write out to image (assumed to be FITS). """ #First the CD matrix: f = refpix['PSCALE']/3600.0 a = fx[1,1]/3600.0 b = fx[1,0]/3600.0 c = fy[1,1]/3600.0 d = fy[1,0]/3600.0 det = (a*d - b*c)*refpix['PSCALE'] # Write to header fimg = fileutil.openImage(_new_name,mode='update') _new_root,_nextn = fileutil.parseFilename(_new_name) _new_extn = fileutil.getExtn(fimg,_nextn) # Transform the higher-order coefficients for n in range(order+1): for m in range(order+1): if n >= m and n>=2: # Form SIP-style keyword names Akey="A_%d_%d" % (m,n-m) Bkey="B_%d_%d" % (m,n-m) # Assign them values Aval= f*(d*fx[n,m]-b*fy[n,m])/det Bval= f*(a*fy[n,m]-c*fx[n,m])/det _new_extn.header.update(Akey,Aval) _new_extn.header.update(Bkey,Bval) # Update the SIP flag keywords as well #iraf.hedit(image,"CTYPE1","RA---TAN-SIP",verify=no,show=no) #iraf.hedit(image,"CTYPE2","DEC--TAN-SIP",verify=no,show=no) _new_extn.header.update("CTYPE1","RA---TAN-SIP") _new_extn.header.update("CTYPE2","DEC--TAN-SIP") # Finally we also need the order #iraf.hedit(image,"A_ORDER","%d" % order,add=yes,verify=no,show=no) #iraf.hedit(image,"B_ORDER","%d" % order,add=yes,verify=no,show=no) _new_extn.header.update("A_ORDER",order) _new_extn.header.update("B_ORDER",order) # Update header with additional keywords required for proper # interpretation of SIP coefficients by PyDrizzle. _new_extn.header.update("IDCSCALE",refpix['PSCALE']) _new_extn.header.update("IDCV2REF",refpix['V2REF']) _new_extn.header.update("IDCV3REF",refpix['V3REF']) _new_extn.header.update("IDCTHETA",refpix['THETA']) _new_extn.header.update("OCX10",fx[1][0]) _new_extn.header.update("OCX11",fx[1][1]) _new_extn.header.update("OCY10",fy[1][0]) _new_extn.header.update("OCY11",fy[1][1]) #_new_extn.header.update("TDDXOFF",rv23_corr[0][0] - v23_corr[0][0]) #_new_extn.header.update("TDDYOFF",-(rv23_corr[1][0] - v23_corr[1][0])) # Report time-dependent coeffs, if computed if instrument == 'ACS' and detector == 'WFC': _new_extn.header.update("TDDALPHA",alpha) _new_extn.header.update("TDDBETA",beta) # Close image now fimg.close() del fimg
def run(configObj, wcsmap=None): """ Run the blot task based on parameters provided interactively by the user. """ # Insure all output filenames specified have .fits extensions if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits' scale_pars = configObj['Data Scaling Parameters'] user_wcs_pars = configObj['User WCS Parameters'] # PyFITS can be used here as it will always operate on # output from PyDrizzle (which will always be a FITS file) # Open the input (drizzled?) image _fname, _sciextn = fileutil.parseFilename(configObj['data']) _inimg = fileutil.openImage(_fname, memmap=False) _expin = fileutil.getKeyword(configObj['data'], scale_pars['expkey'], handle=_inimg) # Return the PyFITS HDU corresponding to the named extension _scihdu = fileutil.getExtn(_inimg, _sciextn) _insci = _scihdu.data.copy() _inexptime = 1.0 if scale_pars['in_units'] == 'counts': if scale_pars['expkey'] in _inimg['PRIMARY'].header: _inexptime = _inimg['PRIMARY'].header[scale_pars['expkey']] elif 'DRIZEXPT' in _inimg['PRIMARY'].header: # Try keyword written out by new 'drizzle' if no valid 'expkey' was given _inexptime = _inimg['PRIMARY'].header['DRIZEXPT'] else: raise ValueError('No valid exposure time keyword could be found ' 'for input %s' % configObj['data']) # always convert input to 'cps' for blot() algorithm if _inexptime != 0.0 or _inexptime != 1.0: np.divide(_insci, _inexptime, _insci) _inimg.close() del _inimg # read in WCS from source (drizzled) image source_wcs = stwcs.wcsutil.HSTWCS(configObj['data']) if source_wcs.wcs.is_unity(): print( "WARNING: No valid WCS found for input drizzled image: {}!".format( configObj['data'])) # define blot_wcs blot_wcs = None _refname, _refextn = fileutil.parseFilename(configObj['reference']) if os.path.exists(_refname): # read in WCS from pre-existing output image blot_wcs = stwcs.wcsutil.HSTWCS(configObj['reference']) if blot_wcs.wcs.is_unity(): print("WARNING: No valid WCS found for output image: {} !".format( configObj['reference'])) # define blot WCS based on input images or specified reference WCS values if user_wcs_pars['user_wcs']: blot_wcs = wcs_functions.build_hstwcs(user_wcs_pars['raref'], user_wcs_pars['decref'], user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'], int(user_wcs_pars['outnx']), int(user_wcs_pars['outny']), user_wcs_pars['outscale'], user_wcs_pars['orient']) configObj['coeffs'] = None # If blot_wcs is still not defined at this point, we have a problem... if blot_wcs is None: blot_wcs = stwcs.distortion.utils.output_wcs([source_wcs], undistort=False) out_wcs = blot_wcs.copy() # perform blotting operation now _outsci = do_blot(_insci, source_wcs, out_wcs, _expin, coeffs=configObj['coeffs'], interp=configObj['interpol'], sinscl=configObj['sinscl'], stepsize=configObj['stepsize'], wcsmap=wcsmap) # create output with proper units and exptime-scaling if scale_pars['out_units'] == 'counts': if scale_pars['expout'] == 'input': _outscale = fileutil.getKeyword(configObj['reference'], scale_pars['expkey']) #_outscale = _expin else: _outscale = float(scale_pars['expout']) print( "Output blotted images scaled by exptime of {}".format(_outscale)) np.multiply(_outsci, _outscale, _outsci) # Add sky back in to the blotted image, as specified by the user if configObj['addsky']: skyval = _scihdu.header['MDRIZSKY'] else: skyval = configObj['skyval'] print("Added {} counts back in to blotted image as sky.".format(skyval)) _outsci += skyval del _scihdu # Write output Numpy objects to a PyFITS file # Blotting only occurs from a drizzled SCI extension # to a blotted SCI extension... outputimage.writeSingleFITS(_outsci, blot_wcs, configObj['outdata'], configObj['reference'])
def make_outputwcs(imageObjectList, output, configObj=None, perfect=False): """ Computes the full output WCS based on the set of input imageObjects provided as input, along with the pre-determined output name from process_input. The user specified output parameters are then used to modify the default WCS to produce the final desired output frame. The input imageObjectList has the outputValues dictionary updated with the information from the computed output WCS. It then returns this WCS as a WCSObject(imageObject) instance. """ if not isinstance(imageObjectList, list): imageObjectList = [imageObjectList] # Compute default output WCS, replace later if user specifies a refimage hstwcs_list = [] undistort = True for img in imageObjectList: chip_wcs = copy.deepcopy(img.getKeywordList('wcs')) # IF the user turned off use of coeffs (coeffs==False) if not configObj['coeffs']: for cw in chip_wcs: # Turn off distortion model for each input cw.sip = None cw.cpdis1 = None cw.cpdis2 = None cw.det2im = None undistort = False hstwcs_list += chip_wcs if not undistort and len(hstwcs_list) == 1: default_wcs = hstwcs_list[0].deepcopy() else: default_wcs = utils.output_wcs(hstwcs_list, undistort=undistort) if perfect: default_wcs.wcs.cd = make_perfect_cd(default_wcs) # Turn WCS instances into WCSObject instances outwcs = createWCSObject(output, default_wcs, imageObjectList) # Merge in user-specified attributes for the output WCS # as recorded in the input configObj object. final_pars = DEFAULT_WCS_PARS.copy() # More interpretation of the configObj needs to be done here to translate # the input parameter names to those understood by 'mergeWCS' as defined # by the DEFAULT_WCS_PARS dictionary. single_step = configObj[util.getSectionName(configObj, 3)] singleParDict = configObj[util.getSectionName(configObj, '3a')].copy() if single_step['driz_separate'] and singleParDict['driz_sep_wcs']: single_pars = DEFAULT_WCS_PARS.copy() del singleParDict['driz_sep_wcs'] keyname = 'driz_sep_' for key in singleParDict: k = key[len(keyname):] if k != 'refimage': single_pars[k] = singleParDict[key] # Now, account for any user-specified reference image def_wcs = default_wcs.deepcopy() single_ref = singleParDict[keyname + 'refimage'] if single_ref: if isinstance(single_ref, wcs.WCS): default_wcs = single_ref else: default_wcs = wcsutil.HSTWCS(singleParDict[keyname + 'refimage']) # ## Create single_wcs instance based on user parameters outwcs.single_wcs = mergeWCS(default_wcs, single_pars) # restore global default WCS to original value so single_drizzle WCS does not # influence final_drizzle WCS default_wcs = def_wcs.deepcopy() final_step = configObj[util.getSectionName(configObj, 7)] finalParDict = configObj[util.getSectionName(configObj, '7a')].copy() if final_step['driz_combine'] and finalParDict['final_wcs']: del finalParDict['final_wcs'] keyname = 'final_' for key in finalParDict: k = key[len(keyname):] if k != 'refimage': final_pars[k] = finalParDict[key] # Now, account for any user-specified reference image final_ref = finalParDict[keyname + 'refimage'] if final_ref: if isinstance(final_ref, wcs.WCS): default_wcs = final_ref if hasattr(final_ref, 'filename'): rootname = final_ref.filename else: rootname = "" print('Creating OUTPUT WCS from WCS object based on {}'.format(rootname)) else: rootname, extnum = fileutil.parseFilename(finalParDict[keyname + 'refimage']) extnum = util.findWCSExtn(finalParDict[keyname + 'refimage']) print('Creating OUTPUT WCS from {}[{}]'.format(rootname, extnum)) default_wcs = wcsutil.HSTWCS('{}[{}]'.format(rootname, extnum)) # ## Create single_wcs instance based on user parameters outwcs.final_wcs = mergeWCS(default_wcs, final_pars) outwcs.wcs = outwcs.final_wcs.copy() # Apply user settings to create custom output_wcs instances # for each drizzle step updateImageWCS(imageObjectList, outwcs) return outwcs
def tran(inimage,outimage,direction='forward',x=None,y=None, coords=None, coordfile=None,colnames=None,separator=None, precision=6, output=None,verbose=True): """ Primary interface to perform coordinate transformations in pixel coordinates between 2 images using STWCS and full distortion models read from each image's header. """ single_coord = False # Only use value provided in `coords` if nothing has been specified for coordfile if coords is not None and coordfile is None: coordfile = coords warnings.simplefilter('always',DeprecationWarning) warnings.warn("Please update calling code to pass in `coordfile` instead of `coords`.", category=DeprecationWarning) warnings.simplefilter('default',DeprecationWarning) if coordfile is not None: if colnames in util.blank_list: colnames = ['c1','c2'] # Determine columns which contain pixel positions cols = util.parse_colnames(colnames,coordfile) # read in columns from input coordinates file xyvals = np.loadtxt(coordfile,usecols=cols,delimiter=separator) if xyvals.ndim == 1: # only 1 entry in coordfile xlist = [xyvals[0].copy()] ylist = [xyvals[1].copy()] else: xlist = xyvals[:,0].copy() ylist = xyvals[:,1].copy() del xyvals else: if isinstance(x,np.ndarray): xlist = x.tolist() ylist = y.tolist() elif not isinstance(x,list): xlist = [x] ylist = [y] single_coord = True else: xlist = x ylist = y # start by reading in WCS+distortion info for each image im1wcs = wcsutil.HSTWCS(inimage) if im1wcs.wcs.is_unity(): print("####\nNo valid input WCS found in {}.\n Results may be invalid.\n####\n".format(inimage)) if util.is_blank(outimage): fname,fextn = fileutil.parseFilename(inimage) numsci = fileutil.countExtn(fname) chips = [] for e in range(1,numsci+1): chips.append(wcsutil.HSTWCS(fname,ext=('sci',e))) if len(chips) == 0: chips = [im1wcs] im2wcs = distortion.utils.output_wcs(chips) else: im2wcs = wcsutil.HSTWCS(outimage) if im2wcs.wcs.is_unity(): print("####\nNo valid output WCS found in {}.\n Results may be invalid.\n####\n".format(outimage)) # Setup the transformation p2p = wcs_functions.WCSMap(im1wcs,im2wcs) if direction[0].lower() == 'f': outx,outy = p2p.forward(xlist,ylist) else: outx,outy = p2p.backward(xlist,ylist) if isinstance(outx,np.ndarray): outx = outx.tolist() outy = outy.tolist() # add formatting based on precision here... xstr = [] ystr = [] fmt = "%."+repr(precision)+"f" for ox,oy in zip(outx,outy): xstr.append(fmt%ox) ystr.append(fmt%oy) if verbose or (not verbose and util.is_blank(output)): print('# Coordinate transformations for ',inimage) print('# X(in) Y(in) X(out) Y(out)\n') for xs,ys,a,b in zip(xlist,ylist,xstr,ystr): print("%.4f %.4f %s %s"%(xs,ys,a,b)) # Create output file, if specified if output: f = open(output,mode='w') f.write("# Coordinates converted from %s\n"%inimage) for xs,ys in zip(xstr,ystr): f.write('%s %s\n'%(xs,ys)) f.close() print('Wrote out results to: ',output) if single_coord: outx = outx[0] outy = outy[0] return outx,outy
def run(configObj,wcsmap=None): """ Run the blot task based on parameters provided interactively by the user. """ # Insure all output filenames specified have .fits extensions if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits' scale_pars = configObj['Data Scaling Parameters'] user_wcs_pars = configObj['User WCS Parameters'] # PyFITS can be used here as it will always operate on # output from PyDrizzle (which will always be a FITS file) # Open the input (drizzled?) image _fname,_sciextn = fileutil.parseFilename(configObj['data']) _inimg = fileutil.openImage(_fname) _expin = fileutil.getKeyword(configObj['data'],scale_pars['expkey'],handle=_inimg) # Return the PyFITS HDU corresponding to the named extension _scihdu = fileutil.getExtn(_inimg,_sciextn) _insci = _scihdu.data.copy() _inexptime = 1.0 if scale_pars['in_units'] == 'counts': if scale_pars['expkey'] in _inimg['PRIMARY'].header: _inexptime = _inimg['PRIMARY'].header[scale_pars['expkey']] elif 'DRIZEXPT' in _inimg['PRIMARY'].header: # Try keyword written out by new 'drizzle' if no valid 'expkey' was given _inexptime = _inimg['PRIMARY'].header['DRIZEXPT'] else: raise ValueError('No valid exposure time keyword could be found ' 'for input %s' % configObj['data']) # always convert input to 'cps' for blot() algorithm if _inexptime != 0.0 or _inexptime != 1.0: np.divide(_insci, _inexptime, _insci) _inimg.close() del _inimg # read in WCS from source (drizzled) image source_wcs = stwcs.wcsutil.HSTWCS(configObj['data']) if source_wcs.wcs.is_unity(): print("WARNING: No valid WCS found for input drizzled image: {}!".format(configObj['data'])) # define blot_wcs blot_wcs = None _refname,_refextn = fileutil.parseFilename(configObj['reference']) if os.path.exists(_refname): # read in WCS from pre-existing output image blot_wcs = stwcs.wcsutil.HSTWCS(configObj['reference']) if blot_wcs.wcs.is_unity(): print("WARNING: No valid WCS found for output image: {} !".format(configObj['reference'])) # define blot WCS based on input images or specified reference WCS values if user_wcs_pars['user_wcs']: blot_wcs = wcs_functions.build_hstwcs( user_wcs_pars['raref'], user_wcs_pars['decref'], user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'], user_wcs_pars['outnx'], user_wcs_pars['outny'], user_wcs_pars['outscale'], user_wcs_pars['orient'] ) configObj['coeffs'] = None # If blot_wcs is still not defined at this point, we have a problem... if blot_wcs is None: blot_wcs = stwcs.distortion.utils.output_wcs([source_wcs],undistort=False) out_wcs = blot_wcs.copy() # perform blotting operation now _outsci = do_blot(_insci, source_wcs, out_wcs, _expin, coeffs=configObj['coeffs'], interp=configObj['interpol'], sinscl=configObj['sinscl'], stepsize=configObj['stepsize'], wcsmap=wcsmap) # create output with proper units and exptime-scaling if scale_pars['out_units'] == 'counts': if scale_pars['expout'] == 'input': _outscale = fileutil.getKeyword(configObj['reference'],scale_pars['expkey']) #_outscale = _expin else: _outscale = float(scale_pars['expout']) print("Output blotted images scaled by exptime of {}".format(_outscale)) np.multiply(_outsci, _outscale, _outsci) # Add sky back in to the blotted image, as specified by the user if configObj['addsky']: skyval = _scihdu.header['MDRIZSKY'] else: skyval = configObj['skyval'] print("Added {} counts back in to blotted image as sky.".format(skyval)) _outsci += skyval del _scihdu # Write output Numpy objects to a PyFITS file # Blotting only occurs from a drizzled SCI extension # to a blotted SCI extension... outputimage.writeSingleFITS(_outsci,blot_wcs, configObj['outdata'],configObj['reference'])
def getSingleTemplate(fname, extlist=['SCI', 'ERR', 'DQ']): """ # Obtain default headers for output file based on a single input file # (Copied from outputimage module.) # Returns ------- headers : tuple of `astropy.io.fits.Header` objects, not HDU objects! headers """ if fname is None: raise ValueError('No data files for creating FITS output.') froot, fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot, mode='readonly') prihdr = ftemplate['PRIMARY'].header.copy() try: del prihdr['pcount'] del prihdr['gcount'] except KeyError: pass if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[0]) else: extnum = (extlist[0], fnum) #scihdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr = fits.Header(ftemplate[extnum].header.copy()) #scihdr.update('extver',1) extnum_sci = extnum # Extract the header for additional extensions if len(extlist) > 1 and extlist[1] not in [ None, '', ' ', 'INDEF', 'None' ]: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header[ 'extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1], fnum) else: # Use science header for remaining headers extnum = (extlist[0], fnum) else: extnum = extnum_sci #errhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr = fits.Header(ftemplate[extnum].header.copy()) #errhdr.update('extver',1) errhdr['bunit'] = 'UNITLESS' if len(extlist) > 2 and extlist[2] not in [ None, '', ' ', 'INDEF', 'None' ]: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header[ 'extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2], fnum) else: # Use science header for remaining headers extnum = (extlist[0], fnum) else: extnum = extnum_sci #dqhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr = fits.Header(ftemplate[extnum].header.copy()) #dqhdr.update('extver',1) dqhdr['bunit'] = 'UNITLESS' else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate return prihdr, scihdr, errhdr, dqhdr
def make_outputwcs(imageObjectList, output, configObj=None, perfect=False): """ Computes the full output WCS based on the set of input imageObjects provided as input, along with the pre-determined output name from process_input. The user specified output parameters are then used to modify the default WCS to produce the final desired output frame. The input imageObjectList has the outputValues dictionary updated with the information from the computed output WCS. It then returns this WCS as a WCSObject(imageObject) instance. """ if not isinstance(imageObjectList,list): imageObjectList = [imageObjectList] # Compute default output WCS, replace later if user specifies a refimage hstwcs_list = [] undistort=True for img in imageObjectList: chip_wcs = copy.deepcopy(img.getKeywordList('wcs')) # IF the user turned off use of coeffs (coeffs==False) if not configObj['coeffs']: for cw in chip_wcs: # Turn off distortion model for each input cw.sip = None cw.cpdis1 = None cw.cpdis2 = None cw.det2im = None undistort=False hstwcs_list += chip_wcs if not undistort and len(hstwcs_list) == 1: default_wcs = hstwcs_list[0].deepcopy() else: default_wcs = utils.output_wcs(hstwcs_list, undistort=undistort) if perfect: default_wcs.wcs.cd = make_perfect_cd(default_wcs) # Turn WCS instances into WCSObject instances outwcs = createWCSObject(output, default_wcs, imageObjectList) # Merge in user-specified attributes for the output WCS # as recorded in the input configObj object. final_pars = DEFAULT_WCS_PARS.copy() # More interpretation of the configObj needs to be done here to translate # the input parameter names to those understood by 'mergeWCS' as defined # by the DEFAULT_WCS_PARS dictionary. single_step = configObj[util.getSectionName(configObj, 3)] singleParDict = configObj[util.getSectionName(configObj, '3a')].copy() if single_step['driz_separate'] and singleParDict['driz_sep_wcs']: single_pars = DEFAULT_WCS_PARS.copy() del singleParDict['driz_sep_wcs'] keyname = 'driz_sep_' for key in singleParDict: k = key[len(keyname):] if k != 'refimage': single_pars[k] = singleParDict[key] # Now, account for any user-specified reference image def_wcs = default_wcs.deepcopy() if singleParDict[keyname + 'refimage']: default_wcs = wcsutil.HSTWCS(singleParDict[keyname + 'refimage']) ### Create single_wcs instance based on user parameters outwcs.single_wcs = mergeWCS(default_wcs, single_pars) # restore global default WCS to original value so single_drizzle WCS does not # influence final_drizzle WCS default_wcs = def_wcs.deepcopy() final_step = configObj[util.getSectionName(configObj,7)] finalParDict = configObj[util.getSectionName(configObj,'7a')].copy() if final_step['driz_combine'] and finalParDict['final_wcs']: del finalParDict['final_wcs'] keyname = 'final_' for key in finalParDict: k = key[len(keyname):] if k != 'refimage': final_pars[k] = finalParDict[key] # Now, account for any user-specified reference image if finalParDict[keyname + 'refimage']: rootname,extnum = fileutil.parseFilename(finalParDict[keyname+'refimage']) extnum = util.findWCSExtn(finalParDict[keyname+'refimage']) print('Creating OUTPUT WCS from {}[{}]'.format(rootname,extnum)) default_wcs = wcsutil.HSTWCS('{}[{}]'.format(rootname,extnum)) ### Create single_wcs instance based on user parameters outwcs.final_wcs = mergeWCS(default_wcs, final_pars) outwcs.wcs = outwcs.final_wcs.copy() # Apply user settings to create custom output_wcs instances # for each drizzle step updateImageWCS(imageObjectList, outwcs) return outwcs