예제 #1
0
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
예제 #2
0
파일: saltslot.py 프로젝트: dr-jpk/pysalt
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
예제 #3
0
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
예제 #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