def fillgaps(profile): """Fill in the gaps""" hdu = pyfits.open(profile) #get the binning xbin, ybin = saltkey.ccdbin( hdu[0], '') #fill in the second gap x1 = 2044/xbin x2 = 2152/xbin d1=np.min(hdu[1].data[:,x1-10:x1], axis=1) d2=np.min(hdu[1].data[:,x2:x2+10], axis=1) d1 = 0.5 * (d1+d2) hdu[1].data[:,x1:x2] = d1.reshape(len(d1),1) #fill in the second gap x1 = 4096/xbin x2 = 4308/xbin d1=np.min(hdu[1].data[:,x1-10:x1], axis=1) d2=np.min(hdu[1].data[:,x2:x2+10], axis=1) d1 = 0.5 * (d1+d2) hdu[1].data[:,x1:x2] = d1.reshape(len(d1),1) if os.path.isfile(profile): os.remove(profile) hdu.writeto(profile)
def calc_resolution(hdu): """Calculate the resolution for a setup""" instrume=saltkey.get('INSTRUME', hdu[0]).strip() grating=saltkey.get('GRATING', hdu[0]).strip() grang=saltkey.get('GR-ANGLE', hdu[0]) grasteps=saltkey.get('GRTILT', hdu[0]) arang=saltkey.get('AR-ANGLE', hdu[0]) arsteps=saltkey.get('CAMANG', hdu[0]) rssfilter=saltkey.get('FILTER', hdu[0]) specmode=saltkey.get('OBSMODE', hdu[0]) masktype=saltkey.get('MASKTYP', hdu[0]).strip().upper() slitname=saltkey.get('MASKID', hdu[0]) xbin, ybin = saltkey.ccdbin( hdu[0], '') slit=st.getslitsize(slitname) #create RSS Model rss=RSSModel.RSSModel(grating_name=grating.strip(), gratang=grang, \ camang=arang,slit=slit, xbin=xbin, ybin=ybin, \ ) res=1e7*rss.calc_resolelement(rss.alpha(), -rss.beta()) return res
def specidentify(images, linelist, outfile, guesstype='rss', guessfile='', automethod='Matchlines', function='poly', order=3, rstep=100, rstart='middlerow', mdiff=5, thresh=3, niter=5, smooth=0, subback=0, inter=True, startext=0, clobber=False, textcolor='black', logfile='salt.log', verbose=True): with logging(logfile, debug) as log: # set up the variables infiles = [] outfiles = [] # Check the input images infiles = saltio.argunpack('Input', images) # create list of output files outfiles = saltio.argunpack('Output', outfile) # open the line lists slines, sfluxes = st.readlinelist(linelist) # Identify the lines in each file for img, ofile in zip(infiles, outfiles): # open the image hdu = saltio.openfits(img) # get the basic information about the spectrograph dateobs = saltkey.get('DATE-OBS', hdu[0]) try: utctime = saltkey.get('UTC-OBS', hdu[0]) except SaltError: utctime = saltkey.get('TIME-OBS', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() grang = saltkey.get('GR-ANGLE', hdu[0]) grasteps = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) arsteps = saltkey.get('CAMANG', hdu[0]) rssfilter = saltkey.get('FILTER', hdu[0]) specmode = saltkey.get('OBSMODE', hdu[0]) masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper() slitname = saltkey.get('MASKID', hdu[0]) xbin, ybin = saltkey.ccdbin(hdu[0], img) for i in range(startext, len(hdu)): if hdu[i].name == 'SCI': log.message('Proccessing extension %i in %s' % (i, img)) # things that will change for each slit if masktype == 'LONGSLIT': slit = st.getslitsize(slitname) xpos = -0.2666 ypos = 0.0117 objid = None elif masktype == 'MOS': slit = 1.5 #slit=saltkey.get('SLIT', hdu[i]) # set up the x and y positions miny = hdu[i].header['MINY'] maxy = hdu[i].header['MAXY'] ras = hdu[i].header['SLIT_RA'] des = hdu[i].header['SLIT_DEC'] objid = hdu[i].header['SLITNAME'] # TODO: Check the perfomance of masks at different PA rac = hdu[0].header['MASK_RA'] dec = hdu[0].header['MASK_DEC'] pac = hdu[0].header['PA'] # these are hard wired at the moment xpixscale = 0.1267 * xbin ypixscale = 0.1267 * ybin cx = int(3162 / xbin) cy = int(2050 / ybin) x, y = mt.convert_fromsky(ras, des, rac, dec, xpixscale=xpixscale, ypixscale=ypixscale, position_angle=-pac, ccd_cx=cx, ccd_cy=cy) xpos = 0.015 * 2 * (cx - x[0]) ypos = 0.0117 else: msg = '%s is not a currently supported masktype' % masktype raise SALTSpecError(msg) if instrume not in ['PFIS', 'RSS']: msg = '%s is not a currently supported instrument' % instrume raise SALTSpecError(msg) # create RSS Model rss = RSSModel.RSSModel(grating_name=grating.strip(), gratang=grang, camang=arang, slit=slit, xbin=xbin, ybin=ybin, xpos=xpos, ypos=ypos) res = 1e7 * rss.calc_resolelement(rss.alpha(), -rss.beta()) dres = res / 10.0 wcen = 1e7 * rss.calc_centralwavelength() R = rss.calc_resolution( wcen / 1e7, rss.alpha(), -rss.beta()) logmsg = '\nGrating\tGR-ANGLE\tAR-ANGLE\tSlit\tWCEN\tR\n' logmsg += '%s\t%8.3f\t%8.3f\t%4.2f\t%6.2f\t%4f\n' % ( grating, grang, arang, slit, wcen, R) if log: log.message(logmsg, with_header=False) # set up the data for the source try: data = hdu[i].data except Exception as e: message = 'Unable to read in data array in %s because %s' % ( img, e) raise SALTSpecError(message) # set up the center row if rstart == 'middlerow': ystart = int(0.5 * len(data)) else: ystart = int(rstart) rss.gamma = 0.0 if masktype == 'MOS': rss.gamma = 180.0 / math.pi * math.atan((y * rss.detector.pix_size * rss.detector.ybin - 0.5 * rss.detector.find_height()) / rss.camera.focallength) # set up the xarr array based on the image xarr = np.arange(len(data[ystart]), dtype='int64') # get the guess for the wavelength solution if guesstype == 'rss': # set up the rss model ws = st.useRSSModel( xarr, rss, function=function, order=order, gamma=rss.gamma) elif guesstype == 'file': soldict = {} soldict = readsolascii(guessfile, soldict) timeobs = enterdatetime('%s %s' % (dateobs, utctime)) exptime = saltkey.get('EXPTIME', hdu[0]) filtername = saltkey.get('FILTER', hdu[0]).strip() try: slitid = saltkey.get('SLITNAME', hdu[i]) except: slitid = None function, order, coef = findlinesol( soldict, ystart, True, timeobs, exptime, instrume, grating, grang, arang, filtername, slitid, xarr=xarr) ws = WavelengthSolution.WavelengthSolution( xarr, xarr, function=function, order=order) ws.set_coef(coef) else: raise SALTSpecError( 'This guesstype is not currently supported') # identify the spectral lines ImageSolution = identify(data, slines, sfluxes, xarr, ystart, ws=ws, function=function, order=order, rstep=rstep, mdiff=mdiff, thresh=thresh, niter=niter, method=automethod, res=res, dres=dres, smooth=smooth, inter=inter, filename=img, subback=0, textcolor=textcolor, log=log, verbose=verbose) if outfile and len(ImageSolution): writeIS(ImageSolution, outfile, dateobs=dateobs, utctime=utctime, instrume=instrume, grating=grating, grang=grang, grasteps=grasteps, arsteps=arsteps, arang=arang, rfilter=rssfilter, slit=slit, xbin=xbin, ybin=ybin, objid=objid, filename=img, log=log, verbose=verbose)
def wavemap( hdu, soldict, caltype="line", function="poly", order=3, blank=0, nearest=False, array_only=False, clobber=True, log=None, verbose=True, ): """Read in an image and a set of wavlength solutions. Calculate the best wavelength solution for a given dataset and then apply that data set to the image return """ # set up the time of the observation dateobs = saltkey.get("DATE-OBS", hdu[0]) utctime = saltkey.get("TIME-OBS", hdu[0]) exptime = saltkey.get("EXPTIME", hdu[0]) instrume = saltkey.get("INSTRUME", hdu[0]).strip() grating = saltkey.get("GRATING", hdu[0]).strip() if caltype == "line": grang = saltkey.get("GRTILT", hdu[0]) arang = saltkey.get("CAMANG", hdu[0]) else: grang = saltkey.get("GR-ANGLE", hdu[0]) arang = saltkey.get("AR-ANGLE", hdu[0]) filtername = saltkey.get("FILTER", hdu[0]).strip() slitname = saltkey.get("MASKID", hdu[0]) slit = st.getslitsize(slitname) xbin, ybin = saltkey.ccdbin(hdu[0]) timeobs = sr.enterdatetime("%s %s" % (dateobs, utctime)) # check to see if there is more than one solution if caltype == "line": if len(soldict) == 1: sol = soldict.keys()[0] slitid = None if not sr.matchobservations(soldict[sol], instrume, grating, grang, arang, filtername, slitid): msg = "Observations do not match setup for transformation but using the solution anyway" if log: log.warning(msg) for i in range(1, len(hdu)): if hdu[i].name == "SCI": if log: log.message("Correcting extension %i" % i) istart = int(0.5 * len(hdu[i].data)) # open up the data # set up the xarr and initial wavlength solution xarr = np.arange(len(hdu[i].data[istart]), dtype="int64") # get the slitid try: slitid = saltkey.get("SLITNAME", hdu[i]) except: slitid = None # check to see if wavext is already there and if so, then check update # that for the transformation from xshift to wavelength if saltkey.found("WAVEXT", hdu[i]): w_ext = saltkey.get("WAVEXT", hdu[i]) - 1 wavemap = hdu[w_ext].data function, order, coef = sr.findlinesol( soldict, istart, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slitid, xarr, ) ws = WavelengthSolution.WavelengthSolution(xarr, xarr, function=function, order=order) ws.set_coef(coef) for j in range(len(hdu[i].data)): wavemap[j, :] = ws.value(wavemap[j, :]) if array_only: return wavemap hdu[w_ext].data = wavemap continue # set up a wavelength solution -- still in here for testing MOS data try: w_arr = sr.findsol( xarr, soldict, istart, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order, ) except SALTSpecError as e: if slitid: msg = "SLITID %s: %s" % (slitid, e) if log: log.warning(msg) continue else: raise SALTSpecError(e) if w_arr is None: w_arr = sr.findsol( xarr, soldict, istart, "rss", nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order, ) # for each line in the data, determine the wavelength solution # for a given line in the image wavemap = np.zeros_like(hdu[i].data) for j in range(len(hdu[i].data)): # find the wavelength solution for the data w_arr = sr.findsol( xarr, soldict, j, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order, ) if w_arr is not None: wavemap[j, :] = w_arr if array_only: return wavemap # write out the oimg hduwav = fits.ImageHDU(data=wavemap, header=hdu[i].header, name="WAV") hdu.append(hduwav) saltkey.new("WAVEXT", len(hdu) - 1, "Extension for Wavelength Map", hdu[i]) return hdu
def specarcstraighten(images, outfile, function='poly', order=3, rstep=1, rstart='middlerow', nrows=1, y1=None, y2=None, sigma=5, sections=3, niter=5, startext=0, clobber=False, logfile='salt.log', verbose=True): with logging(logfile, debug) as log: # Check the input images infiles = saltio.argunpack('Input', images) # create list of output files outfiles = saltio.argunpack('Output', outfile) # Identify the lines in each file for img, ofile in zip(infiles, outfiles): # open the image hdu = saltio.openfits(img) # get the basic information about the spectrograph dateobs = saltkey.get('DATE-OBS', hdu[0]) try: utctime = saltkey.get('UTC-OBS', hdu[0]) except SaltError: utctime = saltkey.get('TIME-OBS', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() grang = saltkey.get('GR-ANGLE', hdu[0]) grasteps = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) arsteps = saltkey.get('CAMANG', hdu[0]) rssfilter = saltkey.get('FILTER', hdu[0]) specmode = saltkey.get('OBSMODE', hdu[0]) masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper() slitname = saltkey.get('MASKID', hdu[0]) xbin, ybin = saltkey.ccdbin(hdu[0], img) for i in range(startext, len(hdu)): if hdu[i].name == 'SCI': log.message('Proccessing extension %i in %s' % (i, img)) # things that will change for each slit if masktype == 'LONGSLIT': slit = st.getslitsize(slitname) objid = None #elif masktype == 'MOS': #slit = 1.5 # slit=saltkey.get('SLIT', hdu[i]) # set up the x and y positions #miny = hdu[i].header['MINY'] #maxy = hdu[i].header['MAXY'] #ras = hdu[i].header['SLIT_RA'] #des = hdu[i].header['SLIT_DEC'] #objid = hdu[i].header['SLITNAME'] # Check the perfomance of masks at different PA #rac = hdu[0].header['MASK_RA'] #dec = hdu[0].header['MASK_DEC'] #pac = hdu[0].header['PA'] else: msg = '%s is not a currently supported masktype' % masktype raise SALTSpecError(msg) if instrume not in ['PFIS', 'RSS']: msg = '%s is not a currently supported instrument' % instrume raise SALTSpecError(msg) # set up the data for the source try: data = hdu[i].data except Exception as e: message = 'Unable to read in data array in %s because %s' % ( img, e) raise SALTSpecError(message) # set up the center row if rstart == 'middlerow': ystart = int(0.5 * len(data)) else: ystart = rstart # set up the xarr array based on the image xarr = np.arange(len(data[ystart]), dtype='int64') # calculate the transformation ImageSolution = arcstraight(data, xarr, ystart, function=function, order=order, rstep=rstep, y1=y1, y2=y2, sigma=sigma, sections=sections, niter=niter, log=log, verbose=verbose) if outfile and len(ImageSolution): writeIS(ImageSolution, outfile, dateobs=dateobs, utctime=utctime, instrume=instrume, grating=grating, grang=grang, grasteps=grasteps, arsteps=arsteps, arang=arang, rfilter=rssfilter, slit=slit, xbin=xbin, ybin=ybin, objid=objid, filename=img, log=log, verbose=verbose)
def make_mosaic(struct, gap, xshift, yshift, rotation, interp_type='linear', boundary='constant', constant=0, geotran=True, fill=False, cleanup=True, log=None, verbose=False): """Given a SALT image struct, combine each of the individual amplifiers and apply the geometric CCD transformations to the image """ # get the name of the file infile = saltkey.getimagename(struct[0], base=True) outpath = './' # identify instrument instrume, keyprep, keygain, keybias, keyxtalk, keyslot = \ saltkey.instrumid(struct) # how many amplifiers? nsciext = saltkey.get('NSCIEXT', struct[0]) nextend = saltkey.get('NEXTEND', struct[0]) nccds = saltkey.get('NCCDS', struct[0]) amplifiers = nccds * 2 if nextend > nsciext: varframe = True else: varframe = False # CCD geometry coefficients if (instrume == 'RSS' or instrume == 'PFIS'): xsh = [0., xshift[0], 0., xshift[1]] ysh = [0., yshift[0], 0., yshift[1]] rot = [0., rotation[0], 0., rotation[1]] elif instrume == 'SALTICAM': xsh = [0., xshift[0], 0.] ysh = [0., yshift[0], 0.] rot = [0., rotation[0], 0] # how many extensions? nextend = saltkey.get('NEXTEND', struct[0]) # CCD on-chip binning xbin, ybin = saltkey.ccdbin(struct[0]) # create temporary primary extension outstruct = [] outstruct.append(struct[0]) # define temporary FITS file store tiled CCDs tilefile = saltio.tmpfile(outpath) tilefile += 'tile.fits' if varframe: tilehdu = [None] * (3 * int(nsciext / 2) + 1) else: tilehdu = [None] * int(nsciext / 2 + 1) tilehdu[0] = fits.PrimaryHDU() #tilehdu[0].header = struct[0].header if log: log.message('', with_stdout=verbose) # iterate over amplifiers, stich them to produce file of CCD images for i in range(int(nsciext / 2)): hdu = i * 2 + 1 # amplifier = hdu%amplifiers # if (amplifier == 0): amplifier = amplifiers # read DATASEC keywords datasec1 = saltkey.get('DATASEC', struct[hdu]) datasec2 = saltkey.get('DATASEC', struct[hdu + 1]) xdsec1, ydsec1 = saltstring.secsplit(datasec1) xdsec2, ydsec2 = saltstring.secsplit(datasec2) # read images imdata1 = saltio.readimage(struct, hdu) imdata2 = saltio.readimage(struct, hdu + 1) # tile 2n amplifiers to yield n CCD images outdata = numpy.zeros( (int(ydsec1[1] + abs(ysh[i + 1] / ybin)), int(xdsec1[1] + xdsec2[1] + abs(xsh[i + 1] / xbin))), numpy.float32) # set up the variance frame if varframe: vardata = outdata.copy() vdata1 = saltio.readimage(struct, struct[hdu].header['VAREXT']) vdata2 = saltio.readimage(struct, struct[hdu + 1].header['VAREXT']) bpmdata = outdata.copy() bdata1 = saltio.readimage(struct, struct[hdu].header['BPMEXT']) bdata2 = saltio.readimage(struct, struct[hdu + 1].header['BPMEXT']) x1 = xdsec1[0] - 1 if x1 != 0: msg = 'The data in %s have not been trimmed prior to mosaicking.' \ % infile log.error(msg) if xsh[i + 1] < 0: x1 += int(abs(xsh[i + 1] / xbin)) x2 = x1 + xdsec1[1] y1 = ydsec1[0] - 1 if ysh[i + 1] < 0: y1 += int(abs(ysh[i + 1] / ybin)) y2 = y1 + ydsec1[1] outdata[y1:y2, x1:x2] =\ imdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] if varframe: vardata[y1:y2, x1:x2] =\ vdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] bpmdata[y1:y2, x1:x2] =\ bdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] x1 = x2 x2 = x1 + xdsec2[1] y1 = ydsec2[0] - 1 if ysh[i + 1] < 0: y1 += abs(ysh[i + 1] / ybin) y2 = y1 + ydsec2[1] outdata[y1:y2, x1:x2] =\ imdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] if varframe: vardata[y1:y2, x1:x2] =\ vdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] bpmdata[y1:y2, x1:x2] =\ bdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] # size of new image naxis1 = str(xdsec1[1] + xdsec2[1]) naxis2 = str(ydsec1[1]) # add image and keywords to HDU list tilehdu[i + 1] = fits.ImageHDU(outdata) tilehdu[i + 1].header = struct[hdu].header #tilehdu[ # i + 1].header['DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' if varframe: vext = i + 1 + int(nsciext / 2.) tilehdu[vext] = fits.ImageHDU(vardata) #tilehdu[vext].header = struct[struct[hdu].header['VAREXT']].header #tilehdu[vext].header[ # 'DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' bext = i + 1 + 2 * int(nsciext / 2.) tilehdu[bext] = fits.ImageHDU(bpmdata) #tilehdu[bext].header = struct[struct[hdu].header['BPMEXT']].header #tilehdu[bext].header[ # 'DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' # image tile log message #1 if log: message = os.path.basename(infile) + '[' + str(hdu) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + '] --> ' message += os.path.basename(tilefile) + '[' + str(i + 1) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + ']' log.message(message, with_stdout=verbose, with_header=False) message = os.path.basename(infile) + '[' + str(hdu + 1) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + '] --> ' message += os.path.basename(tilefile) + '[' + str(i + 1) + '][' message += str(xdsec1[1] + 1) + ':' + \ str(xdsec1[1] + xdsec2[1]) + ',' message += str(ydsec2[0]) + ':' + str(ydsec2[1]) + ']' log.message(message, with_stdout=verbose, with_header=False) # write temporary file of tiled CCDs hdulist = fits.HDUList(tilehdu) hdulist.writeto(tilefile) # iterate over CCDs, transform and rotate images yrot = [None] * 4 xrot = [None] * 4 tranfile = [' '] tranhdu = [0] if varframe: tranfile = [''] * (3 * int(nsciext / 2) + 1) tranhdu = [0] * (3 * int(nsciext / 2) + 1) else: tranfile = [''] * int(nsciext / 2 + 1) tranhdu = [0] * int(nsciext / 2 + 1) # this is hardwired for SALT where the second CCD is considered the # fiducial for hdu in range(1, int(nsciext / 2 + 1)): tranfile[hdu] = saltio.tmpfile(outpath) tranfile[hdu] += 'tran.fits' if varframe: tranfile[hdu + nccds] = saltio.tmpfile(outpath) + 'tran.fits' tranfile[hdu + 2 * nccds] = saltio.tmpfile(outpath) + 'tran.fits' ccd = hdu % nccds if (ccd == 0): ccd = nccds # correct rotation for CCD binning yrot[ccd] = rot[ccd] * ybin / xbin xrot[ccd] = rot[ccd] * xbin / ybin dxshift = xbin * int(float(int(gap) / xbin) + 0.5) - gap # transformation using geotran IRAF task # if (ccd == 1): if (ccd != 2): if geotran: message = '\nSALTMOSAIC -- geotran ' + tilefile + \ '[' + str(ccd) + '] ' + tranfile[hdu] message += ' \"\" \"\" xshift=' + \ str((xsh[ccd] + (2 - ccd) * dxshift) / xbin) + ' ' message += 'yshift=' + \ str(ysh[ccd] / ybin) + ' xrotation=' + str(xrot[ccd]) + ' ' message += 'yrotation=' + \ str(yrot[ccd]) + ' xmag=1 ymag=1 xmin=\'INDEF\'' message += 'xmax=\'INDEF\' ymin=\'INDEF\' ymax=\'INDEF\' ' message += 'ncols=\'INDEF\' ' message += 'nlines=\'INDEF\' verbose=\'no\' ' message += 'fluxconserve=\'yes\' nxblock=2048 ' message += 'nyblock=2048 interpolant=\'' + \ interp_type + '\' boundary=\'constant\' constant=0' log.message(message, with_stdout=verbose) yd, xd = tilehdu[ccd].data.shape ncols = 'INDEF' # ncols=xd+abs(xsh[ccd]/xbin) nlines = 'INDEF' # nlines=yd+abs(ysh[ccd]/ybin) geo_xshift = xsh[ccd] + (2 - ccd) * dxshift / xbin geo_yshift = ysh[ccd] / ybin iraf.images.immatch.geotran(tilefile + "[" + str(ccd) + "]", tranfile[hdu], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) if varframe: var_infile = tilefile + "[" + str(ccd + nccds) + "]" iraf.images.immatch.geotran(var_infile, tranfile[hdu + nccds], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) var2_infile = tilefile + "[" + str(ccd + 2 * nccds) + "]" iraf.images.immatch.geotran(var2_infile, tranfile[hdu + 2 * nccds], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) # open the file and copy the data to tranhdu tstruct = fits.open(tranfile[hdu]) tranhdu[hdu] = tstruct[0].data tstruct.close() if varframe: tranhdu[hdu + nccds] = fits.open(tranfile[hdu + nccds])[0].data tranhdu[hdu + 2 * nccds] = fits.open( tranfile[hdu + 2 * nccds])[0].data else: log.message("Transform CCD #%i using dx=%s, dy=%s, rot=%s" % (ccd, xsh[ccd] / 2.0, ysh[ccd] / 2.0, xrot[ccd]), with_stdout=verbose, with_header=False) tranhdu[hdu] = geometric_transform( tilehdu[ccd].data, tran_func, prefilter=False, order=1, extra_arguments=(xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) tstruct = fits.PrimaryHDU(tranhdu[hdu]) tstruct.writeto(tranfile[hdu]) if varframe: tranhdu[hdu + nccds] = geometric_transform( tilehdu[hdu + 3].data, tran_func, prefilter=False, order=1, extra_arguments=(xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) tranhdu[hdu + 2 * nccds] = geometric_transform( tilehdu[hdu + 6].data, tran_func, prefilter=False, order=1, extra_arguments=(xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) else: log.message("Transform CCD #%i using dx=%s, dy=%s, rot=%s" % (ccd, 0, 0, 0), with_stdout=verbose, with_header=False) tranhdu[hdu] = tilehdu[ccd].data if varframe: tranhdu[hdu + nccds] = tilehdu[ccd + nccds].data tranhdu[hdu + 2 * nccds] = tilehdu[ccd + 2 * nccds].data # open outfile if varframe: outlist = 4 * [None] else: outlist = 2 * [None] #outlist[0] = struct[0].copy() outlist[0] = fits.PrimaryHDU() outlist[0].header = struct[0].header naxis1 = int(gap / xbin * (nccds - 1)) naxis2 = 0 for i in range(1, nccds + 1): yw, xw = tranhdu[i].shape naxis1 += xw + int(abs(xsh[ccd] / xbin)) + 1 naxis2 = max(naxis2, yw) outdata = numpy.zeros((naxis2, naxis1), numpy.float32) outdata.shape = naxis2, naxis1 if varframe: vardata = outdata * 0 bpmdata = outdata * 0 + 1 # iterate over CCDs, stich them to produce a full image hdu = 0 totxshift = 0 for hdu in range(1, nccds + 1): # read DATASEC keywords ydsec, xdsec = tranhdu[hdu].shape # define size and shape of final image # tile CCDs to yield mosaiced image x1 = int((hdu - 1) * (xdsec + gap / xbin)) + int(totxshift) x2 = xdsec + x1 y1 = int(0) y2 = int(ydsec) outdata[y1:y2, x1:x2] = tranhdu[hdu] totxshift += int(abs(xsh[hdu] / xbin)) + 1 if varframe: vardata[y1:y2, x1:x2] = tranhdu[hdu + nccds] bpmdata[y1:y2, x1:x2] = tranhdu[hdu + 2 * nccds] # make sure to cover up all the gaps include bad areas if varframe: baddata = (outdata == 0) baddata = nd.maximum_filter(baddata, size=3) bpmdata[baddata] = 1 # fill in the gaps if requested if fill: if varframe: outdata = fill_gaps(outdata, 0) else: outdata = fill_gaps(outdata, 0) # add to the file outlist[1] = fits.ImageHDU(outdata) if varframe: outlist[2] = fits.ImageHDU(vardata, name='VAR') outlist[3] = fits.ImageHDU(bpmdata, name='BPM') # create the image structure outstruct = fits.HDUList(outlist) # update the head informaation # housekeeping keywords saltkey.put('NEXTEND', 2, outstruct[0]) saltkey.new('EXTNAME', 'SCI', 'Extension name', outstruct[1]) saltkey.new('EXTVER', 1, 'Extension number', outstruct[1]) if varframe: saltkey.new('VAREXT', 2, 'Variance frame extension', outstruct[1]) saltkey.new('BPMEXT', 3, 'BPM Extension', outstruct[1]) try: saltkey.copy(struct[1], outstruct[1], 'CCDSUM') except: pass # Add keywords associated with geometry saltkey.new('SGEOMGAP', gap, 'SALT Chip Gap', outstruct[0]) c1str = '{:3.2f} {:3.2f} {:3.4f}'.format(xshift[0], yshift[0], rotation[0]) saltkey.new('SGEOM1', c1str, 'SALT Chip 1 Transform', outstruct[0]) c2str = '{:3.2f} {:3.2f} {:3.4f}'.format(xshift[1], yshift[1], rotation[1]) saltkey.new('SGEOM2', c2str, 'SALT Chip 2 Transform', outstruct[0]) # WCS keywords saltkey.new('CRPIX1', 0, 'WCS: X reference pixel', outstruct[1]) saltkey.new('CRPIX2', 0, 'WCS: Y reference pixel', outstruct[1]) saltkey.new('CRVAL1', float(xbin), 'WCS: X reference coordinate value', outstruct[1]) saltkey.new('CRVAL2', float(ybin), 'WCS: Y reference coordinate value', outstruct[1]) saltkey.new('CDELT1', float(xbin), 'WCS: X pixel size', outstruct[1]) saltkey.new('CDELT2', float(ybin), 'WCS: Y pixel size', outstruct[1]) saltkey.new('CTYPE1', 'pixel', 'X type', outstruct[1]) saltkey.new('CTYPE2', 'pixel', 'Y type', outstruct[1]) # cleanup temporary files if cleanup: for tfile in tranfile: if os.path.isfile(tfile): saltio.delete(tfile) if os.path.isfile(tilefile): status = saltio.delete(tilefile) # return the file return outstruct
def slotmerge(images, outimages, outpref, geomfile, clobber, logfile, verbose): with logging(logfile, debug) as log: # are the arguments defined saltsafeio.argdefined('images', images) saltsafeio.argdefined('geomfile', geomfile) saltsafeio.argdefined('logfile', logfile) # if the input file is a list, does it exist? if images[0] == '@': saltsafeio.listexists('Input', images) # parse list of input files infiles = saltsafeio.listparse('Raw image', images, '', '', '') # check input files exist saltsafeio.filesexist(infiles, '', 'r') # load output name list: @list, * and comma separated outimages = outimages.strip() outpref = outpref.strip() if len(outpref) == 0 and len(outimages) == 0: raise SaltIOError('Output file(s) not specified') # test output @filelist exists if len(outimages) > 0 and outimages[0] == '@': saltsafeio.listexists('Output', outimages) # parse list of output files outfiles = saltsafeio.listparse('Output image', outimages, outpref, infiles, '') # are input and output lists the same length? saltsafeio.comparelists(infiles, outfiles, 'Input', 'output') # do the output files already exist? if not clobber: saltsafeio.filesexist(outfiles, '', 'w') # does CCD geometry definition file exist geomfilefile = geomfile.strip() saltsafeio.fileexists(geomfile) # read geometry definition file gap = 0 xshift = [0, 0] yshift = [0, 0] rotation = [0, 0] gap, xshift, yshift, rotation = saltsafeio.readccdgeom(geomfile) for ro in rotation: if ro != 0: log.warning('SLOTMERGE currently ignores CCD rotation') # Begin processes each file for infile, outfile in zip(infiles, outfiles): # determine the name for the output file outpath = outfile.rstrip(os.path.basename(outfile)) if (len(outpath) == 0): outpath = '.' # open each raw image struct = saltsafeio.openfits(infile) # identify instrument instrume, keyprep, keygain, keybias, keyxtalk, keyslot = saltsafekey.instrumid( struct, infile) # how many amplifiers? nccds = saltsafekey.get('NCCDS', struct[0], infile) amplifiers = nccds * 2 #if (nccds != 2): # raise SaltError('Can not currently handle more than two CCDs') # CCD geometry coefficients if instrume == 'RSS' or instrume == 'PFIS': xsh = [xshift[0], 0., xshift[1]] ysh = [yshift[0], 0., yshift[1]] rot = [rotation[0], 0., rotation[1]] refid = 1 if instrume == 'SALTICAM': xsh = [xshift[0], 0.] ysh = [yshift[0], 0.] rot = [rotation[0], 0] refid = 1 # how many extensions? nextend = saltsafekey.get('NEXTEND', struct[0], infile) # how many exposures exposures = nextend / amplifiers # CCD on-chip binning xbin, ybin = saltsafekey.ccdbin(struct[0], infile) gp = int(gap / xbin) # create output hdu structure outstruct = [None] * int(exposures + 1) outstruct[0] = struct[0] # iterate over exposures, stitch them to produce file of CCD images for i in range(exposures): # Determine the total size of the image xsize = 0 ysize = 0 for j in range(amplifiers): hdu = i * amplifiers + j + 1 try: xsize += len(struct[hdu].data[0]) if ysize < len(struct[hdu].data): ysize = len(struct[hdu].data) except: msg = 'Unable to access extension %i ' % hdu raise SaltIOError(msg) xsize += gp * (nccds - 1) maxxsh, minxsh = determineshifts(xsh) maxysh, minysh = determineshifts(ysh) xsize += (maxxsh - minxsh) ysize += (maxysh - minysh) # Determine the x and y origins for each frame xdist = 0 ydist = 0 shid = 0 x0 = np.zeros(amplifiers) y0 = np.zeros(amplifiers) for j in range(amplifiers): x0[j] = xdist + xsh[shid] - minxsh y0[j] = ysh[shid] - minysh hdu = i * amplifiers + j + 1 darr = struct[hdu].data xdist += len(darr[0]) if j % 2 == 1: xdist += gp shid += 1 # make the out image outarr = np.zeros((ysize, xsize), np.float64) # Embed each frame into the output array for j in range(amplifiers): hdu = i * amplifiers + j + 1 darr = struct[hdu].data outarr = salttran.embed(darr, x0[j], y0[j], outarr) # Add the outimage to the output structure hdu = i * amplifiers + 1 outhdu = i + 1 outstruct[outhdu] = pyfits.ImageHDU(outarr) outstruct[outhdu].header = struct[hdu].header # Fix the headers in each extension datasec = '[1:%4i,1:%4i]' % (xsize, ysize) saltsafekey.put('DATASEC', datasec, outstruct[outhdu], outfile) saltsafekey.rem('DETSIZE', outstruct[outhdu], outfile) saltsafekey.rem('DETSEC', outstruct[outhdu], outfile) saltsafekey.rem('CCDSEC', outstruct[outhdu], outfile) saltsafekey.rem('AMPSEC', outstruct[outhdu], outfile) # add housekeeping key words outstruct[outhdu] = addhousekeeping(outstruct[outhdu], outhdu, outfile) # close input FITS file saltsafeio.closefits(struct) # housekeeping keywords keymosaic = 'SLOTMERG' fname, hist = history(level=1, wrap=False) saltsafekey.housekeeping(struct[0], keymosaic, 'Amplifiers have been mosaiced', hist) #saltsafekey.history(outstruct[0],hist) # this is added for later use by saltsafekey.put('NCCDS', 0.5, outstruct[0]) saltsafekey.put('NSCIEXT', exposures, outstruct[0]) saltsafekey.put('NEXTEND', exposures, outstruct[0]) # write FITS file of mosaiced image outstruct = pyfits.HDUList(outstruct) saltsafeio.writefits(outstruct, outfile, clobber=clobber)
def specslit(image, outimage, outpref, exttype='auto', slitfile='', outputslitfile='', regprefix='', sections=3, width=25, sigma=2.2, thres=6, order=3, padding=5, yoffset=0, inter=False, clobber=True, logfile='salt.log', verbose=True): with logging(logfile, debug) as log: # check all the input and make sure that all the input needed is provided # by the user # read the image or image list and check if each in the list exist infiles = saltio.argunpack('Input', image) # unpack the outfiles outfiles = saltio.listparse('Outimages', outimage, outpref, infiles, '') # from the extraction type, check whether the input file is specified. # if the slitfile parameter is specified then use the slit files for # the extraction. if the extraction type is auto then use image for the # detection and the slit extraction if exttype == 'rsmt' or exttype == 'fits' or exttype == 'ascii' or exttype == 'ds9': slitfiles = saltio.argunpack('Slitfile', slitfile) if len(slitfiles) == 1: slitfiles = slitfiles * len(infiles) saltio.comparelists(infiles, slitfiles, 'image', 'slitfile') elif exttype == 'auto': slitfiles = infiles log.message( 'Extraction type is AUTO. Slit detection will be done from image' ) # read in if an optional ascii file is requested if len(outputslitfile) > 0: outslitfiles = saltio.argunpack('Outslitfiles', outputslitfile) saltio.comparelists(infiles, outslitfiles, 'image', 'outputslitfile') else: outslitfiles = [''] * len(infiles) # check if the width and sigma parameters were specified. # default is 25 and 2.2 if width < 10.: msg = 'The width parameter needs be a value larger than 10' raise SALTSpecError(msg) if sigma < 0.0: msg = 'Sigma must be greater than zero' raise SaltSpecError(msg) # check the treshold parameter. this needs to be specified by the user if thres <= 0.0: msg = 'Threshold must be greater than zero' raise SaltSpecError(msg) # check to make sure that the sections are greater than the order if sections <= order: msg = 'Number of sections must be greater than the order for the spline fit' raise SaltSpecError(msg) # run through each of the images and extract the slits for img, oimg, sfile, oslit in zip(infiles, outfiles, slitfiles, outslitfiles): log.message('Proccessing image %s' % img) # open the image struct = saltio.openfits(img) ylen, xlen = struct[1].data.shape xbin, ybin = saltkey.ccdbin(struct[0], img) # setup the VARIANCE and BPM frames if saltkey.found('VAREXT', struct[1]): varext = saltkey.get('VAREXT', struct[1]) varlist = [] else: varext = None # setup the BPM frames if saltkey.found('BPMEXT', struct[1]): bpmext = saltkey.get('BPMEXT', struct[1]) bpmlist = [] else: bpmext = None # open the slit definition file or identify the slits in the image slitmask = None ycheck = False if exttype == 'rsmt': log.message('Using slits from %s' % sfile) if yoffset is None: yoffset = 0 ycheck = True slitmask = mt.read_slitmask_from_xml(sfile) xpos = -0.3066 ypos = 0.0117 cx = int(xlen / 2.0) cy = int(ylen / 2.0) + ypos / 0.015 / ybin + yoffset order, slit_positions = mt.convert_slits_from_mask( slitmask, order=1, xbin=xbin, ybin=ybin, pix_scale=0.1267, cx=cx, cy=cy) sections = 1 elif exttype == 'fits': log.message('Using slits from %s' % sfile) order, slit_positions = read_slits_from_fits(sfile) elif exttype == 'ascii': log.message('Using slits from %s' % sfile) order, slit_positions = mt.read_slits_from_ascii(sfile) elif exttype == 'ds9': log.message('Using slits from %s' % sfile) order, slit_positions, slitmask = mt.read_slits_from_ds9( sfile, order=order) slitmask = None sections = 1 elif exttype == 'auto': log.message('Identifying slits in %s' % img) # identify the slits in the image order, slit_positions = identify_slits(struct[1].data, order, sections, width, sigma, thres) # write out the slit identifications if ofile has been supplied if oslit: log.message('Writing slit positions to %s' % oslit) mt.write_outputslitfile(slit_positions, oslit, order) if ycheck: slit_positions, dy = check_ypos(slit_positions, struct[1].data) log.message('Using an offset of {}'.format(dy)) # extract the slits spline_x = mt.divide_image(struct[1].data, sections) spline_x = 0.5 * (np.array(spline_x[:-1]) + np.array(spline_x[1:])) extracted_spectra, spline_positions = mt.extract_slits( slit_positions, spline_x, struct[1].data, order=order, padding=padding) if varext: extracted_var, var_positions = mt.extract_slits( slit_positions, spline_x, struct[varext].data, order=order, padding=padding) if bpmext: extracted_bpm, bpm_positions = mt.extract_slits( slit_positions, spline_x, struct[bpmext].data, order=order, padding=padding) # write out the data to the new array # create the new file hdulist = fits.HDUList([struct[0]]) # log the extracted spectra if needed log.message('', with_stdout=verbose) # setup output ds9 file if regprefix: regout = open( regprefix + os.path.basename(img).strip('.fits') + '.reg', 'w') regout.write('# Region file format: DS9 version 4.1\n') regout.write('# Filename: %s\n' % img) regout.write( 'global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1\nphysical\n' ) # add each imglist = [] nslits = len(spline_positions) for i in range(nslits): y1 = spline_positions[i][0].min() y2 = spline_positions[i][1].max() msg = 'Extracted Spectra %i between %i to %i' % (i + 1, y1, y2) # log.message(msg, with_header=False, with_stdout=verbose) sdu = fits.ImageHDU(extracted_spectra[i], header=struct[1].header) if varext: vdu = fits.ImageHDU(extracted_var[i], header=struct[varext].header) sdu.header['VAREXT'] = i + nslits + 1 varlist.append(vdu) if bpmext: bdu = fits.ImageHDU(extracted_bpm[i], header=struct[bpmext].header) sdu.header['BPMEXT'] = i + 2 * nslits + 1 bpmlist.append(bdu) imglist.append(sdu) # add in some additional keywords imglist[i].header['MINY'] = (y1, 'Lower Y value in original image') imglist[i].header['MAXY'] = (y2, 'Upper Y value in original image') if regprefix: xsize = struct[1].data.shape[1] xsize = int(0.5 * xsize) rtext = '' if slitmask: # rtext='%s, %8.7f, %8.7f, %3.2f' % (slitmask.slitlets.data[i]['name'], slitmask.slitlets.data[i]['targ_ra'], slitmask.slitlets.data[i]['targ_dec'], slitmask.slitlets.data[i]['slit_width']) pass regout.write('box(%i,%i, %i, %i) #text={%s}\n' % (xsize, 0.5 * (y1 + y2), 2 * xsize, y2 - y1, rtext)) # add slit information if slitmask: imglist[i].header['SLITNAME'] = ( slitmask.slitlets.data[i]['name'], 'Slit Name') imglist[i].header['SLIT_RA'] = ( slitmask.slitlets.data[i]['targ_ra'], 'Slit RA') imglist[i].header['SLIT_DEC'] = ( slitmask.slitlets.data[i]['targ_dec'], 'Slit DEC') imglist[i].header['SLIT'] = ( slitmask.slitlets.data[i]['slit_width'], 'Slit Width') # add to the hdulist hdulist += imglist if varext: hdulist += varlist if bpmext: hdulist += bpmlist # write the slit positions to the header # create the binary table HDU that contains the split positions tbhdu = mt.slits_HDUtable(slit_positions, order) bintable_hdr = tbhdu.header # add the extname parameter to the extension tbhdu.header['EXTNAME'] = 'BINTABLE' # add the extname parameter to the extension hdulist[0].header['SLITEXT'] = len(hdulist) hdulist.append(tbhdu) # add addition header information about the mask if slitmask: hdulist[0].header['MASKNAME'] = (slitmask.mask_name, 'SlitMask Name') hdulist[0].header['MASK_RA'] = (slitmask.center_ra, 'SlitMask RA') hdulist[0].header['MASK_DEC'] = (slitmask.center_dec, 'SlitMask DEC') hdulist[0].header['MASK_PA'] = (slitmask.position_angle, 'SlitMask Position Angle') # write out the image saltio.writefits(hdulist, oimg, clobber)
def slotmerge(images,outimages,outpref,geomfile,clobber,logfile,verbose): with logging(logfile,debug) as log: # are the arguments defined saltsafeio.argdefined('images',images) saltsafeio.argdefined('geomfile',geomfile) saltsafeio.argdefined('logfile',logfile) # if the input file is a list, does it exist? if images[0] == '@': saltsafeio.listexists('Input',images) # parse list of input files infiles=saltsafeio.listparse('Raw image',images,'','','') # check input files exist saltsafeio.filesexist(infiles,'','r') # load output name list: @list, * and comma separated outimages = outimages.strip() outpref = outpref.strip() if len(outpref) == 0 and len(outimages) == 0: raise SaltIOError('Output file(s) not specified') # test output @filelist exists if len(outimages) > 0 and outimages[0] == '@': saltsafeio.listexists('Output',outimages) # parse list of output files outfiles=saltsafeio.listparse('Output image',outimages,outpref,infiles,'') # are input and output lists the same length? saltsafeio.comparelists(infiles,outfiles,'Input','output') # do the output files already exist? if not clobber: saltsafeio.filesexist(outfiles,'','w') # does CCD geometry definition file exist geomfilefile = geomfile.strip() saltsafeio.fileexists(geomfile) # read geometry definition file gap = 0 xshift = [0, 0] yshift = [0, 0] rotation = [0, 0] gap, xshift, yshift, rotation=saltsafeio.readccdgeom(geomfile) for ro in rotation: if ro!=0: log.warning('SLOTMERGE currently ignores CCD rotation') # Begin processes each file for infile, outfile in zip(infiles, outfiles): # determine the name for the output file outpath = outfile.rstrip(os.path.basename(outfile)) if (len(outpath) == 0): outpath = '.' # open each raw image struct=saltsafeio.openfits(infile) # identify instrument instrume,keyprep,keygain,keybias,keyxtalk,keyslot=saltsafekey.instrumid(struct,infile) # how many amplifiers? nccds=saltsafekey.get('NCCDS',struct[0],infile) amplifiers = nccds * 2 #if (nccds != 2): # raise SaltError('Can not currently handle more than two CCDs') # CCD geometry coefficients if instrume == 'RSS' or instrume == 'PFIS': xsh = [xshift[0], 0., xshift[1]] ysh = [yshift[0], 0., yshift[1]] rot = [rotation[0], 0., rotation[1]] refid = 1 if instrume == 'SALTICAM': xsh = [xshift[0], 0.] ysh = [yshift[0], 0.] rot = [rotation[0], 0] refid = 1 # how many extensions? nextend=saltsafekey.get('NEXTEND',struct[0],infile) # how many exposures exposures = nextend/amplifiers # CCD on-chip binning xbin, ybin=saltsafekey.ccdbin(struct[0],infile) gp = int(gap / xbin) # create output hdu structure outstruct = [None] * int(exposures+1) outstruct[0]=struct[0] # iterate over exposures, stitch them to produce file of CCD images for i in range(exposures): # Determine the total size of the image xsize=0 ysize=0 for j in range(amplifiers): hdu=i*amplifiers+j+1 try: xsize += len(struct[hdu].data[0]) if ysize < len(struct[hdu].data): ysize=len(struct[hdu].data) except: msg='Unable to access extension %i ' % hdu raise SaltIOError(msg) xsize += gp* (nccds-1) maxxsh, minxsh = determineshifts(xsh) maxysh, minysh = determineshifts(ysh) xsize += (maxxsh-minxsh) ysize += (maxysh-minysh) # Determine the x and y origins for each frame xdist=0 ydist=0 shid=0 x0=np.zeros(amplifiers) y0=np.zeros(amplifiers) for j in range(amplifiers): x0[j]=xdist+xsh[shid]-minxsh y0[j]=ysh[shid]-minysh hdu=i*amplifiers+j+1 darr=struct[hdu].data xdist += len(darr[0]) if j%2==1: xdist += gp shid += 1 # make the out image outarr=np.zeros((ysize, xsize), np.float64) # Embed each frame into the output array for j in range(amplifiers): hdu=i*amplifiers+j+1 darr=struct[hdu].data outarr=salttran.embed(darr, x0[j], y0[j], outarr) # Add the outimage to the output structure hdu=i*amplifiers+1 outhdu=i+1 outstruct[outhdu] = pyfits.ImageHDU(outarr) outstruct[outhdu].header=struct[hdu].header # Fix the headers in each extension datasec='[1:%4i,1:%4i]' % (xsize, ysize) saltsafekey.put('DATASEC',datasec, outstruct[outhdu], outfile) saltsafekey.rem('DETSIZE',outstruct[outhdu],outfile) saltsafekey.rem('DETSEC',outstruct[outhdu],outfile) saltsafekey.rem('CCDSEC',outstruct[outhdu],outfile) saltsafekey.rem('AMPSEC',outstruct[outhdu],outfile) # add housekeeping key words outstruct[outhdu]=addhousekeeping(outstruct[outhdu], outhdu, outfile) # close input FITS file saltsafeio.closefits(struct) # housekeeping keywords keymosaic='SLOTMERG' fname, hist=history(level=1, wrap=False) saltsafekey.housekeeping(struct[0],keymosaic,'Amplifiers have been mosaiced', hist) #saltsafekey.history(outstruct[0],hist) # this is added for later use by saltsafekey.put('NCCDS', 0.5, outstruct[0]) saltsafekey.put('NSCIEXT', exposures, outstruct[0]) saltsafekey.put('NEXTEND', exposures, outstruct[0]) # write FITS file of mosaiced image outstruct=pyfits.HDUList(outstruct) saltsafeio.writefits(outstruct, outfile, clobber=clobber)
def specidentify(images, linelist, outfile, guesstype='rss', guessfile='', automethod='Matchlines', function='poly', order=3, rstep=100, rstart='middlerow', mdiff=5, thresh=3, niter=5, smooth=0, subback=0, inter=True, startext=0, clobber=False, textcolor='black', preprocess=False, logfile='salt.log', verbose=True): with logging(logfile, debug) as log: # set up the variables infiles = [] outfiles = [] # Check the input images infiles = saltio.argunpack('Input', images) # create list of output files outfiles = saltio.argunpack('Output', outfile) # open the line lists slines, sfluxes = st.readlinelist(linelist) # Identify the lines in each file for img, ofile in zip(infiles, outfiles): # open the image hdu = saltio.openfits(img) # get the basic information about the spectrograph dateobs = saltkey.get('DATE-OBS', hdu[0]) try: utctime = saltkey.get('UTC-OBS', hdu[0]) except SaltError: utctime = saltkey.get('TIME-OBS', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() grang = saltkey.get('GR-ANGLE', hdu[0]) grasteps = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) arsteps = saltkey.get('CAMANG', hdu[0]) rssfilter = saltkey.get('FILTER', hdu[0]) specmode = saltkey.get('OBSMODE', hdu[0]) masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper() slitname = saltkey.get('MASKID', hdu[0]) xbin, ybin = saltkey.ccdbin(hdu[0], img) for i in range(startext, len(hdu)): if hdu[i].name == 'SCI': log.message('Proccessing extension %i in %s' % (i, img)) # things that will change for each slit if masktype == 'LONGSLIT': slit = st.getslitsize(slitname) xpos = -0.2666 ypos = 0.0117 objid = None elif masktype == 'MOS': slit = 1. #slit=saltkey.get('SLIT', hdu[i]) # set up the x and y positions miny = hdu[i].header['MINY'] maxy = hdu[i].header['MAXY'] ras = hdu[i].header['SLIT_RA'] des = hdu[i].header['SLIT_DEC'] objid = hdu[i].header['SLITNAME'] # TODO: Check the perfomance of masks at different PA rac = hdu[0].header['MASK_RA'] dec = hdu[0].header['MASK_DEC'] pac = hdu[0].header['PA'] # these are hard wired at the moment xpixscale = 0.1267 * xbin ypixscale = 0.1267 * ybin cx = int(3162 / xbin) cy = int(2050 / ybin) x, y = mt.convert_fromsky(ras, des, rac, dec, xpixscale=xpixscale, ypixscale=ypixscale, position_angle=-pac, ccd_cx=cx, ccd_cy=cy) xpos = 0.015 * 2 * (cx - x[0]) ypos = 0.0117 else: msg = '%s is not a currently supported masktype' % masktype raise SALTSpecError(msg) if instrume not in ['PFIS', 'RSS']: msg = '%s is not a currently supported instrument' % instrume raise SALTSpecError(msg) # create RSS Model rss = RSSModel.RSSModel(grating_name=grating.strip(), gratang=grang, camang=arang, slit=slit, xbin=xbin, ybin=ybin, xpos=xpos, ypos=ypos) res = 1e7 * rss.calc_resolelement(rss.alpha(), -rss.beta()) dres = res / 10.0 wcen = 1e7 * rss.calc_centralwavelength() R = rss.calc_resolution(wcen / 1e7, rss.alpha(), -rss.beta()) logmsg = '\nGrating\tGR-ANGLE\tAR-ANGLE\tSlit\tWCEN\tR\n' logmsg += '%s\t%8.3f\t%8.3f\t%4.2f\t%6.2f\t%4f\n' % ( grating, grang, arang, slit, wcen, R) if log: log.message(logmsg, with_header=False) # set up the data for the source try: data = hdu[i].data except Exception, e: message = 'Unable to read in data array in %s because %s' % ( img, e) raise SALTSpecError(message) # set up the center row if rstart == 'middlerow': ystart = int(0.5 * len(data)) else: ystart = int(rstart) rss.gamma = 0.0 if masktype == 'MOS': rss.gamma = 180.0 / math.pi * math.atan( (y * rss.detector.pix_size * rss.detector.ybin - 0.5 * rss.detector.find_height()) / rss.camera.focallength) # set up the xarr array based on the image xarr = np.arange(len(data[ystart]), dtype='int64') # get the guess for the wavelength solution if guesstype == 'rss': # set up the rss model ws = st.useRSSModel(xarr, rss, function=function, order=order, gamma=rss.gamma) if function in ['legendre', 'chebyshev']: ws.func.func.domain = [xarr.min(), xarr.max()] elif guesstype == 'file': soldict = {} soldict = readsolascii(guessfile, soldict) timeobs = enterdatetime('%s %s' % (dateobs, utctime)) exptime = saltkey.get('EXPTIME', hdu[0]) filtername = saltkey.get('FILTER', hdu[0]).strip() try: slitid = saltkey.get('SLITNAME', hdu[i]) except: slitid = None function, order, coef, domain = findlinesol(soldict, ystart, True, timeobs, exptime, instrume, grating, grang, arang, filtername, slitid, xarr=xarr) ws = WavelengthSolution.WavelengthSolution( xarr, xarr, function=function, order=order) ws.func.func.domain = domain ws.set_coef(coef) else: raise SALTSpecError( 'This guesstype is not currently supported') # identify the spectral lines ImageSolution = identify(data, slines, sfluxes, xarr, ystart, ws=ws, function=function, order=order, rstep=rstep, mdiff=mdiff, thresh=thresh, niter=niter, method=automethod, res=res, dres=dres, smooth=smooth, inter=inter, filename=img, subback=0, textcolor=textcolor, preprocess=preprocess, log=log, verbose=verbose) if outfile and len(ImageSolution): writeIS(ImageSolution, outfile, dateobs=dateobs, utctime=utctime, instrume=instrume, grating=grating, grang=grang, grasteps=grasteps, arsteps=arsteps, arang=arang, rfilter=rssfilter, slit=slit, xbin=xbin, ybin=ybin, objid=objid, filename=img, log=log, verbose=verbose)
def make_mosaic(struct, gap, xshift, yshift, rotation, interp_type='linear', boundary='constant', constant=0, geotran=True, fill=False, cleanup=True, log=None, verbose=False): """Given a SALT image struct, combine each of the individual amplifiers and apply the geometric CCD transformations to the image """ # get the name of the file infile = saltkey.getimagename(struct[0], base=True) outpath = './' # identify instrument instrume, keyprep, keygain, keybias, keyxtalk, keyslot = \ saltkey.instrumid(struct) # how many amplifiers? nsciext = saltkey.get('NSCIEXT', struct[0]) nextend = saltkey.get('NEXTEND', struct[0]) nccds = saltkey.get('NCCDS', struct[0]) amplifiers = nccds * 2 if nextend > nsciext: varframe = True else: varframe = False # CCD geometry coefficients if (instrume == 'RSS' or instrume == 'PFIS'): xsh = [0., xshift[0], 0., xshift[1]] ysh = [0., yshift[0], 0., yshift[1]] rot = [0., rotation[0], 0., rotation[1]] elif instrume == 'SALTICAM': xsh = [0., xshift[0], 0.] ysh = [0., yshift[0], 0.] rot = [0., rotation[0], 0] # how many extensions? nextend = saltkey.get('NEXTEND', struct[0]) # CCD on-chip binning xbin, ybin = saltkey.ccdbin(struct[0]) # create temporary primary extension outstruct = [] outstruct.append(struct[0]) # define temporary FITS file store tiled CCDs tilefile = saltio.tmpfile(outpath) tilefile += 'tile.fits' if varframe: tilehdu = [None] * (3 * int(nsciext / 2) + 1) else: tilehdu = [None] * int(nsciext / 2 + 1) tilehdu[0] = fits.PrimaryHDU() #tilehdu[0].header = struct[0].header if log: log.message('', with_stdout=verbose) # iterate over amplifiers, stich them to produce file of CCD images for i in range(int(nsciext / 2)): hdu = i * 2 + 1 # amplifier = hdu%amplifiers # if (amplifier == 0): amplifier = amplifiers # read DATASEC keywords datasec1 = saltkey.get('DATASEC', struct[hdu]) datasec2 = saltkey.get('DATASEC', struct[hdu + 1]) xdsec1, ydsec1 = saltstring.secsplit(datasec1) xdsec2, ydsec2 = saltstring.secsplit(datasec2) # read images imdata1 = saltio.readimage(struct, hdu) imdata2 = saltio.readimage(struct, hdu + 1) # tile 2n amplifiers to yield n CCD images outdata = numpy.zeros((ydsec1[1] + abs(ysh[i + 1] / ybin), xdsec1[1] + xdsec2[1] + abs(xsh[i + 1] / xbin)), numpy.float32) # set up the variance frame if varframe: vardata = outdata.copy() vdata1 = saltio.readimage(struct, struct[hdu].header['VAREXT']) vdata2 = saltio.readimage(struct, struct[hdu + 1].header['VAREXT']) bpmdata = outdata.copy() bdata1 = saltio.readimage(struct, struct[hdu].header['BPMEXT']) bdata2 = saltio.readimage(struct, struct[hdu + 1].header['BPMEXT']) x1 = xdsec1[0] - 1 if x1 != 0: msg = 'The data in %s have not been trimmed prior to mosaicking.' \ % infile log.error(msg) if xsh[i + 1] < 0: x1 += abs(xsh[i + 1] / xbin) x2 = x1 + xdsec1[1] y1 = ydsec1[0] - 1 if ysh[i + 1] < 0: y1 += abs(ysh[i + 1] / ybin) y2 = y1 + ydsec1[1] outdata[y1:y2, x1:x2] =\ imdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] if varframe: vardata[y1:y2, x1:x2] =\ vdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] bpmdata[y1:y2, x1:x2] =\ bdata1[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] x1 = x2 x2 = x1 + xdsec2[1] y1 = ydsec2[0] - 1 if ysh[i + 1] < 0: y1 += abs(ysh[i + 1] / ybin) y2 = y1 + ydsec2[1] outdata[y1:y2, x1:x2] =\ imdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] if varframe: vardata[y1:y2, x1:x2] =\ vdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] bpmdata[y1:y2, x1:x2] =\ bdata2[ydsec1[0] - 1:ydsec1[1], xdsec1[0] - 1:xdsec1[1]] # size of new image naxis1 = str(xdsec1[1] + xdsec2[1]) naxis2 = str(ydsec1[1]) # add image and keywords to HDU list tilehdu[i + 1] = fits.ImageHDU(outdata) tilehdu[i + 1].header = struct[hdu].header #tilehdu[ # i + 1].header['DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' if varframe: vext = i + 1 + int(nsciext / 2.) tilehdu[vext] = fits.ImageHDU(vardata) #tilehdu[vext].header = struct[struct[hdu].header['VAREXT']].header #tilehdu[vext].header[ # 'DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' bext = i + 1 + 2 * int(nsciext / 2.) tilehdu[bext] = fits.ImageHDU(bpmdata) #tilehdu[bext].header = struct[struct[hdu].header['BPMEXT']].header #tilehdu[bext].header[ # 'DATASEC'] = '[1:' + naxis1 + ',1:' + naxis2 + ']' # image tile log message #1 if log: message = os.path.basename(infile) + '[' + str(hdu) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + '] --> ' message += os.path.basename(tilefile) + '[' + str(i + 1) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + ']' log.message(message, with_stdout=verbose, with_header=False) message = os.path.basename(infile) + '[' + str(hdu + 1) + '][' message += str(xdsec1[0]) + ':' + str(xdsec1[1]) + ',' message += str(ydsec1[0]) + ':' + str(ydsec1[1]) + '] --> ' message += os.path.basename(tilefile) + '[' + str(i + 1) + '][' message += str(xdsec1[1] + 1) + ':' + \ str(xdsec1[1] + xdsec2[1]) + ',' message += str(ydsec2[0]) + ':' + str(ydsec2[1]) + ']' log.message(message, with_stdout=verbose, with_header=False) # write temporary file of tiled CCDs hdulist = fits.HDUList(tilehdu) hdulist.writeto(tilefile) # iterate over CCDs, transform and rotate images yrot = [None] * 4 xrot = [None] * 4 tranfile = [' '] tranhdu = [0] if varframe: tranfile = [''] * (3 * int(nsciext / 2) + 1) tranhdu = [0] * (3 * int(nsciext / 2) + 1) else: tranfile = [''] * int(nsciext / 2 + 1) tranhdu = [0] * int(nsciext / 2 + 1) # this is hardwired for SALT where the second CCD is considered the # fiducial for hdu in range(1, int(nsciext / 2 + 1)): tranfile[hdu] = saltio.tmpfile(outpath) tranfile[hdu] += 'tran.fits' if varframe: tranfile[hdu + nccds] = saltio.tmpfile(outpath) + 'tran.fits' tranfile[hdu + 2 * nccds] = saltio.tmpfile(outpath) + 'tran.fits' ccd = hdu % nccds if (ccd == 0): ccd = nccds # correct rotation for CCD binning yrot[ccd] = rot[ccd] * ybin / xbin xrot[ccd] = rot[ccd] * xbin / ybin dxshift = xbin * int(float(int(gap) / xbin) + 0.5) - gap # transformation using geotran IRAF task # if (ccd == 1): if (ccd != 2): if geotran: message = '\nSALTMOSAIC -- geotran ' + tilefile + \ '[' + str(ccd) + '] ' + tranfile[hdu] message += ' \"\" \"\" xshift=' + \ str((xsh[ccd] + (2 - ccd) * dxshift) / xbin) + ' ' message += 'yshift=' + \ str(ysh[ccd] / ybin) + ' xrotation=' + str(xrot[ccd]) + ' ' message += 'yrotation=' + \ str(yrot[ccd]) + ' xmag=1 ymag=1 xmin=\'INDEF\'' message += 'xmax=\'INDEF\' ymin=\'INDEF\' ymax=\'INDEF\' ' message += 'ncols=\'INDEF\' ' message += 'nlines=\'INDEF\' verbose=\'no\' ' message += 'fluxconserve=\'yes\' nxblock=2048 ' message += 'nyblock=2048 interpolant=\'' + \ interp_type + '\' boundary=\'constant\' constant=0' log.message(message, with_stdout=verbose) yd, xd = tilehdu[ccd].data.shape ncols = 'INDEF' # ncols=xd+abs(xsh[ccd]/xbin) nlines = 'INDEF' # nlines=yd+abs(ysh[ccd]/ybin) geo_xshift = xsh[ccd] + (2 - ccd) * dxshift / xbin geo_yshift = ysh[ccd] / ybin iraf.images.immatch.geotran(tilefile + "[" + str(ccd) + "]", tranfile[hdu], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) if varframe: var_infile = tilefile + "[" + str(ccd + nccds) + "]" iraf.images.immatch.geotran(var_infile, tranfile[hdu + nccds], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) var2_infile = tilefile + "[" + str(ccd + 2 * nccds) + "]" iraf.images.immatch.geotran(var2_infile, tranfile[hdu + 2 * nccds], "", "", xshift=geo_xshift, yshift=geo_yshift, xrotation=xrot[ccd], yrotation=yrot[ccd], xmag=1, ymag=1, xmin='INDEF', xmax='INDEF', ymin='INDEF', ymax='INDEF', ncols=ncols, nlines=nlines, verbose='no', fluxconserve='yes', nxblock=2048, nyblock=2048, interpolant="linear", boundary="constant", constant=0) # open the file and copy the data to tranhdu tstruct = fits.open(tranfile[hdu]) tranhdu[hdu] = tstruct[0].data tstruct.close() if varframe: tranhdu[ hdu + nccds] = fits.open( tranfile[ hdu + nccds])[0].data tranhdu[ hdu + 2 * nccds] = fits.open( tranfile[ hdu + 2 * nccds])[0].data else: log.message( "Transform CCD #%i using dx=%s, dy=%s, rot=%s" % (ccd, xsh[ccd] / 2.0, ysh[ccd] / 2.0, xrot[ccd]), with_stdout=verbose, with_header=False) tranhdu[hdu] = geometric_transform( tilehdu[ccd].data, tran_func, prefilter=False, order=1, extra_arguments=( xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) tstruct = fits.PrimaryHDU(tranhdu[hdu]) tstruct.writeto(tranfile[hdu]) if varframe: tranhdu[hdu + nccds] = geometric_transform( tilehdu[hdu + 3].data, tran_func, prefilter=False, order=1, extra_arguments=( xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) tranhdu[hdu + 2 * nccds] = geometric_transform( tilehdu[hdu + 6].data, tran_func, prefilter=False, order=1, extra_arguments=( xsh[ccd] / 2, ysh[ccd] / 2, 1, 1, xrot[ccd], yrot[ccd])) else: log.message( "Transform CCD #%i using dx=%s, dy=%s, rot=%s" % (ccd, 0, 0, 0), with_stdout=verbose, with_header=False) tranhdu[hdu] = tilehdu[ccd].data if varframe: tranhdu[hdu + nccds] = tilehdu[ccd + nccds].data tranhdu[hdu + 2 * nccds] = tilehdu[ccd + 2 * nccds].data # open outfile if varframe: outlist = 4 * [None] else: outlist = 2 * [None] #outlist[0] = struct[0].copy() outlist[0] = fits.PrimaryHDU() outlist[0].header = struct[0].header naxis1 = int(gap / xbin * (nccds - 1)) naxis2 = 0 for i in range(1, nccds + 1): yw, xw = tranhdu[i].shape naxis1 += xw + int(abs(xsh[ccd] / xbin)) + 1 naxis2 = max(naxis2, yw) outdata = numpy.zeros((naxis2, naxis1), numpy.float32) outdata.shape = naxis2, naxis1 if varframe: vardata = outdata * 0 bpmdata = outdata * 0 + 1 # iterate over CCDs, stich them to produce a full image hdu = 0 totxshift = 0 for hdu in range(1, nccds + 1): # read DATASEC keywords ydsec, xdsec = tranhdu[hdu].shape # define size and shape of final image # tile CCDs to yield mosaiced image x1 = int((hdu - 1) * (xdsec + gap / xbin)) + int(totxshift) x2 = xdsec + x1 y1 = int(0) y2 = int(ydsec) outdata[y1:y2, x1:x2] = tranhdu[hdu] totxshift += int(abs(xsh[hdu] / xbin)) + 1 if varframe: vardata[y1:y2, x1:x2] = tranhdu[hdu + nccds] bpmdata[y1:y2, x1:x2] = tranhdu[hdu + 2 * nccds] # make sure to cover up all the gaps include bad areas if varframe: baddata = (outdata == 0) baddata = nd.maximum_filter(baddata, size=3) bpmdata[baddata] = 1 # fill in the gaps if requested if fill: if varframe: outdata = fill_gaps(outdata, 0) else: outdata = fill_gaps(outdata, 0) # add to the file outlist[1] = fits.ImageHDU(outdata) if varframe: outlist[2] = fits.ImageHDU(vardata,name='VAR') outlist[3] = fits.ImageHDU(bpmdata,name='BPM') # create the image structure outstruct = fits.HDUList(outlist) # update the head informaation # housekeeping keywords saltkey.put('NEXTEND', 2, outstruct[0]) saltkey.new('EXTNAME', 'SCI', 'Extension name', outstruct[1]) saltkey.new('EXTVER', 1, 'Extension number', outstruct[1]) if varframe: saltkey.new('VAREXT', 2, 'Variance frame extension', outstruct[1]) saltkey.new('BPMEXT', 3, 'BPM Extension', outstruct[1]) try: saltkey.copy(struct[1], outstruct[1], 'CCDSUM') except: pass # Add keywords associated with geometry saltkey.new('SGEOMGAP', gap, 'SALT Chip Gap', outstruct[0]) c1str = '{:3.2f} {:3.2f} {:3.4f}'.format(xshift[0], yshift[0], rotation[0]) saltkey.new('SGEOM1', c1str, 'SALT Chip 1 Transform', outstruct[0]) c2str = '{:3.2f} {:3.2f} {:3.4f}'.format(xshift[1], yshift[1], rotation[1]) saltkey.new('SGEOM2', c2str, 'SALT Chip 2 Transform', outstruct[0]) # WCS keywords saltkey.new('CRPIX1', 0, 'WCS: X reference pixel', outstruct[1]) saltkey.new('CRPIX2', 0, 'WCS: Y reference pixel', outstruct[1]) saltkey.new( 'CRVAL1', float(xbin), 'WCS: X reference coordinate value', outstruct[1]) saltkey.new( 'CRVAL2', float(ybin), 'WCS: Y reference coordinate value', outstruct[1]) saltkey.new('CDELT1', float(xbin), 'WCS: X pixel size', outstruct[1]) saltkey.new('CDELT2', float(ybin), 'WCS: Y pixel size', outstruct[1]) saltkey.new('CTYPE1', 'pixel', 'X type', outstruct[1]) saltkey.new('CTYPE2', 'pixel', 'Y type', outstruct[1]) # cleanup temporary files if cleanup: for tfile in tranfile: if os.path.isfile(tfile): saltio.delete(tfile) if os.path.isfile(tilefile): status = saltio.delete(tilefile) # return the file return outstruct
def rectify(hdu, soldict, caltype='line', function='poly', order=3, inttype='interp', w1=None, w2=None, dw=None, nw=None, blank=0, pixscale=0.0, time_interp=False, clobber=True, log=None, verbose=True): """Read in an image and a set of wavlength solutions. Calculate the best wavelength solution for a given dataset and then apply that data set to the image return """ #set the set_w1=(w1 is None) set_w2=(w2 is None) set_dw=(dw is None) set_nw=(nw is None) #set up the time of the observation dateobs=saltkey.get('DATE-OBS', hdu[0]) utctime=saltkey.get('TIME-OBS', hdu[0]) exptime=saltkey.get('EXPTIME', hdu[0]) instrume=saltkey.get('INSTRUME', hdu[0]).strip() grating=saltkey.get('GRATING', hdu[0]).strip() if caltype=='line': grang=saltkey.get('GRTILT', hdu[0]) arang=saltkey.get('CAMANG', hdu[0]) else: grang=saltkey.get('GR-ANGLE', hdu[0]) arang=saltkey.get('AR-ANGLE', hdu[0]) filtername=saltkey.get('FILTER', hdu[0]).strip() slitname=saltkey.get('MASKID', hdu[0]) slit=st.getslitsize(slitname) xbin, ybin = saltkey.ccdbin( hdu[0]) timeobs=enterdatetime('%s %s' % (dateobs, utctime)) #check to see if there is more than one solution if caltype=='line': if len(soldict)==1: sol=soldict.keys()[0] slitid=None if not matchobservations(soldict[sol], instrume, grating, grang, arang, filtername, slitid): msg='Observations do not match setup for transformation but using the solution anyway' if log: log.warning(msg) for i in range(1,len(hdu)): if hdu[i].name=='SCI': if log: log.message('Correcting extension %i' % i) istart=int(0.5*len(hdu[i].data)) #open up the data #set up the xarr and initial wavlength solution xarr=np.arange(len(hdu[i].data[istart]), dtype='int64') #get the slitid try: slitid=saltkey.get('SLITNAME', hdu[i]) except: slitid=None #set up a wavelength solution try: w_arr=findsol(xarr, soldict, istart, caltype, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order ) except SALTSpecError, e: if slitid: msg='SLITID %s: %s' % (slitid, e) if log: log.warning(msg) continue else: raise SALTSpecError(e) if w_arr is None: w_arr=findsol(xarr, soldict, istart, 'rss', timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order ) #set up the output x-axis if set_w1: w1=w_arr.min() if set_w2: w2=w_arr.max() if set_nw: nw=len(xarr) if set_dw: dw=float(w2-w1)/nw nw_arr=createoutputxaxis(w1, w2, nw) #setup the VARIANCE and BPM frames if saltkey.found('VAREXT', hdu[i]): varext=saltkey.get('VAREXT', hdu[i]) else: varext=None #setup the BPM frames if saltkey.found('BPMEXT', hdu[i]): bpmext=saltkey.get('BPMEXT', hdu[i]) else: bpmext=None #for each line in the data, determine the wavelength solution #for a given line in the image for j in range(len(hdu[i].data)): #find the wavelength solution for the data w_arr=findsol(xarr, soldict, j, caltype, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order ) #apply that wavelength solution to the data if w_arr is not None: try: hdu[i].data[j,:]=st.interpolate(nw_arr, w_arr, hdu[i].data[j,:], inttype, left=blank, right=blank) except Exception, e: hdu[i].data[j,:]=hdu[i].data[j,:]*0.0+blank msg='In row %i, solution cannot be found due to %s' % (i, e) #correct the variance frame if varext: try: hdu[varext].data[j,:]=st.interpolate(nw_arr, w_arr, hdu[varext].data[j,:], inttype, left=blank, right=blank) except Exception, e: msg='In row %i, solution cannot be found due to %s' % (i, e) #correct the BPM frame if bpmext: try: hdu[bpmext].data[j,:]=st.interpolate(nw_arr, w_arr, hdu[bpmext].data[j,:], inttype, left=blank, right=blank) except Exception, e: msg='In row %i, solution cannot be found due to %s' % (i, e)
def auto_arc_lens(arc_image, dbfile='wav.db', ndstep=20, logfile='salt.log'): """Automatically process an arc image for the SALT Lens project """ hdu = fits.open(arc_image) hdr = hdu[0].header if hdr['LAMPID'] == 'Xe' and hdr['GRATING'] == 'PG0900' and hdr['GRTILT'] == 15.875: print('Automatically processing arc image') data = hdu[1].data ystart = int(0.5 * len(data)) xarr = np.arange(len(data[ystart]), dtype='int64') farr = data[ystart] lampfile = os.path.dirname(__file__)+'/data/Xe.lens' guessfile = os.path.dirname(__file__)+'/data/lens.db' slines, sfluxes = st.readlinelist(lampfile) spectrum = Spectrum.Spectrum( slines, sfluxes, dw=0.1, stype='line', sigma=6) swarr = spectrum.wavelength sfarr = spectrum.flux * farr.max() / spectrum.flux.max() soldict = readsolascii(guessfile, {}) soldict = (soldict[soldict.keys()[0]]) ws = WavelengthSolution.WavelengthSolution( xarr, xarr, function=soldict[7], order=soldict[8]) ws.func.func.domain = soldict[11] ws.set_coef(soldict[10][2]) # start the pre processing dcoef = ws.coef * 0.0 dcoef[0] = 0.05 * ndstep dcoef[1] = 0.01 * ws.coef[1] ws = st.findxcor(xarr, farr, swarr, sfarr, ws, dcoef=dcoef, ndstep=ndstep, best=False, inttype='interp') xp, wp = st.crosslinematch(xarr, farr, slines, sfluxes, ws, res=6, mdiff=20, wdiff=10, sections=3, sigma=5, niter=5) ws = st.findfit(np.array(xp), np.array(wp), ws=ws, thresh=ws.thresh) print(ws) with logging(logfile, True) as log: iws = ai.AutoIdentify(xarr, data, slines, sfluxes, ws, farr=farr, method='Matchlines', rstep=100, istart=ystart, nrows=1, res=6, dres=0.25, mdiff=20, sigma=5, smooth=3, niter=5, dc=5, ndstep=ndstep, oneline=False, log=log, verbose=True) # get the basic information about the spectrograph dateobs = saltkey.get('DATE-OBS', hdu[0]) try: utctime = saltkey.get('UTC-OBS', hdu[0]) except SaltError: utctime = saltkey.get('TIME-OBS', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() grang = saltkey.get('GR-ANGLE', hdu[0]) grasteps = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) arsteps = saltkey.get('CAMANG', hdu[0]) rssfilter = saltkey.get('FILTER', hdu[0]) specmode = saltkey.get('OBSMODE', hdu[0]) masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper() slitname = saltkey.get('MASKID', hdu[0]) slit = st.getslitsize(slitname) xbin, ybin = saltkey.ccdbin(hdu[0], arc_image) writeIS(iws, dbfile, dateobs=dateobs, utctime=utctime, instrume=instrume, grating=grating, grang=grang, grasteps=grasteps, arsteps=arsteps, arang=arang, rfilter=rssfilter, slit=slit, xbin=xbin, ybin=ybin, objid=None, filename=arc_image, log=log, verbose=True) print(iws) #self.findfit() else: lamp = hdr['LAMPID'] lampfile=iraf.osfn("pysalt$data/linelists/%s.salt" % lamp) lampfile = 'Xe.lens' specidentify(arc_image, lampfile, dbfile, guesstype='rss', guessfile=None, automethod='Matchlines', function='legendre', order=3, rstep=100, rstart='middlerow', mdiff=20, thresh=5, niter=5, smooth=3, inter=True, clobber=True, preprocess=True, logfile=logfile, verbose=True) print("Running specidenity in interactive mode")
def wavemap(hdu, soldict, caltype='line', function='poly', order=3, blank=0, nearest=False, array_only=False, clobber=True, log=None, verbose=True): """Read in an image and a set of wavlength solutions. Calculate the best wavelength solution for a given dataset and then apply that data set to the image return """ # set up the time of the observation dateobs = saltkey.get('DATE-OBS', hdu[0]) utctime = saltkey.get('TIME-OBS', hdu[0]) exptime = saltkey.get('EXPTIME', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() if caltype == 'line': grang = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('CAMANG', hdu[0]) else: grang = saltkey.get('GR-ANGLE', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) filtername = saltkey.get('FILTER', hdu[0]).strip() slitname = saltkey.get('MASKID', hdu[0]) slit = st.getslitsize(slitname) xbin, ybin = saltkey.ccdbin(hdu[0]) timeobs = sr.enterdatetime('%s %s' % (dateobs, utctime)) # check to see if there is more than one solution if caltype == 'line': if len(soldict) == 1: sol = soldict.keys()[0] slitid = None if not sr.matchobservations(soldict[sol], instrume, grating, grang, arang, filtername, slitid): msg = 'Observations do not match setup for transformation but using the solution anyway' if log: log.warning(msg) for i in range(1, len(hdu)): if hdu[i].name == 'SCI': if log: log.message('Correcting extension %i' % i) istart = int(0.5 * len(hdu[i].data)) # open up the data # set up the xarr and initial wavlength solution xarr = np.arange(len(hdu[i].data[istart]), dtype='int64') # get the slitid try: slitid = saltkey.get('SLITNAME', hdu[i]) except: slitid = None #check to see if wavext is already there and if so, then check update #that for the transformation from xshift to wavelength if saltkey.found('WAVEXT', hdu[i]): w_ext = saltkey.get('WAVEXT', hdu[i]) - 1 wavemap = hdu[w_ext].data function, order, coef = sr.findlinesol( soldict, istart, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slitid, xarr) ws = WavelengthSolution.WavelengthSolution(xarr, xarr, function=function, order=order) ws.set_coef(coef) for j in range(len(hdu[i].data)): wavemap[j, :] = ws.value(wavemap[j, :]) if array_only: return wavemap hdu[w_ext].data = wavemap continue # set up a wavelength solution -- still in here for testing MOS data try: w_arr = sr.findsol(xarr, soldict, istart, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) except SALTSpecError as e: if slitid: msg = 'SLITID %s: %s' % (slitid, e) if log: log.warning(msg) continue else: raise SALTSpecError(e) if w_arr is None: w_arr = sr.findsol(xarr, soldict, istart, 'rss', nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) # for each line in the data, determine the wavelength solution # for a given line in the image wavemap = np.zeros_like(hdu[i].data) for j in range(len(hdu[i].data)): # find the wavelength solution for the data w_arr = sr.findsol(xarr, soldict, j, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) if w_arr is not None: wavemap[j, :] = w_arr if array_only: return wavemap # write out the oimg hduwav = fits.ImageHDU(data=wavemap, header=hdu[i].header, name='WAV') hdu.append(hduwav) saltkey.new('WAVEXT', len(hdu) - 1, 'Extension for Wavelength Map', hdu[i]) return hdu
def identify(img, oimg, slines, sfluxes, guesstype, guessfile, function, order, rstep, interact, clobber, log, verbose): """For a given image, find the solution for each row in the file. Use the appropriate first guess and guess type along with the appropriate function and order for the fit. Write out the new image with the solution in the headers and/or as a table in the multi-extension fits file returns the status """ status = 0 ImageSolution = {} dcstep = 3 nstep = 50 res = 2.0 dres = 0.1 centerrow = None nrows = 1 sigma = 3 niter = 5 xdiff = 2 * res method = 'MatchZero' # Open up the image hdu = saltsafeio.openfits(img) # Read in important keywords # determine the central row and read it in try: data = hdu[1].data midline = int(0.5 * len(data)) xarr = np.arange(len(data[midline])) specarr = data except Exception as e: message = 'Unable to read in data array in %s because %s' % (img, e) raise SALTSpecError(message) # determine the type of first guess. Assumes none if guesstype == 'user': pass elif guesstype == 'rss': dateobs = saltsafekey.get('DATE-OBS', hdu[0], img) utctime = saltsafekey.get('UTC-OBS', hdu[0], img) instrume = saltsafekey.get('INSTRUME', hdu[0], img) grating = saltsafekey.get('GRATING', hdu[0], img) grang = saltsafekey.get('GR-ANGLE', hdu[0], img) arang = saltsafekey.get('AR-ANGLE', hdu[0], img) filter = saltsafekey.get('FILTER', hdu[0], img) slit = float(saltsafekey.get('MASKID', hdu[0], img)) xbin, ybin = saltsafekey.ccdbin(hdu[0], img) # set up the rss model rssmodel = RSSModel.RSSModel(grating_name=grating.strip(), gratang=grang, camang=arang, slit=slit, xbin=xbin, ybin=ybin) rss = rssmodel.rss res = 1e7 * rss.calc_resolelement(rss.gratang, rss.gratang - rss.camang) if not instrume in ['PFIS', 'RSS']: msg = '%s is not a currently supported instrument' % instrume raise SALTSpecError(msg) ws = useRSSModel(xarr, rss, function=function, order=order) elif guesstype == 'image': pass else: ws = None # run in either interactive or non-interactive mode if interact: ImageSolution = InterIdentify(xarr, specarr, slines, sfluxes, ws, xdiff=xdiff, function=function, order=order, verbose=True) else: ImageSolution = AutoIdentify(xarr, specarr, slines, sfluxes, ws, rstep=rstep, method=method, icenter=centerrow, nrows=nrows, res=res, dres=dres, dc=dcstep, nstep=nstep, sigma=sigma, niter=niter, verbose=verbose) # set up the list of solutions to into an array key_arr = np.array(ImageSolution.keys()) arg_arr = key_arr.argsort() ws_arr = np.zeros((len(arg_arr), len(ws.coef) + 1), dtype=float) # write the solution to an array for j, i in enumerate(arg_arr): if isinstance(ImageSolution[key_arr[i]], WavelengthSolution.WavelengthSolution): ws_arr[j, 0] = key_arr[i] ws_arr[j, 1:] = ImageSolution[key_arr[i]].coef # write the solution as an file if outfile: # write header to the file that should include the order and function if os.path.isfile(outfile) and not clobber: dout = open(outfile, 'a') else: dout = open(outfile, 'w') msg = '#WS: Wavelength solution for image %s\n' % img msg += '#The following parameters were used in determining the solution:\n' msg += '#name=%s\n' % img msg += '#time-obs=%s %s\n' % (dateobs, utctime) msg += '#instrument=%s\n' % instrume msg += '#grating=%s\n' % grating.strip() msg += '#graang=%s\n' % grang msg += '#arang=%s\n' % arang msg += '#filter=%s\n' % filter.strip() msg += '#Function=%s\n' % function msg += '#Order=%s\n' % order msg += '#Starting Data\n' dout.write(msg) for i in range(len(ws_arr)): if ws_arr[i, 0]: msg = '%5.2f ' % ws_arr[i, 0] msg += ' '.join(['%e' % k for k in ws_arr[i, 1:]]) dout.write(msg + '\n') dout.write('\n') dout.close() # write the solution as an extension hdu.close() return
def saltadvance(images, outpath, obslogfile=None, gaindb=None,xtalkfile=None, geomfile=None,subover=True,trim=True,masbias=None, subbias=False, median=False, function='polynomial', order=5,rej_lo=3, rej_hi=3,niter=5,interp='linear', sdbhost='',sdbname='',sdbuser='', password='', clobber=False, cleanup=True, logfile='salt.log', verbose=True): """SALTADVANCE provides advanced data reductions for a set of data. It will sort the data, and first process the biases, flats, and then the science frames. It will record basic quality control information about each of the steps. """ plotover=False #start logging with logging(logfile,debug) as log: # Check the input images infiles = saltio.argunpack ('Input',images) infiles.sort() # create list of output files outpath=saltio.abspath(outpath) #log into the database sdb=saltmysql.connectdb(sdbhost, sdbname, sdbuser, password) #does the gain database file exist if gaindb: dblist= saltio.readgaindb(gaindb) else: dblist=[] # does crosstalk coefficient data exist if xtalkfile: xtalkfile = xtalkfile.strip() xdict = saltio.readxtalkcoeff(xtalkfile) else: xdict=None #does the mosaic file exist--raise error if no saltio.fileexists(geomfile) # Delete the obslog file if it already exists if os.path.isfile(obslogfile) and clobber: saltio.delete(obslogfile) #read in the obsveration log or create it if os.path.isfile(obslogfile): msg='The observing log already exists. Please either delete it or run saltclean with clobber=yes' raise SaltError(msg) else: headerDict=obslog(infiles, log) obsstruct=createobslogfits(headerDict) saltio.writefits(obsstruct, obslogfile) #create the list of bias frames and process them filename=obsstruct.data.field('FILENAME') detmode=obsstruct.data.field('DETMODE') obsmode=obsstruct.data.field('OBSMODE') ccdtype=obsstruct.data.field('CCDTYPE') propcode=obsstruct.data.field('PROPID') masktype=obsstruct.data.field('MASKTYP') #set the bias list of objects biaslist=filename[(ccdtype=='ZERO')*(propcode=='CAL_BIAS')] masterbias_dict={} for img in infiles: if os.path.basename(img) in biaslist: #open the image struct=fits.open(img) bimg=outpath+'bxgp'+os.path.basename(img) #print the message if log: message='Processing Zero frame %s' % img log.message(message, with_stdout=verbose) #process the image struct=clean(struct, createvar=True, badpixelstruct=None, mult=True, dblist=dblist, xdict=xdict, subover=subover, trim=trim, subbias=False, bstruct=None, median=median, function=function, order=order, rej_lo=rej_lo, rej_hi=rej_hi, niter=niter, plotover=plotover, log=log, verbose=verbose) #update the database updatedq(os.path.basename(img), struct, sdb) #write the file out # housekeeping keywords fname, hist=history(level=1, wrap=False, exclude=['images', 'outimages', 'outpref']) saltkey.housekeeping(struct[0],'SPREPARE', 'Images have been prepared', hist) saltkey.new('SGAIN',time.asctime(time.localtime()),'Images have been gain corrected',struct[0]) saltkey.new('SXTALK',time.asctime(time.localtime()),'Images have been xtalk corrected',struct[0]) saltkey.new('SBIAS',time.asctime(time.localtime()),'Images have been de-biased',struct[0]) # write FITS file saltio.writefits(struct,bimg, clobber=clobber) saltio.closefits(struct) #add files to the master bias list masterbias_dict=compareimages(struct, bimg, masterbias_dict, keylist=biasheader_list) #create the master bias frame for i in masterbias_dict.keys(): bkeys=masterbias_dict[i][0] blist=masterbias_dict[i][1:] mbiasname=outpath+createmasterbiasname(blist, bkeys) bfiles=','.join(blist) saltcombine(bfiles, mbiasname, method='median', reject='sigclip', mask=False, weight=False, blank=0, scale=None, statsec=None, lthresh=3, \ hthresh=3, clobber=False, logfile=logfile,verbose=verbose) #create the list of flatfields and process them flatlist=filename[ccdtype=='FLAT'] masterflat_dict={} for img in infiles: if os.path.basename(img) in flatlist: #open the image struct=fits.open(img) fimg=outpath+'bxgp'+os.path.basename(img) #print the message if log: message='Processing Flat frame %s' % img log.message(message, with_stdout=verbose) #process the image struct=clean(struct, createvar=True, badpixelstruct=None, mult=True, dblist=dblist, xdict=xdict, subover=subover, trim=trim, subbias=False, bstruct=None, median=median, function=function, order=order, rej_lo=rej_lo, rej_hi=rej_hi, niter=niter, plotover=plotover, log=log, verbose=verbose) #update the database updatedq(os.path.basename(img), struct, sdb) #write the file out # housekeeping keywords fname, hist=history(level=1, wrap=False, exclude=['images', 'outimages', 'outpref']) saltkey.housekeeping(struct[0],'SPREPARE', 'Images have been prepared', hist) saltkey.new('SGAIN',time.asctime(time.localtime()),'Images have been gain corrected',struct[0]) saltkey.new('SXTALK',time.asctime(time.localtime()),'Images have been xtalk corrected',struct[0]) saltkey.new('SBIAS',time.asctime(time.localtime()),'Images have been de-biased',struct[0]) # write FITS file saltio.writefits(struct,fimg, clobber=clobber) saltio.closefits(struct) #add files to the master bias list masterflat_dict=compareimages(struct, fimg, masterflat_dict, keylist=flatheader_list) #create the master flat frame for i in masterflat_dict.keys(): fkeys=masterflat_dict[i][0] flist=masterflat_dict[i][1:] mflatname=outpath+createmasterflatname(flist, fkeys) ffiles=','.join(flist) saltcombine(ffiles, mflatname, method='median', reject='sigclip', mask=False, weight=False, blank=0, scale=None, statsec=None, lthresh=3, \ hthresh=3, clobber=False, logfile=logfile,verbose=verbose) #process the arc data arclist=filename[(ccdtype=='ARC') * (obsmode=='SPECTROSCOPY') * (masktype=='LONGSLIT')] for i, img in enumerate(infiles): nimg=os.path.basename(img) if nimg in arclist: #open the image struct=fits.open(img) simg=outpath+'bxgp'+os.path.basename(img) obsdate=os.path.basename(img)[1:9] #print the message if log: message='Processing ARC frame %s' % img log.message(message, with_stdout=verbose) struct=clean(struct, createvar=False, badpixelstruct=None, mult=True, dblist=dblist, xdict=xdict, subover=subover, trim=trim, subbias=False, bstruct=None, median=median, function=function, order=order, rej_lo=rej_lo, rej_hi=rej_hi, niter=niter, plotover=plotover, log=log, verbose=verbose) # write FITS file saltio.writefits(struct,simg, clobber=clobber) saltio.closefits(struct) #mosaic the images mimg=outpath+'mbxgp'+os.path.basename(img) saltmosaic(images=simg, outimages=mimg,outpref='',geomfile=geomfile, interp=interp,cleanup=True,clobber=clobber,logfile=logfile, verbose=verbose) #remove the intermediate steps saltio.delete(simg) #measure the arcdata arcimage=outpath+'mbxgp'+nimg dbfile=outpath+obsdate+'_specid.db' lamp = obsstruct.data.field('LAMPID')[i] lamp = lamp.replace(' ', '') lampfile = iraf.osfn("pysalt$data/linelists/%s.salt" % lamp) print arcimage, lampfile, os.getcwd() specidentify(arcimage, lampfile, dbfile, guesstype='rss', guessfile='', automethod='Matchlines', function='legendre', order=3, rstep=100, rstart='middlerow', mdiff=20, thresh=3, startext=0, niter=5, smooth=3, inter=False, clobber=True, logfile=logfile, verbose=verbose) try: ximg = outpath+'xmbxgp'+os.path.basename(arcimage) specrectify(images=arcimage, outimages=ximg, outpref='', solfile=dbfile, caltype='line', function='legendre', order=3, inttype='interp', w1=None, w2=None, dw=None, nw=None, blank=0.0, conserve=True, nearest=True, clobber=True, logfile=logfile, verbose=verbose) except: pass #process the science data for i, img in enumerate(infiles): nimg=os.path.basename(img) if not (nimg in flatlist or nimg in biaslist or nimg in arclist): #open the image struct=fits.open(img) if struct[0].header['PROPID'].count('CAL_GAIN'): continue simg=outpath+'bxgp'+os.path.basename(img) #print the message if log: message='Processing science frame %s' % img log.message(message, with_stdout=verbose) #Check to see if it is RSS 2x2 and add bias subtraction instrume=saltkey.get('INSTRUME', struct[0]).strip() gainset = saltkey.get('GAINSET', struct[0]) rospeed = saltkey.get('ROSPEED', struct[0]) target = saltkey.get('OBJECT', struct[0]).strip() exptime = saltkey.get('EXPTIME', struct[0]) obsmode = saltkey.get('OBSMODE', struct[0]).strip() detmode = saltkey.get('DETMODE', struct[0]).strip() masktype = saltkey.get('MASKTYP', struct[0]).strip() xbin, ybin = saltkey.ccdbin( struct[0], img) obsdate=os.path.basename(img)[1:9] bstruct=None crtype=None thresh=5 mbox=11 bthresh=5.0, flux_ratio=0.2 bbox=25 gain=1.0 rdnoise=5.0 fthresh=5.0 bfactor=2 gbox=3 maxiter=5 subbias=False if instrume=='RSS' and gainset=='FAINT' and rospeed=='SLOW': bfile='P%sBiasNM%ix%iFASL.fits' % (obsdate, xbin, ybin) if os.path.exists(bfile): bstruct=fits.open(bfile) subbias=True if detmode=='Normal' and target!='ARC' and xbin < 5 and ybin < 5: crtype='edge' thresh=5 mbox=11 bthresh=5.0, flux_ratio=0.2 bbox=25 gain=1.0 rdnoise=5.0 fthresh=5.0 bfactor=2 gbox=3 maxiter=3 #process the image struct=clean(struct, createvar=True, badpixelstruct=None, mult=True, dblist=dblist, xdict=xdict, subover=subover, trim=trim, subbias=subbias, bstruct=bstruct, median=median, function=function, order=order, rej_lo=rej_lo, rej_hi=rej_hi, niter=niter, plotover=plotover, crtype=crtype,thresh=thresh,mbox=mbox, bbox=bbox, \ bthresh=bthresh, flux_ratio=flux_ratio, gain=gain, rdnoise=rdnoise, bfactor=bfactor, fthresh=fthresh, gbox=gbox, maxiter=maxiter, log=log, verbose=verbose) #update the database updatedq(os.path.basename(img), struct, sdb) #write the file out # housekeeping keywords fname, hist=history(level=1, wrap=False, exclude=['images', 'outimages', 'outpref']) saltkey.housekeeping(struct[0],'SPREPARE', 'Images have been prepared', hist) saltkey.new('SGAIN',time.asctime(time.localtime()),'Images have been gain corrected',struct[0]) saltkey.new('SXTALK',time.asctime(time.localtime()),'Images have been xtalk corrected',struct[0]) saltkey.new('SBIAS',time.asctime(time.localtime()),'Images have been de-biased',struct[0]) # write FITS file saltio.writefits(struct,simg, clobber=clobber) saltio.closefits(struct) #mosaic the files--currently not in the proper format--will update when it is if not saltkey.fastmode(saltkey.get('DETMODE', struct[0])): mimg=outpath+'mbxgp'+os.path.basename(img) saltmosaic(images=simg, outimages=mimg,outpref='',geomfile=geomfile, interp=interp,fill=True, cleanup=True,clobber=clobber,logfile=logfile, verbose=verbose) #remove the intermediate steps saltio.delete(simg) #if the file is spectroscopic mode, apply the wavelength correction if obsmode == 'SPECTROSCOPY' and masktype.strip()=='LONGSLIT': dbfile=outpath+obsdate+'_specid.db' try: ximg = outpath+'xmbxgp'+os.path.basename(img) specrectify(images=mimg, outimages=ximg, outpref='', solfile=dbfile, caltype='line', function='legendre', order=3, inttype='interp', w1=None, w2=None, dw=None, nw=None, blank=0.0, conserve=True, nearest=True, clobber=True, logfile=logfile, verbose=verbose) except Exception, e: log.message('%s' % e) #clean up the results if cleanup: #clean up the bias frames for i in masterbias_dict.keys(): blist=masterbias_dict[i][1:] for b in blist: saltio.delete(b) #clean up the flat frames for i in masterflat_dict.keys(): flist=masterflat_dict[i][1:] for f in flist: saltio.delete(f)
def identify(img, oimg, slines, sfluxes, guesstype, guessfile, function, order, rstep, interact, clobber, log, verbose): """For a given image, find the solution for each row in the file. Use the appropriate first guess and guess type along with the appropriate function and order for the fit. Write out the new image with the solution in the headers and/or as a table in the multi-extension fits file returns the status """ status = 0 ImageSolution = {} dcstep = 3 nstep = 50 res = 2.0 dres = 0.1 centerrow = None nrows = 1 sigma = 3 niter = 5 xdiff = 2 * res method = "MatchZero" # Open up the image hdu = saltsafeio.openfits(img) # Read in important keywords # determine the central row and read it in try: data = hdu[1].data midline = int(0.5 * len(data)) xarr = np.arange(len(data[midline])) specarr = data except Exception as e: message = "Unable to read in data array in %s because %s" % (img, e) raise SALTSpecError(message) # determine the type of first guess. Assumes none if guesstype == "user": pass elif guesstype == "rss": dateobs = saltsafekey.get("DATE-OBS", hdu[0], img) utctime = saltsafekey.get("UTC-OBS", hdu[0], img) instrume = saltsafekey.get("INSTRUME", hdu[0], img) grating = saltsafekey.get("GRATING", hdu[0], img) grang = saltsafekey.get("GR-ANGLE", hdu[0], img) arang = saltsafekey.get("AR-ANGLE", hdu[0], img) filter = saltsafekey.get("FILTER", hdu[0], img) slit = float(saltsafekey.get("MASKID", hdu[0], img)) xbin, ybin = saltsafekey.ccdbin(hdu[0], img) # set up the rss model rssmodel = RSSModel.RSSModel( grating_name=grating.strip(), gratang=grang, camang=arang, slit=slit, xbin=xbin, ybin=ybin ) rss = rssmodel.rss res = 1e7 * rss.calc_resolelement(rss.gratang, rss.gratang - rss.camang) if not instrume in ["PFIS", "RSS"]: msg = "%s is not a currently supported instrument" % instrume raise SALTSpecError(msg) ws = useRSSModel(xarr, rss, function=function, order=order) elif guesstype == "image": pass else: ws = None # run in either interactive or non-interactive mode if interact: ImageSolution = InterIdentify( xarr, specarr, slines, sfluxes, ws, xdiff=xdiff, function=function, order=order, verbose=True ) else: ImageSolution = AutoIdentify( xarr, specarr, slines, sfluxes, ws, rstep=rstep, method=method, icenter=centerrow, nrows=nrows, res=res, dres=dres, dc=dcstep, nstep=nstep, sigma=sigma, niter=niter, verbose=verbose, ) # set up the list of solutions to into an array key_arr = np.array(ImageSolution.keys()) arg_arr = key_arr.argsort() ws_arr = np.zeros((len(arg_arr), len(ws.coef) + 1), dtype=float) # write the solution to an array for j, i in enumerate(arg_arr): if isinstance(ImageSolution[key_arr[i]], WavelengthSolution.WavelengthSolution): ws_arr[j, 0] = key_arr[i] ws_arr[j, 1:] = ImageSolution[key_arr[i]].coef # write the solution as an file if outfile: # write header to the file that should include the order and function if os.path.isfile(outfile) and not clobber: dout = open(outfile, "a") else: dout = open(outfile, "w") msg = "#WS: Wavelength solution for image %s\n" % img msg += "#The following parameters were used in determining the solution:\n" msg += "#name=%s\n" % img msg += "#time-obs=%s %s\n" % (dateobs, utctime) msg += "#instrument=%s\n" % instrume msg += "#grating=%s\n" % grating.strip() msg += "#graang=%s\n" % grang msg += "#arang=%s\n" % arang msg += "#filter=%s\n" % filter.strip() msg += "#Function=%s\n" % function msg += "#Order=%s\n" % order msg += "#Starting Data\n" dout.write(msg) for i in range(len(ws_arr)): if ws_arr[i, 0]: msg = "%5.2f " % ws_arr[i, 0] msg += " ".join(["%e" % k for k in ws_arr[i, 1:]]) dout.write(msg + "\n") dout.write("\n") dout.close() # write the solution as an extension hdu.close() return
def rectify(hdu, soldict, caltype='line', function='poly', order=3, inttype='interp', w1=None, w2=None, dw=None, nw=None, blank=0, pixscale=0.0, time_interp=False, conserve=False, nearest=False, clobber=True, log=None, verbose=True): """Read in an image and a set of wavlength solutions. Calculate the best wavelength solution for a given dataset and then apply that data set to the image return """ # set the basic values set_w1 = (w1 is None) set_w2 = (w2 is None) set_dw = (dw is None) set_nw = (nw is None) # set up the time of the observation dateobs = saltkey.get('DATE-OBS', hdu[0]) utctime = saltkey.get('TIME-OBS', hdu[0]) exptime = saltkey.get('EXPTIME', hdu[0]) instrume = saltkey.get('INSTRUME', hdu[0]).strip() grating = saltkey.get('GRATING', hdu[0]).strip() if caltype == 'line': grang = saltkey.get('GRTILT', hdu[0]) arang = saltkey.get('CAMANG', hdu[0]) else: grang = saltkey.get('GR-ANGLE', hdu[0]) arang = saltkey.get('AR-ANGLE', hdu[0]) filtername = saltkey.get('FILTER', hdu[0]).strip() slitname = saltkey.get('MASKID', hdu[0]) slit = st.getslitsize(slitname) xbin, ybin = saltkey.ccdbin(hdu[0]) timeobs = enterdatetime('%s %s' % (dateobs, utctime)) # check to see if there is more than one solution if caltype == 'line': if len(soldict) == 1: sol = soldict.keys()[0] slitid = None if not matchobservations( soldict[sol], instrume, grating, grang, arang, filtername, slitid): msg = 'Observations do not match setup for transformation but using the solution anyway' if log: log.warning(msg) for i in range(1, len(hdu)): if hdu[i].name == 'SCI': if log: log.message('Correcting extension %i' % i) istart = int(0.5 * len(hdu[i].data)) # open up the data # set up the xarr and initial wavlength solution xarr = np.arange(len(hdu[i].data[istart]), dtype='int64') # get the slitid try: slitid = saltkey.get('SLITNAME', hdu[i]) except: slitid = None # set up a wavelength solution try: w_arr = findsol(xarr, soldict, istart, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) except SALTSpecError as e: if slitid: msg = 'SLITID %s: %s' % (slitid, e) if log: log.warning(msg) continue else: raise SALTSpecError(e) if w_arr is None: w_arr = findsol(xarr, soldict, istart, 'rss', nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) # set up the output x-axis if set_w1: w1 = w_arr.min() if set_w2: w2 = w_arr.max() if set_nw: nw = len(xarr) if set_dw: dw = float(w2 - w1) / nw nw_arr = createoutputxaxis(w1, w2, nw) # setup the VARIANCE and BPM frames if saltkey.found('VAREXT', hdu[i]): varext = saltkey.get('VAREXT', hdu[i]) else: varext = None # setup the BPM frames if saltkey.found('BPMEXT', hdu[i]): bpmext = saltkey.get('BPMEXT', hdu[i]) else: bpmext = None # for each line in the data, determine the wavelength solution # for a given line in the image for j in range(len(hdu[i].data)): # find the wavelength solution for the data w_arr = findsol(xarr, soldict, j, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slit, xbin, ybin, slitid, function, order) # apply that wavelength solution to the data if w_arr is not None: try: hdu[i].data[ j, :] = st.interpolate( nw_arr, w_arr, hdu[i].data[ j, :], inttype, left=blank, right=blank) except Exception as e: hdu[i].data[j, :] = hdu[i].data[j, :] * 0.0 + blank msg = 'In row %i, solution cannot be found due to %s' % ( i, e) # correct the variance frame if varext: try: hdu[varext].data[ j, :] = st.interpolate( nw_arr, w_arr, hdu[varext].data[ j, :], inttype, left=blank, right=blank) except Exception as e: msg = 'In row %i, solution cannot be found due to %s' % ( i, e) # correct the BPM frame if bpmext: try: hdu[bpmext].data[ j, :] = st.interpolate( nw_arr, w_arr, hdu[bpmext].data[ j, :], inttype, left=blank, right=blank) except Exception as e: msg = 'In row %i, solution cannot be found due to %s' % ( i, e) else: hdu[i].data[j, :] = hdu[i].data[j, :] * 0.0 + blank if conserve: hdu[i].data = hdu[i].data / dw if varext: hdu[varext].data = hdu[varext].data / dw # Add WCS information saltkey.new('CTYPE1', 'LAMBDA', 'Coordinate Type', hdu[i]) saltkey.new('CTYPE2', 'PIXEL', 'Coordinate Type', hdu[i]) saltkey.new( 'CD1_1', dw, 'WCS: Wavelength Dispersion in angstrom/pixel', hdu[i]) saltkey.new('CD2_1', 0.0, 'WCS: ', hdu[i]) saltkey.new('CD1_2', 0.0, 'WCS: ', hdu[i]) saltkey.new('CD2_2', ybin * pixscale, 'WCS: ', hdu[i]) saltkey.new('CRPIX1', 0.0, 'WCS: X Reference pixel', hdu[i]) saltkey.new('CRPIX2', 0.0, 'WCS: Y Reference pixel', hdu[i]) saltkey.new('CRVAL1', w1, 'WCS: X Reference pixel', hdu[i]) saltkey.new('CRVAL2', 0.0, 'WCS: Y Reference pixel', hdu[i]) saltkey.new('CDELT1', 1.0, 'WCS: X pixel size', hdu[i]) saltkey.new('CDELT2', 1.0, 'WCS: Y pixel size', hdu[i]) saltkey.new('DC-FLAG', 0, 'Dispesion Corrected image', hdu[i]) return hdu
message = 'Unable to read in data array in %s because %s' % (img, e) raise SALTSpecError(message) #determine the type of first guess. Assumes none if guesstype=='user': pass elif guesstype=='rss': dateobs=saltsafekey.get('DATE-OBS', hdu[0], img) utctime=saltsafekey.get('UTC-OBS', hdu[0], img) instrume=saltsafekey.get('INSTRUME', hdu[0], img) grating=saltsafekey.get('GRATING', hdu[0], img) grang=saltsafekey.get('GR-ANGLE', hdu[0], img) arang=saltsafekey.get('AR-ANGLE', hdu[0], img) filter=saltsafekey.get('FILTER', hdu[0], img) xbin, ybin = saltsafekey.ccdbin( hdu[0], img) if not instrume in ['PFIS', 'RSS']: msg='%s is not a currently supported instrument' % instrume raise SALTSpecError(msg) ws=useRSSModel(xarr, grating, grang, arang, xbin, function=function, order=order) elif guesstype=='image': pass else: ws=None #if interactive is selected launch the tool in interactive mode #if not, produce a wavelength solution from the information already #provided. xdiff=20 ws= findwavelengthsolution(xarr, specarr, slines, sfluxes, ws, xdiff, function, order, zeropoint=False, interact=interact, verbose=verbose)
def specslit(image, outimage, outpref, exttype='auto', slitfile='', outputslitfile='', regprefix='', sections=3, width=25, sigma=2.2, thres=6, order=3, padding=5, yoffset=0, inter=False, clobber=True, logfile='salt.log', verbose=True): with logging(logfile, debug) as log: # check all the input and make sure that all the input needed is provided # by the user # read the image or image list and check if each in the list exist infiles = saltio.argunpack('Input', image) # unpack the outfiles outfiles = saltio.listparse( 'Outimages', outimage, outpref, infiles, '') # from the extraction type, check whether the input file is specified. # if the slitfile parameter is specified then use the slit files for # the extraction. if the extraction type is auto then use image for the # detection and the slit extraction if exttype == 'rsmt' or exttype == 'fits' or exttype == 'ascii' or exttype == 'ds9': slitfiles = saltio.argunpack('Slitfile', slitfile) if len(slitfiles) == 1: slitfiles = slitfiles * len(infiles) saltio.comparelists(infiles, slitfiles, 'image', 'slitfile') elif exttype == 'auto': slitfiles = infiles log.message( 'Extraction type is AUTO. Slit detection will be done from image') # read in if an optional ascii file is requested if len(outputslitfile) > 0: outslitfiles = saltio.argunpack('Outslitfiles', outputslitfile) saltio.comparelists( infiles, outslitfiles, 'image', 'outputslitfile') else: outslitfiles = [''] * len(infiles) # check if the width and sigma parameters were specified. # default is 25 and 2.2 if width < 10.: msg = 'The width parameter needs be a value larger than 10' raise SALTSpecError(msg) if sigma < 0.0: msg = 'Sigma must be greater than zero' raise SaltSpecError(msg) # check the treshold parameter. this needs to be specified by the user if thres <= 0.0: msg = 'Threshold must be greater than zero' raise SaltSpecError(msg) # check to make sure that the sections are greater than the order if sections <= order: msg = 'Number of sections must be greater than the order for the spline fit' raise SaltSpecError(msg) # run through each of the images and extract the slits for img, oimg, sfile, oslit in zip( infiles, outfiles, slitfiles, outslitfiles): log.message('Proccessing image %s' % img) # open the image struct = saltio.openfits(img) ylen, xlen = struct[1].data.shape xbin, ybin = saltkey.ccdbin(struct[0], img) # setup the VARIANCE and BPM frames if saltkey.found('VAREXT', struct[1]): varext = saltkey.get('VAREXT', struct[1]) varlist = [] else: varext = None # setup the BPM frames if saltkey.found('BPMEXT', struct[1]): bpmext = saltkey.get('BPMEXT', struct[1]) bpmlist = [] else: bpmext = None # open the slit definition file or identify the slits in the image slitmask = None ycheck = False if exttype == 'rsmt': log.message('Using slits from %s' % sfile) if yoffset is None: yoffset = 0 ycheck = True slitmask = mt.read_slitmask_from_xml(sfile) xpos = -0.3066 ypos = 0.0117 cx = int(xlen / 2.0) cy = int(ylen / 2.0) + ypos / 0.015 / ybin + yoffset order, slit_positions = mt.convert_slits_from_mask( slitmask, order=1, xbin=xbin, ybin=ybin, pix_scale=0.1267, cx=cx, cy=cy) sections = 1 elif exttype == 'fits': log.message('Using slits from %s' % sfile) order, slit_positions = read_slits_from_fits(sfile) elif exttype == 'ascii': log.message('Using slits from %s' % sfile) order, slit_positions = mt.read_slits_from_ascii(sfile) elif exttype == 'ds9': log.message('Using slits from %s' % sfile) order, slit_positions, slitmask = mt.read_slits_from_ds9( sfile, order=order) slitmask = None sections = 1 elif exttype == 'auto': log.message('Identifying slits in %s' % img) # identify the slits in the image order, slit_positions = identify_slits( struct[1].data, order, sections, width, sigma, thres) # write out the slit identifications if ofile has been supplied if oslit: log.message('Writing slit positions to %s' % oslit) mt.write_outputslitfile(slit_positions, oslit, order) if ycheck: slit_positions, dy = check_ypos(slit_positions, struct[1].data) log.message('Using an offset of {}'.format(dy)) # extract the slits spline_x = mt.divide_image(struct[1].data, sections) spline_x = 0.5 * (np.array(spline_x[:-1]) + np.array(spline_x[1:])) extracted_spectra, spline_positions = mt.extract_slits(slit_positions, spline_x, struct[1].data, order=order, padding=padding) if varext: extracted_var, var_positions = mt.extract_slits(slit_positions, spline_x, struct[varext].data, order=order, padding=padding) if bpmext: extracted_bpm, bpm_positions = mt.extract_slits(slit_positions, spline_x, struct[bpmext].data, order=order, padding=padding) # write out the data to the new array # create the new file hdulist = fits.HDUList([struct[0]]) # log the extracted spectra if needed log.message('', with_stdout=verbose) # setup output ds9 file if regprefix: regout = open( regprefix + os.path.basename(img).strip('.fits') + '.reg', 'w') regout.write('# Region file format: DS9 version 4.1\n') regout.write('# Filename: %s\n' % img) regout.write( 'global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1\nphysical\n') # add each imglist = [] nslits = len(spline_positions) for i in range(nslits): y1 = spline_positions[i][0].min() y2 = spline_positions[i][1].max() msg = 'Extracted Spectra %i between %i to %i' % (i + 1, y1, y2) # log.message(msg, with_header=False, with_stdout=verbose) sdu = fits.ImageHDU( extracted_spectra[i], header=struct[1].header) if varext: vdu = fits.ImageHDU( extracted_var[i], header=struct[varext].header) sdu.header['VAREXT'] = i + nslits + 1 varlist.append(vdu) if bpmext: bdu = fits.ImageHDU( extracted_bpm[i], header=struct[bpmext].header) sdu.header['BPMEXT']= i + 2 * nslits + 1 bpmlist.append(bdu) imglist.append(sdu) # add in some additional keywords imglist[i].header['MINY'] = (y1, 'Lower Y value in original image') imglist[i].header['MAXY'] = (y2, 'Upper Y value in original image') if regprefix: xsize = struct[1].data.shape[1] xsize = int(0.5 * xsize) rtext = '' if slitmask: # rtext='%s, %8.7f, %8.7f, %3.2f' % (slitmask.slitlets.data[i]['name'], slitmask.slitlets.data[i]['targ_ra'], slitmask.slitlets.data[i]['targ_dec'], slitmask.slitlets.data[i]['slit_width']) pass regout.write('box(%i,%i, %i, %i) #text={%s}\n' % ( xsize, 0.5 * (y1 + y2), 2 * xsize, y2 - y1, rtext)) # add slit information if slitmask: imglist[i].header['SLITNAME'] = (slitmask.slitlets.data[i]['name'], 'Slit Name') imglist[i].header['SLIT_RA'] = (slitmask.slitlets.data[i]['targ_ra'], 'Slit RA') imglist[i].header['SLIT_DEC'] = (slitmask.slitlets.data[i]['targ_dec'], 'Slit DEC') imglist[i].header['SLIT'] = (slitmask.slitlets.data[i]['slit_width'], 'Slit Width') # add to the hdulist hdulist += imglist if varext: hdulist += varlist if bpmext: hdulist += bpmlist # write the slit positions to the header # create the binary table HDU that contains the split positions tbhdu = mt.slits_HDUtable(slit_positions, order) bintable_hdr = tbhdu.header # add the extname parameter to the extension tbhdu.header['EXTNAME'] = 'BINTABLE' # add the extname parameter to the extension hdulist[0].header['SLITEXT'] = len(hdulist) hdulist.append(tbhdu) # add addition header information about the mask if slitmask: hdulist[0].header['MASKNAME'] = (slitmask.mask_name, 'SlitMask Name') hdulist[0].header['MASK_RA'] = (slitmask.center_ra, 'SlitMask RA') hdulist[0].header['MASK_DEC'] = ( slitmask.center_dec, 'SlitMask DEC') hdulist[0].header['MASK_PA'] = ( slitmask.position_angle, 'SlitMask Position Angle') # write out the image saltio.writefits(hdulist, oimg, clobber)
def prepare(hdu): """Prepare HRS data to be similar to other SALT file formats This includes splitting each amplifier into multi-extension formats """ #set the detector detname=saltkey.get('DETNAM', hdu[0]) if detname=='08443-03-01' or detname=='HRDET': detector='hrdet' elif detname=='04434-23-02' or detname=='HBDET': detector='hbdet' else: raise SaltError('%s is not an HRS detector' % detnam) #get key parameters try: nccd=saltkey.get('CCDNAMPS', hdu[0]) except: nccd=saltkey.get('CCDAMPS', hdu[0]) xbin, ybin=saltkey.ccdbin(hdu[0]) gain=saltkey.get('GAIN', hdu[0]) gain=gain.split() rospeed=saltkey.get('ROSPEED', hdu[0]) ccdshape=hdu[0].data.shape #create a multiexention fits file phdu=pyfits.PrimaryHDU() phdu.header=hdu[0].header nhdu = pyfits.HDUList(phdu) #these keywords need to be added saltkey.new('DETMODE', value='Normal', comment='Detector mode', hdu=nhdu[0]) saltkey.new('NCCDS', value=1, comment='Detector mode', hdu=nhdu[0]) saltkey.new('GAINSET', value='SLOW', comment='Detector mode', hdu=nhdu[0]) value='OBJECT' if hdu[0].header['OBJECT']=='Bias': value='ZERO' if hdu[0].header['OBJECT']=='Arc': value='ARC' if hdu[0].header['OBJECT']=='Flat': value='FLAT' saltkey.new('CCDTYPE', value=value, comment='CCD Type', hdu=nhdu[0]) if nccd==1: nhdu.append(pyfits.ImageHDU(hdu[0].data)) j=1 saltkey.new('GAIN', value=float(gain[0]), comment='Nominal CCD gain (e/ADU)', hdu=nhdu[j]) saltkey.new('RDNOISE', value=0, comment='Nominal readout noise in e', hdu=nhdu[j]) saltkey.new('SATURATE', value=1, comment='Pixel saturation level in ADU', hdu=nhdu[j]) saltkey.new('XTALK', value=0.0, comment='Cross talk coefficient', hdu=nhdu[j]) detsize=getdetsize(ccdshape, xbin, ybin) ampshape=nhdu[j].data.shape ampsec=getdetsize(ccdshape, 1, 1) saltkey.new('DETSIZE', value=detsize, comment='Detector size', hdu=nhdu[j]) saltkey.new('BIASSEC', value=getbiassec(j, ampshape, xbin, ybin), comment='Bias section', hdu=nhdu[j]) saltkey.new('DATASEC', value=getdatasec(j, ampshape, xbin, ybin), comment='Data section', hdu=nhdu[j]) saltkey.new('AMPSEC', value=ampsec, comment='Amplifier section', hdu=nhdu[j]) saltkey.new('CCDSEC', value=detsize, comment='CCD section', hdu=nhdu[j]) saltkey.new('DETSEC', value=detsize, comment='Detector section', hdu=nhdu[j]) return nhdu for i in range(nccd): j=i+1 x1,x2,y1,y2=definesection(j, detector, ccdshape) nhdu.append(pyfits.ImageHDU(hdu[0].data[y1:y2,x1:x2])) #keywords that need to be added include #gain, rdnoise, xtalk, saturate, saltkey.new('GAIN', value=float(gain[i]), comment='Nominal CCD gain (e/ADU)', hdu=nhdu[j]) saltkey.new('RDNOISE', value=0, comment='Nominal readout noise in e', hdu=nhdu[j]) saltkey.new('SATURATE', value=1, comment='Pixel saturation level in ADU', hdu=nhdu[j]) saltkey.new('XTALK', value=0.0, comment='Cross talk coefficient', hdu=nhdu[j]) #DETSIZE, BIASSEC, DATASEC, #AMPSEC, CCDSEC, DETSEC ampsec='[%i:%i,%i:%i]' % (x1+1,x2,y1+1,y2) ampshape=nhdu[j].data.shape saltkey.new('DETSIZE', value=getdetsize(ccdshape, xbin, ybin), comment='Detector size', hdu=nhdu[j]) saltkey.new('BIASSEC', value=getbiassec(j, ampshape, xbin, ybin), comment='Bias section', hdu=nhdu[j]) saltkey.new('DATASEC', value=getdatasec(j, ampshape, xbin, ybin), comment='Data section', hdu=nhdu[j]) saltkey.new('AMPSEC', value=ampsec, comment='Amplifier section', hdu=nhdu[j]) saltkey.new('CCDSEC', value=getdetsize(ccdshape, xbin, ybin), comment='CCD section', hdu=nhdu[j]) saltkey.new('DETSEC', value=getdetsize(ccdshape, xbin, ybin), comment='Detector section', hdu=nhdu[j]) #BSCALE, BZERO #nhdu[j].header.set('BSCALE', value=1.0, comment='Val=BSCALE*pix+BZERO') #nhdu[j].header.set('BZERO', value=32768., comment='Val=BSCALE*pix+BZERO') #ATM1_1, ATM2_2, #not implimented return nhdu