def getMdriztabParameters(files): """ Gets entry in MDRIZTAB where task parameters live. This method returns a record array mapping the selected row. """ # Get the MDRIZTAB table file name from the primary header. # It is gotten from the first file in the input list. No # consistency checks are performed. _fileName = files[0] _header = fileutil.getHeader(_fileName) if 'MDRIZTAB' in _header: _tableName = _header['MDRIZTAB'] else: raise KeyError("No MDRIZTAB found in file " + _fileName) _tableName = fileutil.osfn(_tableName) # Now get the filters from the primary header. _filters = fileutil.getFilterNames(_header) # Specifically check to see whether the MDRIZTAB file can be found mtab_path = os.path.split(_tableName)[0] # protect against no path given for _tableName if mtab_path and not os.path.exists(mtab_path): # check path first, if given raise IOError("Directory for MDRIZTAB '%s' could not be accessed!"%mtab_path) if not os.path.exists(_tableName): # then check for the table itself raise IOError("MDRIZTAB table '%s' could not be found!"%_tableName) # Open MDRIZTAB file. try: _mdriztab = fits.open(_tableName, memmap=False) except: raise IOError("MDRIZTAB table '%s' not valid!" % _tableName) # Look for matching rows based on filter name. If no # match, pick up rows for the default filter. _rows = _getRowsByFilter(_mdriztab, _filters) if _rows == []: _rows = _getRowsByFilter(_mdriztab, 'ANY') # Now look for the row that matches the number of images. # The logic below assumes that rows for a given filter # are arranged in ascending order of the 'numimage' field. _nimages = len(files) _row = 0 for i in _rows: _numimages = _mdriztab[1].data.field('numimages')[i] if _nimages >= _numimages: _row = i print('- MDRIZTAB: AstroDrizzle parameters read from row %s.'%(_row+1)) mpars = _mdriztab[1].data[_row] _mdriztab.close() interpreted = _interpretMdriztabPars(mpars) if "staticfile" in interpreted: interpreted.pop("staticfile") return interpreted
def getMdriztabParameters(files): """ Gets entry in MDRIZTAB where task parameters live. This method returns a record array mapping the selected row. """ # Get the MDRIZTAB table file name from the primary header. # It is gotten from the first file in the input list. No # consistency checks are performed. _fileName = files[0] _header = fileutil.getHeader(_fileName) if 'MDRIZTAB' in _header: _tableName = _header['MDRIZTAB'] else: raise KeyError("No MDRIZTAB found in file " + _fileName) _tableName = fileutil.osfn(_tableName) # Now get the filters from the primary header. _filters = fileutil.getFilterNames(_header) # Specifically check to see whether the MDRIZTAB file can be found mtab_path = os.path.split(_tableName)[0] # protect against no path given for _tableName if mtab_path and not os.path.exists(mtab_path): # check path first, if given raise IOError("Directory for MDRIZTAB '%s' could not be accessed!"%mtab_path) if not os.path.exists(_tableName): # then check for the table itself raise IOError("MDRIZTAB table '%s' could not be found!"%_tableName) # Open MDRIZTAB file. try: _mdriztab = fits.open(_tableName) except: raise IOError("MDRIZTAB table '%s' not valid!" % _tableName) # Look for matching rows based on filter name. If no # match, pick up rows for the default filter. _rows = _getRowsByFilter(_mdriztab, _filters) if _rows == []: _rows = _getRowsByFilter(_mdriztab, 'ANY') # Now look for the row that matches the number of images. # The logic below assumes that rows for a given filter # are arranged in ascending order of the 'numimage' field. _nimages = len(files) _row = 0 for i in _rows: _numimages = _mdriztab[1].data.field('numimages')[i] if _nimages >= _numimages: _row = i print('- MDRIZTAB: AstroDrizzle parameters read from row %s.'%(_row+1)) mpars = _mdriztab[1].data[_row] _mdriztab.close() interpreted = _interpretMdriztabPars(mpars) if "staticfile" in interpreted: interpreted.pop("staticfile") return interpreted
def getIDCFile(image,keyword="",directory=None): # Open the primary header of the file and read the name of # the IDCTAB. # Parameters: # header - primary and extension header object to read IDCTAB info # # keyword(optional) - header keyword with name of IDCTAB # --OR-- 'HEADER' if need to build IDCTAB name from scratch # (default value: 'IDCTAB') # directory(optional) - directory with default drizzle coeffs tables # (default value: 'drizzle$coeffs') # # This function needs to be generalized to support # keyword='HEADER', as would be the case for WFPC2 data. # if type(image) == type(''): # We were provided an image name, so read in the header... header = fileutil.getHeader(image) else: # otherwise, we were provided an image header we can work with directly header = image if keyword.lower() == 'header': idcfile,idctype = __getIDCTAB(header) if (idcfile == None): idcfile,idctype = __buildIDCTAB(header,directory) elif keyword.lower() == 'idctab': # keyword specifies header keyword with IDCTAB name idcfile,idctype = __getIDCTAB(header) elif keyword == '': idcfile = None idctype = None else: # Need to build IDCTAB filename from scratch idcfile,idctype = __buildIDCTAB(header,directory,kw = keyword) # Account for possible absence of IDCTAB name in header if idcfile == 'N/A': idcfile = None if idcfile != None and idcfile != '': # Now we need to recursively expand any IRAF symbols to full paths... #if directory: idcfile = fileutil.osfn(idcfile) if idcfile == None: print('WARNING: No valid distortion coefficients available!') print('Using default unshifted, unscaled, unrotated model.') return idcfile,idctype
def getExptime(self): header = fileutil.getHeader(self.name+'[sci,1]') _exptime = float(header['EXPTIME']) if _exptime == 0.: _exptime = 1.0 if 'EXPSTART' in header: _expstart = float(header['EXPSTART']) _expend = float(header['EXPEND']) else: _expstart = 0. _expend = _exptime return (_exptime,_expstart,_expend)
def check_exptime(filelist): """ Removes files with EXPTIME==0 from filelist. """ removed_files = [] for f in filelist: try: exptime = fileutil.getHeader(f+'[sci,1]')['EXPTIME'] except KeyError: removed_files.append(f) print("Warning: There are files without keyword EXPTIME") continue if exptime <= 0: removed_files.append(f) print("Warning: There are files with zero exposure time: keyword EXPTIME = 0.0") if removed_files != []: print("Warning: Removing the following files from input list") for f in removed_files: print('\t',f) return removed_files
def check_exptime(filelist): """ Removes files with EXPTIME==0 from filelist. """ removed_files = [] for f in filelist: try: exptime = fileutil.getHeader(f + '[sci,1]')['EXPTIME'] except KeyError: removed_files.append(f) print("Warning: There are files without keyword EXPTIME") continue if exptime <= 0: removed_files.append(f) print( "Warning: There are files with zero exposure time: keyword EXPTIME = 0.0" ) if removed_files != []: print("Warning: Removing the following files from input list") for f in removed_files: print('\t', f) return removed_files
def _getInputImage (input,group=None): """ Factory function to return appropriate imageObject class instance""" # extract primary header and SCI,1 header from input image sci_ext = 'SCI' if group in [None,'']: exten = '[sci,1]' phdu = fits.getheader(input, memmap=False) else: # change to use fits more directly here? if group.find(',') > 0: grp = group.split(',') if grp[0].isalpha(): grp = (grp[0],int(grp[1])) else: grp = int(grp[0]) else: grp = int(group) phdu = fits.getheader(input, memmap=False) phdu.extend(fits.getheader(input, ext=grp, memmap=False)) # Extract the instrument name for the data that is being processed by Multidrizzle _instrument = phdu['INSTRUME'] # Determine the instrument detector in use. NICMOS is a special case because it does # not use the 'DETECTOR' keyword. It instead used 'CAMERA' to identify which of it's # 3 camera's is in use. All other instruments support the 'DETECTOR' keyword. if _instrument == 'NICMOS': _detector = phdu['CAMERA'] else: try: _detector = phdu['DETECTOR'] except KeyError: # using the phdu as set above (fits.getheader) is MUCH faster and # works for the majority of data; but fileutil handles waivered fits phdu = fileutil.getHeader(input+exten) _detector = phdu['DETECTOR'] # if this fails, let it throw del phdu # just to keep clean # Match up the instrument and detector with the right class # only importing the instrument modules as needed. try: if _instrument == 'ACS': from . import acsData if _detector == 'HRC': return acsData.HRCInputImage(input,group=group) if _detector == 'WFC': return acsData.WFCInputImage(input,group=group) if _detector == 'SBC': return acsData.SBCInputImage(input,group=group) if _instrument == 'NICMOS': from . import nicmosData if _detector == 1: return nicmosData.NIC1InputImage(input) if _detector == 2: return nicmosData.NIC2InputImage(input) if _detector == 3: return nicmosData.NIC3InputImage(input) if _instrument == 'WFPC2': from . import wfpc2Data return wfpc2Data.WFPC2InputImage(input,group=group) """ if _detector == 1: return wfpc2Data.PCInputImage(input) if _detector == 2: return wfpc2Data.WF2InputImage(input) if _detector == 3: return wfpc2Data.WF3InputImage(input) if _detector == 4: return wfpc2Data.WF4InputImage(input) """ if _instrument == 'STIS': from . import stisData if _detector == 'CCD': return stisData.CCDInputImage(input,group=group) if _detector == 'FUV-MAMA': return stisData.FUVInputImage(input,group=group) if _detector == 'NUV-MAMA': return stisData.NUVInputImage(input,group=group) if _instrument == 'WFC3': from . import wfc3Data if _detector == 'UVIS': return wfc3Data.WFC3UVISInputImage(input,group=group) if _detector == 'IR': return wfc3Data.WFC3IRInputImage(input,group=group) except ImportError: msg = 'No module implemented for '+str(_instrument)+'!' raise ValueError(msg) # If a supported instrument is not detected, print the following error message # and raise an exception. msg = 'Instrument: ' + str(_instrument) + '/' + str(_detector) + ' not yet supported!' raise ValueError(msg)
def _getInputImage(input, output=None, group=None): """ Factory function to return appropriate imageObject class instance""" # extract primary header and SCI,1 header from input image sci_ext = 'SCI' if group in [None, '']: exten = '[sci,1]' phdu = fits.getheader(input, memmap=False) else: # change to use fits more directly here? if group.find(',') > 0: grp = group.split(',') if grp[0].isalpha(): grp = (grp[0], int(grp[1])) else: grp = int(grp[0]) else: grp = int(group) phdu = fits.getheader(input, memmap=False) phdu.extend(fits.getheader(input, ext=grp, memmap=False)) # Extract the instrument name for the data that is being processed by Multidrizzle _instrument = phdu['INSTRUME'] # Determine the instrument detector in use. NICMOS is a special case because it does # not use the 'DETECTOR' keyword. It instead used 'CAMERA' to identify which of it's # 3 camera's is in use. All other instruments support the 'DETECTOR' keyword. if _instrument == 'NICMOS': _detector = phdu['CAMERA'] else: try: _detector = phdu['DETECTOR'] except KeyError: # using the phdu as set above (fits.getheader) is MUCH faster and # works for the majority of data; but fileutil handles waivered fits phdu = fileutil.getHeader(input + exten) _detector = phdu['DETECTOR'] # if this fails, let it throw del phdu # just to keep clean # Match up the instrument and detector with the right class # only importing the instrument modules as needed. try: if _instrument == 'ACS': from . import acsData if _detector == 'HRC': return acsData.HRCInputImage(input, output=output, group=group) if _detector == 'WFC': return acsData.WFCInputImage(input, output=output, group=group) if _detector == 'SBC': return acsData.SBCInputImage(input, output=output, group=group) if _instrument == 'NICMOS': from . import nicmosData if _detector == 1: return nicmosData.NIC1InputImage(input, output=output) if _detector == 2: return nicmosData.NIC2InputImage(input, output=output) if _detector == 3: return nicmosData.NIC3InputImage(input, output=output) if _instrument == 'WFPC2': from . import wfpc2Data return wfpc2Data.WFPC2InputImage(input, output=output, group=group) """ if _detector == 1: return wfpc2Data.PCInputImage(input) if _detector == 2: return wfpc2Data.WF2InputImage(input) if _detector == 3: return wfpc2Data.WF3InputImage(input) if _detector == 4: return wfpc2Data.WF4InputImage(input) """ if _instrument == 'STIS': from . import stisData if _detector == 'CCD': return stisData.CCDInputImage(input, output=output, group=group) if _detector == 'FUV-MAMA': return stisData.FUVInputImage(input, output=output, group=group) if _detector == 'NUV-MAMA': return stisData.NUVInputImage(input, output=output, group=group) if _instrument == 'WFC3': from . import wfc3Data if _detector == 'UVIS': return wfc3Data.WFC3UVISInputImage(input, output=output, group=group) if _detector == 'IR': return wfc3Data.WFC3IRInputImage(input, output=output, group=group) except ImportError: msg = 'No module implemented for ' + str(_instrument) + '!' raise ValueError(msg) # If a supported instrument is not detected, print the following error message # and raise an exception. msg = 'Instrument: ' + str(_instrument) + '/' + str( _detector) + ' not yet supported!' raise ValueError(msg)
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