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 slot(struct,infile,dbspeed,dbrate,dbgain,dbnoise,dbbias,dbamp,xcoeff,gaindb,xtalkfile, logfile,verbose): import saltprint, saltkey, saltio, saltstat, time # identify instrument instrume,keyprep,keygain,keybias,keyxtalk,keyslot,status = saltkey.instrumid(struct,infile,logfile) # number of image HDU nextend = 0 while (status == 0): try: struct[nextend+1].header['XTENSION'] nextend += 1 except: break nccds,status = saltkey.get('NCCDS',struct[0],infile,logfile) amplifiers = nccds * 2 if (nextend%(amplifiers) != 0): message = '\nERROR -- SALTSLOT: Number of image extensions and' message += 'number of amplifiers are not consistent' status = saltprint.err(saltlog,message) status = saltkey.new('NSCIEXT',nextend,'Number of science extensions',struct[0],infile,logfile) status = saltkey.new('NEXTEND',nextend,'Number of data extensions',struct[0],infile,logfile) # check image file and gain database are compatible if (status == 0): ngains = len(dbgain) if (int(max(dbamp)) != amplifiers): message = '\nERROR -- SALTGSLOT: ' + infile + ' contains ' + str(amplifiers) + ' amplifiers' message += ', the gaindb file ' + gaindb + ' contains ' + str(max(dbamp)) + ' amplifiers' status = saltprint.err(logfile,message) # check image file and cross talk database are compatible if (status == 0): if (len(xcoeff)-1 != amplifiers): message = '\nERROR -- SALTSLOT: ' + infile + ' contains ' + str(amplifiers) + ' amplifiers' message += ', the cross talk file ' + xtalkfile + ' contains ' + str(len(xcoeff)-1) + ' amplifiers' status = saltprint.err(logfile,message) # housekeeping keywords if (status == 0): status = saltkey.put('SAL-TLM',time.asctime(time.localtime()),struct[0],infile,logfile) status = saltkey.new(keyslot,time.asctime(time.localtime()), 'Data have been cleaned by SALTSLOT',struct[0],infile,logfile) # keywords for image extensions for i in range(nextend): hdu = i + 1 status = saltkey.new('EXTNAME','SCI','Extension name',struct[hdu],infile,logfile) status = saltkey.new('EXTVER',hdu,'Extension number',struct[hdu],infile,logfile) # log coefficent table if (status == 0): message = '%30s %5s %4s %8s' % ('HDU','Gain','Bias','Xtalk') saltprint.log(logfile,'\n ---------------------------------------------',verbose) saltprint.log(logfile,message,verbose) saltprint.log(logfile,' ---------------------------------------------',verbose) # loop over image extensions if (status == 0): for i in range(nextend/2): hdu = i * 2 + 1 amplifier = hdu%amplifiers if (amplifier == 0): amplifier = amplifiers if (status == 0): value,status = saltkey.get('NAXIS1',struct[hdu],infile,logfile) naxis1 = int(value) if (status == 0): value,status = saltkey.get('NAXIS1',struct[hdu+1],infile,logfile) naxis2 = int(value) if (status == 0 and hdu == 1): biassec, status = saltkey.get('BIASSEC',struct[hdu],infile,logfile) if (status == 0 and hdu == 1): ranges = biassec.lstrip('[').rstrip(']').split(',') x1_1 = int(ranges[0].split(':')[0]) - 1 x2_1 = int(ranges[0].split(':')[1]) - 1 y1_1 = int(ranges[1].split(':')[0]) - 1 y2_1 = int(ranges[1].split(':')[1]) - 1 if (status == 0 and hdu == 1): biassec, status = saltkey.get('BIASSEC',struct[hdu+1],infile,logfile) if (status == 0 and hdu == 1): ranges = biassec.lstrip('[').rstrip(']').split(',') x1_2 = int(ranges[0].split(':')[0]) - 1 x2_2 = int(ranges[0].split(':')[1]) - 1 y1_2 = int(ranges[1].split(':')[0]) - 1 y2_2 = int(ranges[1].split(':')[1]) - 1 if (status == 0 and hdu == 1): datasec,status = saltkey.get('DATASEC',struct[hdu],infile,logfile) if (status == 0 and hdu == 1): ranges = datasec.lstrip('[').rstrip(']').split(',') dx1_1 = int(ranges[0].split(':')[0]) - 1 dx2_1 = int(ranges[0].split(':')[1]) dy1_1 = int(ranges[1].split(':')[0]) - 1 dy2_1 = int(ranges[1].split(':')[1]) if (status == 0 and hdu == 1): datasec,status = saltkey.get('DATASEC',struct[hdu+1],infile,logfile) if (status == 0 and hdu == 1): ranges = datasec.lstrip('[').rstrip(']').split(',') dx1_2 = int(ranges[0].split(':')[0]) - 1 dx2_2 = int(ranges[0].split(':')[1]) dy1_2 = int(ranges[1].split(':')[0]) - 1 dy2_2 = int(ranges[1].split(':')[1]) if (status == 0 and dx2_1 - dx1_1 != dx2_2 - dx1_2): message = 'ERROR -- SALTSLOT: HDUs '+infile message += '['+str(hdu)+'] and '+infile+'['+str(hdu+1)+']' message += ' have different dimensions' status = saltprint.err(logfile,message) # read speed and gain of each exposure if (status == 0 and hdu == 1): gainset,status = saltkey.get('GAINSET',struct[0],infile,logfile) rospeed,status = saltkey.get('ROSPEED',struct[0],infile,logfile) if (rospeed == 'NONE'): saltprint.log(logfile," ",verbose) message = "ERROR -- SALTSLOT: Readout speed is 'NONE' in " message += "primary keywords of " + infile status = saltprint.err(logfile,message) # read raw images if (status == 0): imagedata1,status = saltio.readimage(struct,hdu,logfile) imagedata2,status = saltio.readimage(struct,hdu+1,logfile) # gain correction if (status == 0): for j in range(len(dbgain)): if (gainset == dbrate[j] and rospeed == dbspeed[j] and amplifier == int(dbamp[j])): try: gain1 = float(dbgain[j]) imagedata1 *= gain1 except: mesage = 'ERROR -- SALTSLOT: Cannot perform gain correction on image ' message += infile+'['+str(hdu)+']' status = saltprint.err(logfile,message) elif (gainset == dbrate[j] and rospeed == dbspeed[j] and amplifier + 1 == int(dbamp[j])): try: gain2 = float(dbgain[j]) imagedata2 *= gain2 except: mesage = 'ERROR -- SALTSLOT: Cannot perform gain correction on image ' message += infile+'['+str(hdu+1)+']' status = saltprint.err(logfile,message) # crosstalk correction if (status == 0): revimage1 = imagedata1 * float(xcoeff[amplifier]) revimage2 = imagedata2 * float(xcoeff[amplifier+1]) for j in range(dx2_1-dx1_1+1): imagedata1[:,j] -= revimage2[:,dx2_2-j-1] imagedata2[:,j] -= revimage1[:,dx2_1-j-1] # bias subtraction if (status == 0): overx_val_1 = [] overx_val_2 = [] for x in range(x1_1,x2_1+1): list_1 = imagedata1[y1_1:y2_1,x] * 1.0 overx_val_1.append(saltstat.median(list_1,logfile)) overlevel_1 = saltstat.median(overx_val_1,logfile) for x in range(x1_2,x2_2+1): list_2 = imagedata2[y1_2:y2_2,x] * 1.0 overx_val_2.append(saltstat.median(list_2,logfile)) overlevel_2 = saltstat.median(overx_val_2,logfile) imagedata1 -= overlevel_1 imagedata2 -= overlevel_2 # trim overscan if (status == 0): imagedata1 = imagedata1[dy1_1:dy2_1,dx1_1:dx2_1] imagedata2 = imagedata2[dy1_2:dy2_2,dx1_2:dx2_2] datasec = '[1:'+str(dx2_1-dx1_1)+',1:'+str(dy2_1-dy1_1)+']' status = saltkey.put('DATASEC',datasec,struct[hdu],infile,logfile) status = saltkey.rem('BIASSEC',struct[hdu],infile,logfile) datasec = '[1:'+str(dx2_2-dx1_2)+',1:'+str(dy2_2-dy1_2)+']' status = saltkey.put('DATASEC',datasec,struct[hdu+1],infile,logfile) status = saltkey.rem('BIASSEC',struct[hdu+1],infile,logfile) # log coefficient table if (status == 0): infilename = infile.split('/') infilename = infilename[len(infilename)-1] message = '%25s[%3d] %5.2f %4d %8.6f' % \ (infilename, hdu, gain1, overlevel_1, float(xcoeff[amplifier+1])) saltprint.log(logfile,message,verbose) message = '%25s[%3d] %5.2f %4d %8.6f' % \ (infilename, hdu+1, gain2, overlevel_2,float(xcoeff[amplifier])) saltprint.log(logfile,message,verbose) # update image in HDU structure if (status == 0): struct,status = saltio.writeimage(struct,hdu,imagedata1,logfile) struct,status = saltio.writeimage(struct,hdu+1,imagedata2,logfile) return struct, status
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 slot(struct, infile, dbspeed, dbrate, dbgain, dbnoise, dbbias, dbamp, xcoeff, gaindb, xtalkfile, logfile, verbose): import saltprint, saltkey, saltio, saltstat, time # identify instrument instrume, keyprep, keygain, keybias, keyxtalk, keyslot, status = saltkey.instrumid( struct, infile, logfile) # number of image HDU nextend = 0 while (status == 0): try: struct[nextend + 1].header['XTENSION'] nextend += 1 except: break nccds, status = saltkey.get('NCCDS', struct[0], infile, logfile) amplifiers = nccds * 2 if (nextend % (amplifiers) != 0): message = '\nERROR -- SALTSLOT: Number of image extensions and' message += 'number of amplifiers are not consistent' status = saltprint.err(saltlog, message) status = saltkey.new('NSCIEXT', nextend, 'Number of science extensions', struct[0], infile, logfile) status = saltkey.new('NEXTEND', nextend, 'Number of data extensions', struct[0], infile, logfile) # check image file and gain database are compatible if (status == 0): ngains = len(dbgain) if (int(max(dbamp)) != amplifiers): message = '\nERROR -- SALTGSLOT: ' + infile + ' contains ' + str( amplifiers) + ' amplifiers' message += ', the gaindb file ' + gaindb + ' contains ' + str( max(dbamp)) + ' amplifiers' status = saltprint.err(logfile, message) # check image file and cross talk database are compatible if (status == 0): if (len(xcoeff) - 1 != amplifiers): message = '\nERROR -- SALTSLOT: ' + infile + ' contains ' + str( amplifiers) + ' amplifiers' message += ', the cross talk file ' + xtalkfile + ' contains ' + str( len(xcoeff) - 1) + ' amplifiers' status = saltprint.err(logfile, message) # housekeeping keywords if (status == 0): status = saltkey.put('SAL-TLM', time.asctime(time.localtime()), struct[0], infile, logfile) status = saltkey.new(keyslot, time.asctime(time.localtime()), 'Data have been cleaned by SALTSLOT', struct[0], infile, logfile) # keywords for image extensions for i in range(nextend): hdu = i + 1 status = saltkey.new('EXTNAME', 'SCI', 'Extension name', struct[hdu], infile, logfile) status = saltkey.new('EXTVER', hdu, 'Extension number', struct[hdu], infile, logfile) # log coefficent table if (status == 0): message = '%30s %5s %4s %8s' % ('HDU', 'Gain', 'Bias', 'Xtalk') saltprint.log(logfile, '\n ---------------------------------------------', verbose) saltprint.log(logfile, message, verbose) saltprint.log(logfile, ' ---------------------------------------------', verbose) # loop over image extensions if (status == 0): for i in range(nextend / 2): hdu = i * 2 + 1 amplifier = hdu % amplifiers if (amplifier == 0): amplifier = amplifiers if (status == 0): value, status = saltkey.get('NAXIS1', struct[hdu], infile, logfile) naxis1 = int(value) if (status == 0): value, status = saltkey.get('NAXIS1', struct[hdu + 1], infile, logfile) naxis2 = int(value) if (status == 0 and hdu == 1): biassec, status = saltkey.get('BIASSEC', struct[hdu], infile, logfile) if (status == 0 and hdu == 1): ranges = biassec.lstrip('[').rstrip(']').split(',') x1_1 = int(ranges[0].split(':')[0]) - 1 x2_1 = int(ranges[0].split(':')[1]) - 1 y1_1 = int(ranges[1].split(':')[0]) - 1 y2_1 = int(ranges[1].split(':')[1]) - 1 if (status == 0 and hdu == 1): biassec, status = saltkey.get('BIASSEC', struct[hdu + 1], infile, logfile) if (status == 0 and hdu == 1): ranges = biassec.lstrip('[').rstrip(']').split(',') x1_2 = int(ranges[0].split(':')[0]) - 1 x2_2 = int(ranges[0].split(':')[1]) - 1 y1_2 = int(ranges[1].split(':')[0]) - 1 y2_2 = int(ranges[1].split(':')[1]) - 1 if (status == 0 and hdu == 1): datasec, status = saltkey.get('DATASEC', struct[hdu], infile, logfile) if (status == 0 and hdu == 1): ranges = datasec.lstrip('[').rstrip(']').split(',') dx1_1 = int(ranges[0].split(':')[0]) - 1 dx2_1 = int(ranges[0].split(':')[1]) dy1_1 = int(ranges[1].split(':')[0]) - 1 dy2_1 = int(ranges[1].split(':')[1]) if (status == 0 and hdu == 1): datasec, status = saltkey.get('DATASEC', struct[hdu + 1], infile, logfile) if (status == 0 and hdu == 1): ranges = datasec.lstrip('[').rstrip(']').split(',') dx1_2 = int(ranges[0].split(':')[0]) - 1 dx2_2 = int(ranges[0].split(':')[1]) dy1_2 = int(ranges[1].split(':')[0]) - 1 dy2_2 = int(ranges[1].split(':')[1]) if (status == 0 and dx2_1 - dx1_1 != dx2_2 - dx1_2): message = 'ERROR -- SALTSLOT: HDUs ' + infile message += '[' + str(hdu) + '] and ' + infile + '[' + str( hdu + 1) + ']' message += ' have different dimensions' status = saltprint.err(logfile, message) # read speed and gain of each exposure if (status == 0 and hdu == 1): gainset, status = saltkey.get('GAINSET', struct[0], infile, logfile) rospeed, status = saltkey.get('ROSPEED', struct[0], infile, logfile) if (rospeed == 'NONE'): saltprint.log(logfile, " ", verbose) message = "ERROR -- SALTSLOT: Readout speed is 'NONE' in " message += "primary keywords of " + infile status = saltprint.err(logfile, message) # read raw images if (status == 0): imagedata1, status = saltio.readimage(struct, hdu, logfile) imagedata2, status = saltio.readimage(struct, hdu + 1, logfile) # gain correction if (status == 0): for j in range(len(dbgain)): if (gainset == dbrate[j] and rospeed == dbspeed[j] and amplifier == int(dbamp[j])): try: gain1 = float(dbgain[j]) imagedata1 *= gain1 except: mesage = 'ERROR -- SALTSLOT: Cannot perform gain correction on image ' message += infile + '[' + str(hdu) + ']' status = saltprint.err(logfile, message) elif (gainset == dbrate[j] and rospeed == dbspeed[j] and amplifier + 1 == int(dbamp[j])): try: gain2 = float(dbgain[j]) imagedata2 *= gain2 except: mesage = 'ERROR -- SALTSLOT: Cannot perform gain correction on image ' message += infile + '[' + str(hdu + 1) + ']' status = saltprint.err(logfile, message) # crosstalk correction if (status == 0): revimage1 = imagedata1 * float(xcoeff[amplifier]) revimage2 = imagedata2 * float(xcoeff[amplifier + 1]) for j in range(dx2_1 - dx1_1 + 1): imagedata1[:, j] -= revimage2[:, dx2_2 - j - 1] imagedata2[:, j] -= revimage1[:, dx2_1 - j - 1] # bias subtraction if (status == 0): overx_val_1 = [] overx_val_2 = [] for x in range(x1_1, x2_1 + 1): list_1 = imagedata1[y1_1:y2_1, x] * 1.0 overx_val_1.append(saltstat.median(list_1, logfile)) overlevel_1 = saltstat.median(overx_val_1, logfile) for x in range(x1_2, x2_2 + 1): list_2 = imagedata2[y1_2:y2_2, x] * 1.0 overx_val_2.append(saltstat.median(list_2, logfile)) overlevel_2 = saltstat.median(overx_val_2, logfile) imagedata1 -= overlevel_1 imagedata2 -= overlevel_2 # trim overscan if (status == 0): imagedata1 = imagedata1[dy1_1:dy2_1, dx1_1:dx2_1] imagedata2 = imagedata2[dy1_2:dy2_2, dx1_2:dx2_2] datasec = '[1:' + str(dx2_1 - dx1_1) + ',1:' + str(dy2_1 - dy1_1) + ']' status = saltkey.put('DATASEC', datasec, struct[hdu], infile, logfile) status = saltkey.rem('BIASSEC', struct[hdu], infile, logfile) datasec = '[1:' + str(dx2_2 - dx1_2) + ',1:' + str(dy2_2 - dy1_2) + ']' status = saltkey.put('DATASEC', datasec, struct[hdu + 1], infile, logfile) status = saltkey.rem('BIASSEC', struct[hdu + 1], infile, logfile) # log coefficient table if (status == 0): infilename = infile.split('/') infilename = infilename[len(infilename) - 1] message = '%25s[%3d] %5.2f %4d %8.6f' % \ (infilename, hdu, gain1, overlevel_1, float(xcoeff[amplifier+1])) saltprint.log(logfile, message, verbose) message = '%25s[%3d] %5.2f %4d %8.6f' % \ (infilename, hdu+1, gain2, overlevel_2,float(xcoeff[amplifier])) saltprint.log(logfile, message, verbose) # update image in HDU structure if (status == 0): struct, status = saltio.writeimage(struct, hdu, imagedata1, logfile) struct, status = saltio.writeimage(struct, hdu + 1, imagedata2, logfile) return struct, status