Beispiel #1
0
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)
Beispiel #2
0
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
Beispiel #3
0
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)
Beispiel #4
0
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