def prepare(filenames, obsparam, header_update, keep_wcs=False, flipx=False, flipy=False, rotate=0, man_ra=None, man_dec=None, diagnostics=False, display=False): """ prepare wrapper output: diagnostic properties """ # start logging logging.info('preparing data with parameters: %s' % (', '.join([('%s: %s' % (var, str(val))) for var, val in list(locals().items())]))) # change FITS file extensions to .fits for idx, filename in enumerate(filenames): if filename.split('.')[-1] in ['fts', 'FTS', 'FITS', 'fit', 'FIT']: os.rename(filename, '.'.join(filename.split('.')[:-1])+'.fits') filenames[idx] = '.'.join(filename.split('.')[:-1])+'.fits' logging.info('change filename from "%s" to "%s"' % (filename, filenames[idx])) # identify keywords for GENERIC telescopes # open one sample image file hdulist = fits.open(filenames[0], verify='ignore', ignore_missing_end='True') header = hdulist[0].header # check if this is a single-extension FITS file if float(header['NAXIS']) > 2.: logging.error('This is not a single-extension FITS file. Please ' 'extract individual extensions and run them ' 'individually.') sys.exit() # keywords that have to be implanted into each image implants = {} # if GENERIC telescope, ask user for header keywords if obsparam['telescope_keyword'] is 'GENERIC': keywords = {'pixel scale in arcsec/px before binning': 'secpix', 'binning factor in both axes': 'binning', 'image center RA (keyword or degrees)': 'ra', 'image center DEC (keyword or degrees)': 'dec', 'filter used (clear if none was used)': 'filter', 'observation midtime': 'date_keyword', 'exposure time (seconds)': 'exptime'} for description, keyword in list(keywords.items()): try: if obsparam[keyword] in header: continue except: pass inp = input('%s? > ' % description) if keyword is 'secpix': obsparam[keyword] = (float(inp), float(inp)) if keyword is 'binning': implants['BINX'] = (float(inp), 'PP: user-defined') implants['BINY'] = (float(inp), 'PP: user-defined') if keyword is 'ra': try: implants['OBJCTRA'] = (float(inp), 'PP: user_defined') obsparam['radec_separator'] = 'XXX' except TypeError: obsparam['ra'] = inp # # check for separator # try: # dummy = float(header[inp]) # obsparam['radec_separator'] = 'XXX' # except ValueError: # if ':' in header[inp]: # obsparam['radec_separator'] = ':' # if ' ' in header[inp].strip(): # obsparam['radec_separator'] = ' ' if keyword is 'dec': try: implants['OBJCTDEC'] = (float(inp), 'PP: user_defined') obsparam['radec_separator'] = 'XXX' except TypeError: obsparam['dec'] = inp if keyword is 'filter': implants[obsparam['filter']] = (inp, 'PP: user-defined') if keyword is 'date_keyword': obsparam['date_keyword'] = inp if keyword is 'exptime': implants['EXPTIME'] = (float(inp), 'PP: user-defined') implants['INSTRUME'] = ('GENERIC', 'PP: manually set') # prepare image headers for photometry pipeline for filename in filenames: if display: print('preparing', filename) # open image file hdulist = fits.open(filename, mode='update', verify='silentfix', ignore_missing_end=True) header = hdulist[0].header # add other headers, if available if len(hdulist) > 1: for i in range(len(hdulist)): try: header += hdulist[i].header except: pass # account for flips and rotation in telescope configuration # if instrument has several chips... if 'chip_id' in obsparam: chip_id = header[obsparam['chip_id']] this_flipx = obsparam['flipx'][chip_id] this_flipy = obsparam['flipy'][chip_id] this_rotate = obsparam['rotate'][chip_id] # if not... else: this_flipx = obsparam['flipx'] this_flipy = obsparam['flipy'] this_rotate = obsparam['rotate'] if flipx: this_flipx = numpy.invert(this_flipx) if flipy: this_flipy = numpy.invert(this_flipy) if rotate > 0: this_rotate += rotate # read image data imdata = hdulist[0].data # check if image is a cube, or a single frame put into a cube if len(imdata.shape) > 2: # this image is a cube if imdata.shape[0] == 1: # this is a single image put into a cube # turn this into a single-frame fits file imdata = imdata[0] else: # this is really a cube; don't know what to do raise TypeError(("%s is a cube FITS file; don't know how to " "handle this file...") % filename) # add header keywords for Source Extractor if 'EPOCH' not in header: header['EPOCH'] = (2000, 'PP: required for registration') # if 'EQUINOX' not in header: # header['EQUINOX'] = (2000, 'PP: required for registration') # add header keywords for SCAMP header['PHOTFLAG'] = ('F', 'PP: data is not photometric (SCAMP)') header['PHOT_K'] = (0.05, 'PP: assumed extinction coefficient') if not keep_wcs: # remove keywords that might collide with fake wcs for key in list(header.keys()): if re.match('^CD[1,2]_[1,2]', key) is not None: # if key not in obsparam.values(): # header.remove(key) if not toolbox.if_val_in_dict(key, obsparam): header.remove(key) elif 'PV' in key and '_' in key: header.remove(key) elif key in ['CTYPE1', 'CRPIX1', 'CRVAL1', 'CROTA1', 'CROTA2', 'CFINT1', 'CTYPE2', 'CRPIX2', 'CRVAL2', 'CFINT2', 'LTM1_1', 'LTM2_2', 'WAT0_001', 'LTV1', 'LTV2', 'PIXXMIT', 'PIXOFFST', 'PC1_1', 'PC1_2', 'PC2_1', 'PC2_2', #'CUNIT1', 'CUNIT2', 'A_ORDER', 'A_0_0', 'A_0_1', 'A_0_2', 'A_1_0', 'A_1_1', 'A_2_0', 'B_ORDER', 'B_0_0', 'B_0_1', 'B_0_2', 'B_1_0', 'B_1_1', 'B_2_0', 'AP_ORDER', 'AP_0_0', 'AP_0_1', 'AP_0_2', 'AP_1_0', 'AP_1_1', 'AP_2_0', 'BP_ORDER', 'BP_0_0', 'BP_0_1', 'BP_0_2', 'BP_1_0', 'BP_1_1', 'BP_2_0', 'CDELT1', 'CDELT2', 'CRDELT1', 'CRDELT2']: if not toolbox.if_val_in_dict(key, obsparam): header.remove(key) # normalize CUNIT keywords try: if 'degree' in header['CUNIT1'].lower(): header['CUNIT1'] = ('deg') if 'degree' in header['CUNIT2'].lower(): header['CUNIT2'] = ('deg') except KeyError: pass # if GENERIC telescope, add implants to header if obsparam['telescope_keyword'] is 'GENERIC': for key, val in list(implants.items()): header[key] = (val[0], val[1]) # read out image binning mode binning = toolbox.get_binning(header, obsparam) # add pixel resolution keyword header['SECPIXX'] = (obsparam['secpix'][0]*binning[0], 'PP: x pixscale after binning') header['SECPIXY'] = (obsparam['secpix'][1]*binning[1], 'PP: y pixscale after binning') # create observation midtime jd if not keep_wcs or 'MIDTIMJD' not in header: if obsparam['date_keyword'].find('|') == -1: header['MIDTIMJD'] = \ (toolbox.dateobs_to_jd(header[obsparam['date_keyword']]) + float(header[obsparam['exptime']])/2./86400., 'PP: obs midtime') else: datetime = (header[obsparam['date_keyword'].split('|')[0]] + 'T' + header[obsparam['date_keyword'].split('|')[1]]) datetime = datetime.replace('/', '-') header['MIDTIMJD'] = (toolbox.dateobs_to_jd(datetime) + float(header[obsparam['exptime']])/2./86400., 'PP: obs midtime') # other keywords header['TELINSTR'] = (obsparam['telescope_instrument'], 'PP: tel/instr name') header['TEL_KEYW'] = (obsparam['telescope_keyword'], 'PP: tel/instr keyword') header['FILTER'] = (header[obsparam['filter']], 'PP:copied') header['EXPTIME'] = (header[obsparam['exptime']], 'PP: copied') if obsparam['airmass'] in header: header['AIRMASS'] = (header[obsparam['airmass']], 'PP: copied') else: header['AIRMASS'] = (1, 'PP: fake airmass') # check if filter can be translated by PP try: obsparam['filter_translations'][header[obsparam['filter']]] except KeyError: logging.warning('cannot translate filter keyword \"' + header[obsparam['filter']] + '\"; assume clear filter') header[obsparam['filter']] = 'clear' header['FILTER'] = (header[obsparam['filter']], 'PP:copied') # perform header update for key, value in list(header_update.items()): if key in header: header['_'+key[:6]] = (header[key], 'PP: old value for %s' % key) header[key] = (value, 'PP: manually updated') # check if OBJECT keyword is available if 'OBJECT' not in header: header['OBJECT'] = 'None' elif len(header['OBJECT'].strip()) == 0: header['OBJECT'] = 'None' # # check if RA, Dec, airmass headers are available; # # else: query horizons # # to get approximate information # if (obsparam['ra'] not in header or # obsparam['dec'] not in header or # obsparam['airmass'] not in header): # logging.info('Either RA, Dec, or airmass missing from image ' + # 'header; pull approximate information for Horizons') # # obtain approximate ra and dec (and airmass) from JPL Horizons # eph = callhorizons.query(header[obsparam['object']]. # replace('_', ' ')) # eph.set_discreteepochs(header['MIDTIMJD']) # try: # n = eph.get_ephemerides(obsparam['observatory_code']) # except ValueError: # logging.warning('Target (%s) is not an asteroid' % # header[obsparam['object']]) # n = None # if n is None: # raise KeyError((('%s is not an asteroid known ' # 'to JPL Horizons') % # header[obsparam['object']])) # header[obsparam['ra']] = (eph['RA'][0], # 'PP: queried from Horizons') # header[obsparam['dec']] = (eph['DEC'][0], # 'PP: queried from Horizons') # header[obsparam['airmass']] = (eph['airmass'][0], # 'PP: queried from Horizons') # add fake wcs information that is necessary to run SCAMP # read out ra and dec from header if obsparam['radec_separator'] == 'XXX': ra_deg = float(header[obsparam['ra']]) dec_deg = float(header[obsparam['dec']]) else: ra_string = header[obsparam['ra']].split( obsparam['radec_separator']) dec_string = header[obsparam['dec']].split( obsparam['radec_separator']) ra_deg = 15.*(float(ra_string[0]) + old_div(float(ra_string[1]), 60.) + old_div(float(ra_string[2]), 3600.)) dec_deg = (abs(float(dec_string[0])) + old_div(float(dec_string[1]), 60.) + old_div(float(dec_string[2]), 3600.)) if dec_string[0].find('-') > -1: dec_deg = -1 * dec_deg # transform to equinox J2000, if necessary if 'EQUINOX' in header: equinox = float(header['EQUINOX']) if equinox != 2000.: anyeq = SkyCoord(ra=ra_deg*u.deg, dec=dec_deg*u.deg, frame=FK5, equinox=Time(equinox, format='jyear', scale='utc')) coo = anyeq.transform_to(ICRS) ra_deg = coo.ra.deg dec_deg = coo.dec.deg header['EQUINOX'] = (2000.0, 'PP: normalized to ICRS') if man_ra is not None and man_dec is not None: ra_deg = float(man_ra) dec_deg = float(man_dec) # special treatment for UKIRT/WFCAM if obsparam['telescope_keyword'] == 'UKIRTWFCAM': ra_deg = (float(header['TELRA'])/24.*360. - old_div(float(header['JITTER_X']), 3600.)) dec_deg = (float(header['TELDEC']) - old_div(float(header['JITTER_Y']), 3600.)) # apply flips xnorm, ynorm = 1, 1 if this_flipx: xnorm = -1 if this_flipy: ynorm = -1 # check if instrument has a chip offset ra_offset, dec_offset = 0, 0 if (man_ra is None or man_dec is None) and \ 'chip_offset_fixed' in obsparam: cid = header[obsparam['chip_id']] ra_offset = float(obsparam['chip_offset_fixed'][cid][0]) dec_offset = float(obsparam['chip_offset_fixed'][cid][1]) if not keep_wcs: # create fake header header['RADECSYS'] = ('FK5', 'PP: fake wcs coordinates') header['RADESYS'] = ('FK5', 'PP: fake wcs coordinates') header['CTYPE1'] = ('RA---TAN', 'PP: fake Coordinate type') header['CTYPE2'] = ('DEC--TAN', 'PP: fake Coordinate type') header['CRVAL1'] = (ra_deg+ra_offset, 'PP: fake Coordinate reference value') header['CRVAL2'] = (dec_deg+dec_offset, 'PP: fake Coordinate reference value') header['CRPIX1'] = (int(old_div( float(header[obsparam['extent'][0]]), 2)), 'PP: fake Coordinate reference pixel') header['CRPIX2'] = (int(old_div( float(header[obsparam['extent'][1]]), 2)), 'PP: fake Coordinate reference pixel') # plugin default distortion parameters, if available if 'distort' in obsparam: if 'functionof' in obsparam['distort']: pv_dict = obsparam['distort'][header[obsparam['distort'] ['functionof']]] else: pv_dict = obsparam['distort'] try: for pv_key, pv_val in pv_dict.items(): header[pv_key] = (pv_val, 'PP: default distortion') except KeyError: logging.error(('No distortion coefficients available for ' '%s %s') % (obsparam['distort']['functionof'], header[obsparam['distort'] ['functionof']])) header['CD1_1'] = (xnorm * numpy.cos(this_rotate/180.*numpy.pi) * obsparam['secpix'][0]*binning[0]/3600., 'PP: fake Coordinate matrix') header['CD1_2'] = (ynorm * -numpy.sin(this_rotate/180.*numpy.pi) * obsparam['secpix'][1]*binning[1]/3600., 'PP: fake Coordinate matrix') header['CD2_1'] = (xnorm * numpy.sin(this_rotate/180.*numpy.pi) * obsparam['secpix'][0]*binning[0]/3600., 'PP: fake Coordinate matrix') header['CD2_2'] = (ynorm * numpy.cos(this_rotate/180.*numpy.pi) * obsparam['secpix'][1]*binning[1]/3600., 'PP: fake Coordinate matrix') # crop center from LOWELL42 frames if obsparam['telescope_keyword'] == 'LOWELL42': imdata = imdata[100:-100, 100:-100] logging.info('cropping LOWELL42 data') # overwrite imdata in case something has been modified hdulist[0].data = imdata hdulist.flush() hdulist.close() logging.info('created fake wcs information for image %s' % filename) # create diagnostics if diagnostics: diag.create_index(filenames, os.getcwd(), obsparam, display) logging.info('Done! -----------------------------------------------------') return None
def create_index(filenames, directory, obsparam, display=False): """ create index.html diagnostic root website for one pipeline process """ if display: print('create frame index table and frame images') logging.info('create frame index table and frame images') # obtain filtername from first image file refheader = fits.open(filenames[0], ignore_missing_end=True)[0].header filtername = obsparam['filter_translations'][refheader[obsparam['filter']]] del (refheader) html = "<H2>data directory: %s</H2>\n" % directory html += ("<H1>%s/%s-band - Diagnostic Output</H1>\n" + \ "%d frames total, see full pipeline " + \ "<A HREF=\"%s\">log</A> for more information\n") % \ (obsparam['telescope_instrument'], filtername, len(filenames), '.diagnostics/' + _pp_conf.log_filename.split('.diagnostics/')[1]) ### create frame information table html += "<P><TABLE BORDER=\"1\">\n<TR>\n" html += "<TH>Idx</TH><TH>Filename</TH><TH>Midtime (JD)</TH>" + \ "<TH>Objectname</TH><TH>Filter</TH>" + \ "<TH>Airmass</TH><TH>Exptime (s)</TH>" + \ "<TH>FoV (arcmin)</TH>\n</TR>\n" # fill table and create frames filename = filenames for idx, filename in enumerate(filenames): ### fill table hdulist = fits.open(filename, ignore_missing_end=True) header = hdulist[0].header # read out image binning mode binning = toolbox.get_binning(header, obsparam) #framefilename = _pp_conf.diagroot + '/' + filename + '.png' framefilename = '.diagnostics/' + filename + '.png' try: objectname = header[obsparam['object']] except KeyError: objectname = 'Unknown Target' html += ("<TR><TD>%d</TD><TD><A HREF=\"%s\">%s</A></TD>" + \ "<TD>%16.8f</TD><TD>%s</TD>" + \ "<TD>%s</TD><TD>%4.2f</TD><TD>%.1f</TD>" + \ "<TD>%.1f x %.1f</TD>\n</TR>\n") % \ (idx+1, framefilename, filename, header["MIDTIMJD"], objectname, header[obsparam['filter']], float(header[obsparam['airmass']]), float(header[obsparam['exptime']]), header[obsparam['extent'][0]]*obsparam['secpix'][0]*binning[0]/60., header[obsparam['extent'][1]]*obsparam['secpix'][1]*binning[1]/60.) ### create frame image imgdat = hdulist[0].data imgdat = imresize(imgdat, min(1., 1000. / numpy.max(imgdat.shape)), interp='nearest') # resize image larger than 1000px on one side median = numpy.median( imgdat[int(imgdat.shape[1] * 0.25):int(imgdat.shape[1] * 0.75), int(imgdat.shape[0] * 0.25):int(imgdat.shape[0] * 0.75)]) std = numpy.std( imgdat[int(imgdat.shape[1] * 0.25):int(imgdat.shape[1] * 0.75), int(imgdat.shape[0] * 0.25):int(imgdat.shape[0] * 0.75)]) plt.figure(figsize=(5, 5)) img = plt.imshow(imgdat, cmap='gray', vmin=median - 1.5 * std, vmax=median + 1.5 * std, origin='lower') # remove axes plt.axis('off') img.axes.get_xaxis().set_visible(False) img.axes.get_yaxis().set_visible(False) plt.savefig(framefilename, format='png', bbox_inches='tight', pad_inches=0, dpi=200) plt.close() hdulist.close() del (imgdat) html += '</TABLE>\n' create_website(_pp_conf.index_filename, html) ### add to summary website, if requested if _pp_conf.use_diagnostics_summary: add_to_summary(header[obsparam['object']], filtername, len(filenames)) return None
def prepare(filenames, obsparam, header_update, keep_wcs=False, flipx=False, flipy=False, rotate=0, man_ra=None, man_dec=None, diagnostics=False, display=False): """ prepare wrapper output: diagnostic properties """ # start logging logging.info('preparing data with parameters: %s' % (', '.join([('%s: %s' % (var, str(val))) for var, val in list(locals().items())]))) # change FITS file extensions to .fits for idx, filename in enumerate(filenames): if filename.split('.')[-1] in ['fts', 'FTS', 'FITS', 'fit', 'FIT']: os.rename(filename, '.'.join(filename.split('.')[:-1])+'.fits') filenames[idx] = '.'.join(filename.split('.')[:-1])+'.fits' logging.info('change filename from "%s" to "%s"' % (filename, filenames[idx])) # identify keywords for GENERIC telescopes # open one sample image file hdulist = fits.open(filenames[0], verify='ignore', ignore_missing_end='True') header = hdulist[0].header # check if this is a single-extension FITS file if float(header['NAXIS']) > 2.: logging.error('This is not a single-extension FITS file. Please ' 'extract individual extensions and run them ' 'individually.') sys.exit() # keywords that have to be implanted into each image implants = {} # if GENERIC telescope, ask user for header keywords if obsparam['telescope_keyword'] is 'GENERIC': keywords = {'pixel scale in arcsec/px before binning': 'secpix', 'binning factor in both axes': 'binning', 'image center RA (keyword or degrees)': 'ra', 'image center DEC (keyword or degrees)': 'dec', 'filter used (clear if none was used)': 'filter', 'observation midtime': 'date_keyword', 'exposure time (seconds)': 'exptime'} for description, keyword in list(keywords.items()): try: if obsparam[keyword] in header: continue except: pass inp = input('%s? > ' % description) if keyword is 'secpix': obsparam[keyword] = (float(inp), float(inp)) if keyword is 'binning': implants['BINX'] = (float(inp), 'PP: user-defined') implants['BINY'] = (float(inp), 'PP: user-defined') if keyword is 'ra': try: implants['OBJCTRA'] = (float(inp), 'PP: user_defined') obsparam['radec_separator'] = 'XXX' except TypeError: obsparam['ra'] = inp # # check for separator # try: # dummy = float(header[inp]) # obsparam['radec_separator'] = 'XXX' # except ValueError: # if ':' in header[inp]: # obsparam['radec_separator'] = ':' # if ' ' in header[inp].strip(): # obsparam['radec_separator'] = ' ' if keyword is 'dec': try: implants['OBJCTDEC'] = (float(inp), 'PP: user_defined') obsparam['radec_separator'] = 'XXX' except TypeError: obsparam['dec'] = inp if keyword is 'filter': implants[obsparam['filter']] = (inp, 'PP: user-defined') if keyword is 'date_keyword': obsparam['date_keyword'] = inp if keyword is 'exptime': implants['EXPTIME'] = (float(inp), 'PP: user-defined') implants['INSTRUME'] = ('GENERIC', 'PP: manually set') # prepare image headers for photometry pipeline for filename in filenames: if display: print('preparing', filename) # open image file hdulist = fits.open(filename, mode='update', verify='silentfix', ignore_missing_end=True) header = hdulist[0].header # add other headers, if available if len(hdulist) > 1: for i in range(len(hdulist)): try: header += hdulist[i].header except: pass # account for flips and rotation in telescope configuration # if instrument has several chips... if 'chip_id' in obsparam: chip_id = header[obsparam['chip_id']] this_flipx = obsparam['flipx'][chip_id] this_flipy = obsparam['flipy'][chip_id] this_rotate = obsparam['rotate'][chip_id] # if not... else: this_flipx = obsparam['flipx'] this_flipy = obsparam['flipy'] this_rotate = obsparam['rotate'] if flipx: this_flipx = numpy.invert(this_flipx) if flipy: this_flipy = numpy.invert(this_flipy) if rotate > 0: this_rotate += rotate # read image data imdata = hdulist[0].data # check if image is a cube, or a single frame put into a cube if len(imdata.shape) > 2: # this image is a cube if imdata.shape[0] == 1: # this is a single image put into a cube # turn this into a single-frame fits file imdata = imdata[0] else: # this is really a cube; don't know what to do raise TypeError(("%s is a cube FITS file; don't know how to " "handle this file...") % filename) # add header keywords for Source Extractor if 'EPOCH' not in header: header['EPOCH'] = (2000, 'PP: required for registration') # add header keywords for SCAMP header['PHOTFLAG'] = ('F', 'PP: data is not photometric (SCAMP)') header['PHOT_K'] = (0.05, 'PP: assumed extinction coefficient') if not keep_wcs: # remove keywords that might collide with fake wcs for key in list(header.keys()): if re.match('^CD[1,2]_[1,2]', key) is not None: # if key not in obsparam.values(): # header.remove(key) if not toolbox.if_val_in_dict(key, obsparam): header.remove(key) elif 'PV' in key and '_' in key: header.remove(key) elif key in (['CTYPE1', 'CRPIX1', 'CRVAL1', 'CROTA1', 'CROTA2', 'CFINT1', 'CTYPE2', 'CRPIX2', 'CRVAL2', 'CFINT2', 'LTM1_1', 'LTM2_2', 'WAT0_001', 'LTV1', 'LTV2', 'PIXXMIT', 'PIXOFFST', 'PC1_1', 'PC1_2', 'PC2_1', 'PC2_2', 'A_ORDER', 'A_0_0', 'A_0_1', 'A_0_2', 'A_1_0', 'A_1_1', 'A_2_0', 'B_ORDER', 'B_0_0', 'B_0_1', 'B_0_2', 'B_1_0', 'B_1_1', 'B_2_0', 'AP_ORDER', 'AP_0_0', 'AP_0_1', 'AP_0_2', 'AP_1_0', 'AP_1_1', 'AP_2_0', 'BP_ORDER', 'BP_0_0', 'BP_0_1', 'BP_0_2', 'BP_1_0', 'BP_1_1', 'BP_2_0', 'CDELT1', 'CDELT2', 'CRDELT1', 'CRDELT2'] + ['TR{}_{}'.format(i, j) for i in range(1, 3) for j in range(15)]): if not toolbox.if_val_in_dict(key, obsparam): header.remove(key) # normalize CUNIT keywords try: if 'degree' in header['CUNIT1'].lower(): header['CUNIT1'] = ('deg') if 'degree' in header['CUNIT2'].lower(): header['CUNIT2'] = ('deg') except KeyError: pass # if GENERIC telescope, add implants to header if obsparam['telescope_keyword'] is 'GENERIC': for key, val in list(implants.items()): header[key] = (val[0], val[1]) # read out image binning mode binning = toolbox.get_binning(header, obsparam) # add pixel resolution keyword header['SECPIXX'] = (obsparam['secpix'][0]*binning[0], 'PP: x pixscale after binning') header['SECPIXY'] = (obsparam['secpix'][1]*binning[1], 'PP: y pixscale after binning') # create observation midtime jd if not keep_wcs or 'MIDTIMJD' not in header: if obsparam['date_keyword'].find('|') == -1: header['MIDTIMJD'] = \ (toolbox.dateobs_to_jd(header[obsparam['date_keyword']]) + float(header[obsparam['exptime']])/2./86400., 'PP: obs midtime') else: datetime = (header[obsparam['date_keyword'].split('|')[0]] + 'T' + header[obsparam['date_keyword'].split('|')[1]]) datetime = datetime.replace('/', '-') header['MIDTIMJD'] = (toolbox.dateobs_to_jd(datetime) + float( header[obsparam['exptime']])/2./86400., 'PP: obs midtime') # other keywords header['TELINSTR'] = (obsparam['telescope_instrument'], 'PP: tel/instr name') header['TEL_KEYW'] = (obsparam['telescope_keyword'], 'PP: tel/instr keyword') header[obsparam['filter']] = header[obsparam['filter']].strip() header['FILTER'] = (header[obsparam['filter']], 'PP:copied') header['EXPTIME'] = (header[obsparam['exptime']], 'PP: copied') if obsparam['airmass'] in header: header['AIRMASS'] = (header[obsparam['airmass']], 'PP: copied') else: header['AIRMASS'] = (1, 'PP: fake airmass') # check if filter can be translated by PP try: obsparam['filter_translations'][header[obsparam['filter']]] except KeyError: logging.warning('cannot translate filter keyword \"' + header[obsparam['filter']] + '\"') # header[obsparam['filter']] = 'clear' header['FILTER'] = (header[obsparam['filter']], 'PP:copied') # perform header update for key, value in list(header_update.items()): if key in header: header['_'+key[:6]] = (header[key], 'PP: old value for %s' % key) header[key] = (value, 'PP: manually updated') # check if OBJECT keyword is available if 'OBJECT' not in header: header['OBJECT'] = 'None' elif len(header['OBJECT'].strip()) == 0: header['OBJECT'] = 'None' # add fake wcs information that is necessary to run SCAMP # read out ra and dec from header if obsparam['radec_separator'] == 'XXX': ra_deg = float(header[obsparam['ra']]) dec_deg = float(header[obsparam['dec']]) else: ra_string = header[obsparam['ra']].split( obsparam['radec_separator']) dec_string = header[obsparam['dec']].split( obsparam['radec_separator']) ra_deg = 15.*(float(ra_string[0]) + float(ra_string[1]) / 60. + float(ra_string[2]) / 3600.) dec_deg = (abs(float(dec_string[0])) + float(dec_string[1]) / 60. + float(dec_string[2]) / 3600.) if dec_string[0].find('-') > -1: dec_deg = -1 * dec_deg # transform to equinox J2000, if necessary if 'EQUINOX' in header: equinox = float(header['EQUINOX']) if equinox != 2000.: anyeq = SkyCoord(ra=ra_deg*u.deg, dec=dec_deg*u.deg, frame=FK5, equinox=Time(equinox, format='jyear', scale='utc')) coo = anyeq.transform_to(ICRS) ra_deg = coo.ra.deg dec_deg = coo.dec.deg header['EQUINOX'] = (2000.0, 'PP: normalized to ICRS') else: header['EQUINOX'] = (2000, 'added by PP') if man_ra is not None and man_dec is not None: ra_deg = float(man_ra) dec_deg = float(man_dec) # special treatment for UKIRT/WFCAM if obsparam['telescope_keyword'] == 'UKIRTWFCAM': try: ra_deg = (float(header['TELRA'])/24.*360. - float(header['JITTER_X'])/3600) dec_deg = (float(header['TELDEC']) - float(header['JITTER_Y'])/3600) except KeyError: # JITTER keywords not in combined images pass # apply flips xnorm, ynorm = 1, 1 if this_flipx: xnorm = -1 if this_flipy: ynorm = -1 # check if instrument has a chip offset ra_offset, dec_offset = 0, 0 if (man_ra is None or man_dec is None) and \ 'chip_offset_fixed' in obsparam: cid = header[obsparam['chip_id']] ra_offset = float(obsparam['chip_offset_fixed'][cid][0]) dec_offset = float(obsparam['chip_offset_fixed'][cid][1]) if not keep_wcs: # create fake header header['RADECSYS'] = ('FK5', 'PP: fake wcs coordinates') header['RADESYS'] = ('FK5', 'PP: fake wcs coordinates') header['CTYPE1'] = ('RA---TAN', 'PP: fake Coordinate type') header['CTYPE2'] = ('DEC--TAN', 'PP: fake Coordinate type') header['CRVAL1'] = (ra_deg+ra_offset, 'PP: fake Coordinate reference value') header['CRVAL2'] = (dec_deg+dec_offset, 'PP: fake Coordinate reference value') header['CRPIX1'] = (int(float(header[obsparam['extent'][0]])/2), 'PP: fake Coordinate reference pixel') header['CRPIX2'] = (int(float(header[obsparam['extent'][1]])/2), 'PP: fake Coordinate reference pixel') # plugin default distortion parameters, if available if 'distort' in obsparam: if 'functionof' in obsparam['distort']: pv_dict = obsparam['distort'][header[obsparam['distort'] ['functionof']]] else: pv_dict = obsparam['distort'] try: for pv_key, pv_val in pv_dict.items(): header[pv_key] = (pv_val, 'PP: default distortion') except KeyError: logging.error(('No distortion coefficients available for ' '%s %s') % (obsparam['distort']['functionof'], header[obsparam['distort'] ['functionof']])) header['CD1_1'] = (xnorm * numpy.cos(this_rotate/180.*numpy.pi) * obsparam['secpix'][0]*binning[0]/3600., 'PP: fake Coordinate matrix') header['CD1_2'] = (ynorm * -numpy.sin(this_rotate/180.*numpy.pi) * obsparam['secpix'][1]*binning[1]/3600., 'PP: fake Coordinate matrix') header['CD2_1'] = (xnorm * numpy.sin(this_rotate/180.*numpy.pi) * obsparam['secpix'][0]*binning[0]/3600., 'PP: fake Coordinate matrix') header['CD2_2'] = (ynorm * numpy.cos(this_rotate/180.*numpy.pi) * obsparam['secpix'][1]*binning[1]/3600., 'PP: fake Coordinate matrix') # crop center from LOWELL42 frames if obsparam['telescope_keyword'] == 'LOWELL42': imdata = imdata[100:-100, 100:-100] logging.info('cropping LOWELL42 data') # overwrite imdata in case something has been modified hdulist[0].data = imdata hdulist.flush() hdulist.close() logging.info('created fake wcs information for image %s' % filename) # create diagnostics if diagnostics: if display: print('creating diagnostic output') logging.info(' ~~~~~~~~~ creating diagnostic output') diag.add_index(filenames, os.getcwd(), obsparam) logging.info('Done! -----------------------------------------------------') return None