Beispiel #1
0
def get_slits(slits):
    '''
    this function checks whether the detected slits for the left and right
    edges are the same length and also that the number of slits detected for
    each image section is the same. Additionally it checks whether there is
    an unexpecdedly large deviation in the slit curvature.
    '''

    num_sections = len(slits)

    # set up the calculation for the number of slits calculated
    # for each section
    section = [slits[i] for i in range(0, num_sections)]
    lengths = [[len(section[j][0]), len(section[j][1])]
               for j in range(0, len(section))]

    # first check and see if all the left and right edges are of equal length
    for k in range(0, len(lengths)):
        if lengths[k][0] != lengths[k][1]:
            msg = 'Number of edges for section %i does not match. Try changing your threshold value' % k
            raise SALTSpecError(msg)

    for m in range(0, len(lengths)):
        if lengths[m][0] == 0 or lengths[m][1] == 0:
            msg = 'No edges detected for section %i. Try changing your threshold value' % k
            raise SALTSpecError(msg)

    equal = []
    for i in range(0, len(lengths) - 1):
        if lengths[i][0] != lengths[i +
                                    1][0] or lengths[i][1] != lengths[i +
                                                                      1][1]:
            equal.append(False)
        else:
            equal.append(True)

    if (not all(equal)):
        msg = 'An unequal amount of slits were detected for one of the sections'
        raise SALTSpecError(msg)

    # write the slit positions into the defined slit positions format
    # such that each slit is given by:
    # [slitnumber, [bottom slit positions], [top slit positions]]
    allslits = []
    for j in range(0, len(slits[0][0][:])):
        spline_left = [slits[i][0][j] for i in range(0, len(slits))]
        spline_right = [slits[i][1][j] for i in range(0, len(slits))]
        allslits.append([j, spline_left, spline_right])

    return allslits
Beispiel #2
0
def specsky(images,
            outimages,
            outpref,
            method='normal',
            section=None,
            function='polynomial',
            order=2,
            clobber=True,
            logfile='salt.log',
            verbose=True):

    with logging(logfile, debug) as log:

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.listparse('Outfile', outimages, outpref, infiles, '')

        if method not in ['normal', 'fit']:
            msg = '%s mode is not supported yet' % method
            raise SALTSpecError(msg)

        if section is None:
            section = saltio.getSection(section)
            msg = 'This mode is not supported yet'
            raise SALTSpecError(msg)
        else:
            section = saltio.getSection(section)

        # Identify the lines in each file
        for img, ofile in zip(infiles, outfiles):
            log.message('Subtracting sky spectrum in image %s into %s' %
                        (img, ofile))
            # open the images
            hdu = saltio.openfits(img)

            # sky subtract the array
            hdu = skysubtract(hdu,
                              method=method,
                              section=section,
                              funct=function,
                              order=order)

            # write out the image
            if clobber and os.path.isfile(ofile):
                saltio.delete(ofile)
            hdu.writeto(ofile)
Beispiel #3
0
def which_ext(hdu, ext_name, debug):
    '''
    this function determines which extension in the fits file is the primary, sci
    and binary table. an integer is retunred with the position of the ext in
    the fits file.
    * hdu is an opened fits file. opened with pyfits.open
    * ext_name is the name of the wanted extension
    '''
    if debug:
        print 'determining the fits extension for %s' % ext_name

    if ext_name == 'PRIMARY':
        for i in range(0, len(hdu)):
            if hdu[i].name == 'PRIMARY':
                pos = i
                return pos

    elif ext_name == 'SCI':
        for i in range(0, len(hdu)):
            if hdu[i].name == 'SCI':
                pos = i
                return pos

    elif ext_name == 'BINTABLE':
        for i in range(0, len(hdu)):
            if hdu[i].name == 'BINTABLE':
                pos = i
                return pos

    else:
        msg = 'the hdu was not found in the fits header'
        raise SALTSpecError(msg)
Beispiel #4
0
def findsol(xarr, soldict, y_i, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername,
            slit, xbin, ybin, slitid, function, order):
    """Find the wavelength solution.  Either from a database containing all the
       solutions adn calculate the best one or calculate based on the model
       for RSS
    """

    if caltype == 'line':
        function, order, coef, domain = findlinesol(
            soldict, y_i, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername, slitid, xarr)
        if function is None:
            msg = 'No solution matches for %s, %s, %s, %s, %s, %s' % (
                instrume, grating, grang, arang, filtername, slitid)
            raise SALTSpecError(msg)
        if coef is None:
            return None
        order = int(order)
        ws = WavelengthSolution.WavelengthSolution(
            xarr,
            xarr,
            function=function,
            order=order) 
        ws.func.func.domain = domain
        ws.set_coef(coef)
        w_arr = ws.value(xarr)

    elif caltype == 'rss':
        w_arr = calcsol(
            xarr,
            y_i,
            instrume,
            grating,
            grang,
            arang,
            filtername,
            slit,
            xbin,
            ybin,
            function,
            order)
    else:
        message = 'SALTRECTIFY--Invalid caltype'
        raise SALTSpecError(message)

    return w_arr
Beispiel #5
0
def specextract(images,
                outfile,
                method='normal',
                section=None,
                thresh=3.0,
                minsize=3.0,
                outformat='ascii',
                ext=1,
                convert=True,
                clobber=True,
                logfile='salt.log',
                verbose=True):

    with logging(logfile, debug) as log:

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.argunpack('outfile', outfile)

        if method is 'weighted':
            msg = 'This mode is not supported yet'
            raise SALTSpecError(msg)

        section = saltio.checkfornone(section)
        if section is not None:
            sections = saltio.getSection(section, iraf_format=False)
            section = []
            for i in range(0, len(sections), 2):
                section.append((sections[i], sections[i + 1]))

        # Identify the lines in each file
        for img, ofile in zip(infiles, outfiles):
            log.message('\nExtracting spectrum in image %s to %s' %
                        (img, ofile),
                        with_header=False,
                        with_stdout=verbose)

            # open the images
            hdu = saltio.openfits(img)
            ap_list = extract(hdu,
                              ext=ext,
                              method=method,
                              section=section,
                              minsize=minsize,
                              thresh=thresh,
                              convert=convert)

            # write the spectra out
            if ap_list:
                write_extract(ofile.strip(),
                              ap_list,
                              outformat=outformat,
                              clobber=clobber)

        log.message('', with_header=False, with_stdout=verbose)
Beispiel #6
0
def speccal(specfile, outfile, calfile, extfile, airmass=None, exptime=None,
            clobber=True, logfile='salt.log', verbose=True):

    with logging(logfile, debug) as log:

        # read in the specfile and create a spectrum object
        obs_spectra = st.readspectrum(specfile, error=True, ftype='ascii')

        # read in the std file and convert from magnitudes to fnu
        # then convert it to fwave (ergs/s/cm2/A)
        cal_spectra = st.readspectrum(calfile, error=False, ftype='ascii')

        # read in the extinction file (leave in magnitudes)
        ext_spectra = st.readspectrum(extfile, error=False, ftype='ascii')

        # determine the airmass if not specified
        if saltio.checkfornone(airmass) is None:
            message = 'Airmass was not supplied'
            raise SALTSpecError(message)

        # determine the exptime if not specified
        if saltio.checkfornone(airmass) is None:
            message = 'Exposure Time was not supplied'
            raise SALTSpecError(message)

        # calculate the calibrated spectra
        log.message('Calculating the calibration curve for %s' % specfile)
        error = False
        try:
            if obs_spectra.var is not None:
                error = True
        except:
            error = False
        flux_spectra = calfunc(
            obs_spectra,
            cal_spectra,
            ext_spectra,
            airmass,
            exptime,
            error)

        # write the spectra out
        st.writespectrum(flux_spectra, outfile, ftype='ascii', error=error)
Beispiel #7
0
def createoutputxaxis(wstart, wend, nw):
    """Create the output array for the axis for the data to be transformed onto.
    """

    try:
        warr = np.linspace(wstart, wend, num=nw)
    except Exception as e:
        msg = 'No output array was create because %s' % e
        raise SALTSpecError(msg)
    return warr
Beispiel #8
0
def write_extract(ofile, ap_list, outformat='ascii', fvar=None, clobber=False):
    """Write out to either a txt file or fits file depending on the extension
       of ofile

    """
    if outformat == 'FITS':
        write_extract_fits(ofile, ap_list, clobber)
    elif outformat == 'ascii':
        write_extract_text(ofile, ap_list, clobber)
    else:
        msg = '%s is not a supported output format' % outformat
        raise SALTSpecError(msg)
    return
Beispiel #9
0
def createbadpixel(inhdu, bphdu, sci_ext, bp_ext):
    """Create the bad pixel hdu from a bad pixel hdu"""
    if bphdu is None:
        data = inhdu[sci_ext].data * 0.0
    else:
        infile = inhdu._HDUList__file.name
        bpfile = bphdu._HDUList__file.name
        for k in ['INSTRUME', 'CCDSUM', 'NAXIS1', 'NAXIS2']:
            if not saltkey.compare(
                    inhdu[sci_ext], bphdu[sci_ext], k, infile, bpfile):
                message = '%s and %s are not the same %s' % (infile, bpfile, k)
                raise SALTSpecError(message)
        data = bphdu[sci_ext].data.copy()

    header = inhdu[sci_ext].header.copy()
    header['EXTVER'] = bp_ext
    header.update('SCIEXT', sci_ext, comment='Extension of science frame')
    return pyfits.ImageHDU(data=data, header=header, name='BPM')
Beispiel #10
0
def read_slits_from_ds9(simg, order=1):
    '''
    This function reads the input from an outputslitfile if it specified as a
    ds9 region file. It will read the slit positions return an array that resembles
    the split_pos array that is passed to the extract_slits function and the
    order of the spline to be fitted.
    '''

    # read in the slit file
    slitfile = open(simg, 'r')
    slits = slitfile.read()
    slitfile.close()

    # throw an error if the positions aren't in image format
    if slits.count('image') == 0:
        msg = "Please use 'image' for format when saving ds9 region file"
        raise SALTSpecError(msg)
    slits = slits.split('\n')

    # loop through and create all slits
    allslits = []
    alltext = []
    i = 0
    for line in slits:
        if line.startswith('#') or line.startswith('global'):
            pass
        elif line.count('box'):
            line = line.split('#')
            if len(line) == 2:
                rtext = line[1].replace(' text={', '')
                rtext = rtext.replace('}', '')
                alltext.append(rtext.split(','))
            line = line[0].replace('box(', '')
            line = line.replace(')', '')
            col = line.split(',')
            slitnum = i
            left_edge = [int(float(col[1]) - 0.5 * float(col[3]))]
            right_edge = [int(float(col[1]) + 0.5 * float(col[3]))]
            allslits.append([slitnum, left_edge, right_edge])
            i += 1

    return order, allslits, alltext
Beispiel #11
0
def specprepare(images, outimages, outpref, badpixelimage='',
                clobber=True, logfile='salt.log', verbose=True):

    with logging(logfile, debug) as log:

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.listparse('Outfile', outimages, outpref, infiles, '')

        # verify that the input and output lists are the same length
        saltio.comparelists(infiles, outfiles, 'Input', 'output')

        # open the badpixel image
        if saltio.checkfornone(badpixelimage) is None:
            badpixelstruct = None
        else:
            try:
                badpixelstruct = saltio.openfits(badpixelimage)
            except saltio.SaltIOError as e:
                msg = 'badpixel image must be specificied\n %s' % e
                raise SALTSpecError(msg)

        # open each raw image file

        for img, oimg, in zip(infiles, outfiles):

            # open the fits file
            struct = saltio.openfits(img)

            # prepare file
            struct = prepare(struct, badpixelstruct)

            # write FITS file
            saltio.writefits(struct, oimg, clobber=clobber)
            saltio.closefits(struct)

            message = 'SPECPREPARE -- %s => %s' % (img, oimg)
            log.message(message)
def specarcstraighten(images, outfile, function='poly', order=3, rstep=1,
                      rstart='middlerow', nrows=1, 
                      y1=None, y2=None, sigma=5, sections=3, niter=5,
                      startext=0, clobber=False, logfile='salt.log', verbose=True):

    with logging(logfile, debug) as log:

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.argunpack('Output', outfile)

        # Identify the lines in each file
        for img, ofile in zip(infiles, outfiles):

            # open the image
            hdu = saltio.openfits(img)

            # get the basic information about the spectrograph
            dateobs = saltkey.get('DATE-OBS', hdu[0])
            try:
                utctime = saltkey.get('UTC-OBS', hdu[0])
            except SaltError:
                utctime = saltkey.get('TIME-OBS', hdu[0])

            instrume = saltkey.get('INSTRUME', hdu[0]).strip()
            grating = saltkey.get('GRATING', hdu[0]).strip()
            grang = saltkey.get('GR-ANGLE', hdu[0])
            grasteps = saltkey.get('GRTILT', hdu[0])
            arang = saltkey.get('AR-ANGLE', hdu[0])
            arsteps = saltkey.get('CAMANG', hdu[0])
            rssfilter = saltkey.get('FILTER', hdu[0])
            specmode = saltkey.get('OBSMODE', hdu[0])
            masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper()
            slitname = saltkey.get('MASKID', hdu[0])
            xbin, ybin = saltkey.ccdbin(hdu[0], img)

            for i in range(startext, len(hdu)):
                if hdu[i].name == 'SCI':
                    log.message('Proccessing extension %i in  %s' % (i, img))
                    # things that will change for each slit

                    if masktype == 'LONGSLIT':
                        slit = st.getslitsize(slitname)
                        objid = None
                    #elif masktype == 'MOS':
                        #slit = 1.5
                        # slit=saltkey.get('SLIT', hdu[i])

                        # set up the x and y positions
                        #miny = hdu[i].header['MINY']
                        #maxy = hdu[i].header['MAXY']
                        #ras = hdu[i].header['SLIT_RA']
                        #des = hdu[i].header['SLIT_DEC']
                        #objid = hdu[i].header['SLITNAME']

                        # Check the perfomance of masks at different PA
                        #rac = hdu[0].header['MASK_RA']
                        #dec = hdu[0].header['MASK_DEC']
                        #pac = hdu[0].header['PA']

                    else:
                        msg = '%s is not a currently supported masktype' % masktype
                        raise SALTSpecError(msg)

                    if instrume not in ['PFIS', 'RSS']:
                        msg = '%s is not a currently supported instrument' % instrume
                        raise SALTSpecError(msg)

                    # set up the data for the source
                    try:
                        data = hdu[i].data
                    except Exception as e:
                        message = 'Unable to read in data array in %s because %s' % (
                            img, e)
                        raise SALTSpecError(message)

                    # set up the center row
                    if rstart == 'middlerow':
                        ystart = int(0.5 * len(data))
                    else:
                        ystart = rstart


                    # set up the xarr array based on the image
                    xarr = np.arange(len(data[ystart]), dtype='int64')

                    # calculate the transformation
                    ImageSolution = arcstraight(data, xarr, ystart, function=function, order=order, 
                                                rstep=rstep, y1=y1, y2=y2, sigma=sigma, sections=sections,
                                                niter=niter, log=log, verbose=verbose)

                    if outfile and len(ImageSolution):
                        writeIS(ImageSolution, outfile, dateobs=dateobs, utctime=utctime, instrume=instrume,
                                grating=grating, grang=grang, grasteps=grasteps, arsteps=arsteps,
                                arang=arang, rfilter=rssfilter, slit=slit, xbin=xbin,
                                ybin=ybin, objid=objid,
                                filename=img, log=log, verbose=verbose)
Beispiel #13
0
def extract(hdu,
            ext=1,
            method='normal',
            section=[],
            minsize=3.0,
            thresh=3.0,
            convert=True):
    """For a given image, extract a 1D spectra from the image
       and write the spectra to the output file

    """

    ap_list = []
    i = ext
    if hdu[i].name == 'SCI':
        # set up the data, variance, and bad pixel frames
        # first step is to find the region to extract
        data_arr = hdu[i].data
        try:
            var_arr = hdu[hdu[i].header['VAREXT']].data
        except:
            var_arr = None
        try:
            bpm_arr = hdu[hdu[i].header['BPMEXT']].data
        except:
            bpm_arr = None
        var_arr = None
        bpm_arr = None

        xarr = np.arange(len(data_arr[0]))

        # convert using the WCS information
        try:
            w0 = saltkey.get('CRVAL1', hdu[i])
            dw = saltkey.get('CD1_1', hdu[i])
        except Exception as e:
            msg = 'Error on Ext %i: %s' % (i, e)
            raise SALTSpecError(msg)
        warr = w0 + dw * xarr

        # convert from air to vacuum
        if convert:
            warr = Spectrum.air2vac(warr)

        # set up the sections in case of findobj
        if section is None:
            section = findobj.findObjects(data_arr,
                                          method='median',
                                          specaxis=1,
                                          minsize=minsize,
                                          thresh=thresh,
                                          niter=5)

        # extract all of the  regions
        for sec in section:
            ap = apext.apext(warr, data_arr, ivar=var_arr)
            y1, y2 = sec
            ap.flatten(y1, y2)
            ap_list.append(ap)

    return ap_list
Beispiel #14
0
def wavemap(hdu,
            soldict,
            caltype='line',
            function='poly',
            order=3,
            blank=0,
            nearest=False,
            array_only=False,
            clobber=True,
            log=None,
            verbose=True):
    """Read in an image and a set of wavlength solutions.  Calculate the best
       wavelength solution for a given dataset and then apply that data set to the
       image

     return
    """

    # set up the time of the observation
    dateobs = saltkey.get('DATE-OBS', hdu[0])
    utctime = saltkey.get('TIME-OBS', hdu[0])
    exptime = saltkey.get('EXPTIME', hdu[0])
    instrume = saltkey.get('INSTRUME', hdu[0]).strip()
    grating = saltkey.get('GRATING', hdu[0]).strip()
    if caltype == 'line':
        grang = saltkey.get('GRTILT', hdu[0])
        arang = saltkey.get('CAMANG', hdu[0])
    else:
        grang = saltkey.get('GR-ANGLE', hdu[0])
        arang = saltkey.get('AR-ANGLE', hdu[0])
    filtername = saltkey.get('FILTER', hdu[0]).strip()
    slitname = saltkey.get('MASKID', hdu[0])
    slit = st.getslitsize(slitname)
    xbin, ybin = saltkey.ccdbin(hdu[0])

    timeobs = sr.enterdatetime('%s %s' % (dateobs, utctime))

    # check to see if there is more than one solution
    if caltype == 'line':
        if len(soldict) == 1:
            sol = soldict.keys()[0]
            slitid = None
            if not sr.matchobservations(soldict[sol], instrume, grating, grang,
                                        arang, filtername, slitid):
                msg = 'Observations do not match setup for transformation but using the solution anyway'
                if log:
                    log.warning(msg)

    for i in range(1, len(hdu)):
        if hdu[i].name == 'SCI':
            if log:
                log.message('Correcting extension %i' % i)
            istart = int(0.5 * len(hdu[i].data))

            # open up the data
            # set up the xarr and initial wavlength solution
            xarr = np.arange(len(hdu[i].data[istart]), dtype='int64')

            # get the slitid
            try:
                slitid = saltkey.get('SLITNAME', hdu[i])
            except:
                slitid = None

            #check to see if wavext is already there and if so, then check update
            #that for the transformation from xshift to wavelength
            if saltkey.found('WAVEXT', hdu[i]):
                w_ext = saltkey.get('WAVEXT', hdu[i]) - 1
                wavemap = hdu[w_ext].data
                function, order, coef = sr.findlinesol(
                    soldict, istart, nearest, timeobs, exptime, instrume,
                    grating, grang, arang, filtername, slitid, xarr)
                ws = WavelengthSolution.WavelengthSolution(xarr,
                                                           xarr,
                                                           function=function,
                                                           order=order)
                ws.set_coef(coef)
                for j in range(len(hdu[i].data)):
                    wavemap[j, :] = ws.value(wavemap[j, :])
                if array_only: return wavemap
                hdu[w_ext].data = wavemap
                continue

            # set up a wavelength solution -- still in here for testing MOS data
            try:
                w_arr = sr.findsol(xarr, soldict, istart, caltype, nearest,
                                   timeobs, exptime, instrume, grating, grang,
                                   arang, filtername, slit, xbin, ybin, slitid,
                                   function, order)
            except SALTSpecError as e:
                if slitid:
                    msg = 'SLITID %s: %s' % (slitid, e)
                    if log:
                        log.warning(msg)
                    continue
                else:
                    raise SALTSpecError(e)

            if w_arr is None:
                w_arr = sr.findsol(xarr, soldict, istart, 'rss', nearest,
                                   timeobs, exptime, instrume, grating, grang,
                                   arang, filtername, slit, xbin, ybin, slitid,
                                   function, order)

            # for each line in the data, determine the wavelength solution
            # for a given line in the image
            wavemap = np.zeros_like(hdu[i].data)
            for j in range(len(hdu[i].data)):
                # find the wavelength solution for the data
                w_arr = sr.findsol(xarr, soldict, j, caltype, nearest, timeobs,
                                   exptime, instrume, grating, grang, arang,
                                   filtername, slit, xbin, ybin, slitid,
                                   function, order)
                if w_arr is not None: wavemap[j, :] = w_arr
            if array_only: return wavemap

            # write out the oimg
            hduwav = fits.ImageHDU(data=wavemap,
                                   header=hdu[i].header,
                                   name='WAV')
            hdu.append(hduwav)
            saltkey.new('WAVEXT',
                        len(hdu) - 1, 'Extension for Wavelength Map', hdu[i])

    return hdu
Beispiel #15
0
def rectify(hdu, soldict, caltype='line', function='poly', order=3, inttype='interp',
            w1=None, w2=None, dw=None, nw=None, blank=0, pixscale=0.0, time_interp=False,
            conserve=False, nearest=False, clobber=True, log=None, verbose=True):
    """Read in an image and a set of wavlength solutions.  Calculate the best
       wavelength solution for a given dataset and then apply that data set to the
       image

     return
    """

    # set the basic values
    set_w1 = (w1 is None)
    set_w2 = (w2 is None)
    set_dw = (dw is None)
    set_nw = (nw is None)

    # set up the time of the observation
    dateobs = saltkey.get('DATE-OBS', hdu[0])
    utctime = saltkey.get('TIME-OBS', hdu[0])
    exptime = saltkey.get('EXPTIME', hdu[0])
    instrume = saltkey.get('INSTRUME', hdu[0]).strip()
    grating = saltkey.get('GRATING', hdu[0]).strip()
    if caltype == 'line':
        grang = saltkey.get('GRTILT', hdu[0])
        arang = saltkey.get('CAMANG', hdu[0])
    else:
        grang = saltkey.get('GR-ANGLE', hdu[0])
        arang = saltkey.get('AR-ANGLE', hdu[0])
    filtername = saltkey.get('FILTER', hdu[0]).strip()
    slitname = saltkey.get('MASKID', hdu[0])
    slit = st.getslitsize(slitname)
    xbin, ybin = saltkey.ccdbin(hdu[0])

    timeobs = enterdatetime('%s %s' % (dateobs, utctime))

    # check to see if there is more than one solution
    if caltype == 'line':
        if len(soldict) == 1:
            sol = soldict.keys()[0]
            slitid = None
            if not matchobservations(
                    soldict[sol], instrume, grating, grang, arang, filtername, slitid):
                msg = 'Observations do not match setup for transformation but using the solution anyway'
                if log:
                    log.warning(msg)

    for i in range(1, len(hdu)):
        if hdu[i].name == 'SCI':
            if log:
                log.message('Correcting extension %i' % i)
            istart = int(0.5 * len(hdu[i].data))
            # open up the data
            # set up the xarr and initial wavlength solution
            xarr = np.arange(len(hdu[i].data[istart]), dtype='int64')

            # get the slitid
            try:
                slitid = saltkey.get('SLITNAME', hdu[i])
            except:
                slitid = None
            # set up a wavelength solution
            try:
                w_arr = findsol(xarr, soldict, istart, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername,
                                slit, xbin, ybin, slitid, function, order)
            except SALTSpecError as e:
                if slitid:
                    msg = 'SLITID %s: %s' % (slitid, e)
                    if log:
                        log.warning(msg)
                    continue
                else:
                    raise SALTSpecError(e)

            if w_arr is None:
                w_arr = findsol(xarr, soldict, istart, 'rss', nearest, timeobs, exptime, instrume, grating, grang, arang, filtername,
                                slit, xbin, ybin, slitid, function, order)

            # set up the output x-axis

            if set_w1:
                w1 = w_arr.min()
            if set_w2:
                w2 = w_arr.max()
            if set_nw:
                nw = len(xarr)
            if set_dw:
                dw = float(w2 - w1) / nw
            nw_arr = createoutputxaxis(w1, w2, nw)

            # setup the VARIANCE and BPM frames
            if saltkey.found('VAREXT', hdu[i]):
                varext = saltkey.get('VAREXT', hdu[i])
            else:
                varext = None

            # setup the BPM frames
            if saltkey.found('BPMEXT', hdu[i]):
                bpmext = saltkey.get('BPMEXT', hdu[i])
            else:
                bpmext = None

            # for each line in the data, determine the wavelength solution
            # for a given line in the image
            for j in range(len(hdu[i].data)):
                # find the wavelength solution for the data
                w_arr = findsol(xarr, soldict, j, caltype, nearest, timeobs, exptime, instrume, grating, grang, arang, filtername,
                                slit, xbin, ybin, slitid, function, order)

                # apply that wavelength solution to the data
                if w_arr is not None:
                    try:
                        hdu[i].data[
                            j,
                            :] = st.interpolate(
                            nw_arr,
                            w_arr,
                            hdu[i].data[
                                j,
                                :],
                            inttype,
                            left=blank,
                            right=blank)
                    except Exception as e:
                        hdu[i].data[j, :] = hdu[i].data[j, :] * 0.0 + blank
                        msg = 'In row %i, solution cannot be found due to %s' % (
                            i, e)

                    # correct the variance frame
                    if varext:
                        try:
                            hdu[varext].data[
                                j,
                                :] = st.interpolate(
                                nw_arr,
                                w_arr,
                                hdu[varext].data[
                                    j,
                                    :],
                                inttype,
                                left=blank,
                                right=blank)
                        except Exception as e:
                            msg = 'In row %i, solution cannot be found due to %s' % (
                                i, e)

                    # correct the BPM frame
                    if bpmext:
                        try:
                            hdu[bpmext].data[
                                j,
                                :] = st.interpolate(
                                nw_arr,
                                w_arr,
                                hdu[bpmext].data[
                                    j,
                                    :],
                                inttype,
                                left=blank,
                                right=blank)
                        except Exception as e:
                            msg = 'In row %i, solution cannot be found due to %s' % (
                                i, e)
                else:
                    hdu[i].data[j, :] = hdu[i].data[j, :] * 0.0 + blank

            if conserve:
                hdu[i].data = hdu[i].data / dw
                if varext:
                    hdu[varext].data = hdu[varext].data / dw

            # Add WCS information
            saltkey.new('CTYPE1', 'LAMBDA', 'Coordinate Type', hdu[i])
            saltkey.new('CTYPE2', 'PIXEL', 'Coordinate Type', hdu[i])
            saltkey.new(
                'CD1_1',
                dw,
                'WCS: Wavelength Dispersion in angstrom/pixel',
                hdu[i])
            saltkey.new('CD2_1', 0.0, 'WCS: ', hdu[i])
            saltkey.new('CD1_2', 0.0, 'WCS: ', hdu[i])
            saltkey.new('CD2_2', ybin * pixscale, 'WCS: ', hdu[i])
            saltkey.new('CRPIX1', 0.0, 'WCS: X Reference pixel', hdu[i])
            saltkey.new('CRPIX2', 0.0, 'WCS: Y Reference pixel', hdu[i])
            saltkey.new('CRVAL1', w1, 'WCS: X Reference pixel', hdu[i])
            saltkey.new('CRVAL2', 0.0, 'WCS: Y Reference pixel', hdu[i])
            saltkey.new('CDELT1', 1.0, 'WCS: X pixel size', hdu[i])
            saltkey.new('CDELT2', 1.0, 'WCS: Y pixel size', hdu[i])
            saltkey.new('DC-FLAG', 0, 'Dispesion Corrected image', hdu[i])

    return hdu
Beispiel #16
0
def specsens(specfile,
             outfile,
             stdfile,
             extfile,
             airmass=None,
             exptime=None,
             stdzp=3.68e-20,
             function='polynomial',
             order=3,
             thresh=3,
             niter=5,
             fitter='gaussian',
             clobber=True,
             logfile='salt.log',
             verbose=True):

    with logging(logfile, debug) as log:

        # read in the specfile and create a spectrum object
        obs_spectra = st.readspectrum(specfile.strip(),
                                      error=True,
                                      ftype='ascii')

        # smooth the observed spectrum
        # read in the std file and convert from magnitudes to fnu
        # then convert it to fwave (ergs/s/cm2/A)
        std_spectra = st.readspectrum(stdfile.strip(),
                                      error=False,
                                      ftype='ascii')
        std_spectra.flux = Spectrum.magtoflux(std_spectra.flux, stdzp)
        std_spectra.flux = Spectrum.fnutofwave(std_spectra.wavelength,
                                               std_spectra.flux)

        # Get the typical bandpass of the standard star,
        std_bandpass = np.diff(std_spectra.wavelength).mean()
        # Smooth the observed spectrum to that bandpass
        obs_spectra.flux = st.boxcar_smooth(obs_spectra, std_bandpass)
        # read in the extinction file (leave in magnitudes)
        ext_spectra = st.readspectrum(extfile.strip(),
                                      error=False,
                                      ftype='ascii')

        # determine the airmass if not specified
        if saltio.checkfornone(airmass) is None:
            message = 'Airmass was not supplied'
            raise SALTSpecError(message)

        # determine the exptime if not specified
        if saltio.checkfornone(exptime) is None:
            message = 'Exposure Time was not supplied'
            raise SALTSpecError(message)

        # calculate the calibrated spectra
        log.message('Calculating the calibration curve for %s' % specfile)
        cal_spectra = sensfunc(obs_spectra, std_spectra, ext_spectra, airmass,
                               exptime)

        # plot(cal_spectra.wavelength, cal_spectra.flux * std_spectra.flux)
        # fit the spectra--first take a first cut of the spectra
        # using the median absolute deviation to throw away bad points
        cmed = np.median(cal_spectra.flux)
        cmad = saltstat.mad(cal_spectra.flux)
        mask = (abs(cal_spectra.flux - cmed) < thresh * cmad)
        mask = np.logical_and(mask, (cal_spectra.flux > 0))

        # now fit the data
        # Fit using a gaussian process.
        if fitter == 'gaussian':
            from sklearn.gaussian_process import GaussianProcess
            #Instanciate a Gaussian Process model

            dy = obs_spectra.var[mask]**0.5
            dy /= obs_spectra.flux[mask] / cal_spectra.flux[mask]
            y = cal_spectra.flux[mask]
            gp = GaussianProcess(corr='squared_exponential',
                                 theta0=1e-2,
                                 thetaL=1e-4,
                                 thetaU=0.1,
                                 nugget=(dy / y)**2.0)
            X = np.atleast_2d(cal_spectra.wavelength[mask]).T
            # Fit to data using Maximum Likelihood Estimation of the parameters
            gp.fit(X, y)

            x = np.atleast_2d(cal_spectra.wavelength).T
            # Make the prediction on the meshed x-axis (ask for MSE as well)
            y_pred = gp.predict(x)

            cal_spectra.flux = y_pred

        else:
            fit = interfit(cal_spectra.wavelength[mask],
                           cal_spectra.flux[mask],
                           function=function,
                           order=order,
                           thresh=thresh,
                           niter=niter)
            fit.interfit()
            cal_spectra.flux = fit(cal_spectra.wavelength)

        # write the spectra out
        st.writespectrum(cal_spectra, outfile, ftype='ascii')
def specslitnormalize(images,
                      outimages,
                      outpref,
                      response=None,
                      response_output=None,
                      order=2,
                      conv=1e-2,
                      niter=20,
                      startext=0,
                      clobber=False,
                      logfile='salt.log',
                      verbose=True):

    with logging(logfile, debug) as log:

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.listparse('Outfile', outimages, outpref, infiles, '')

        # read in the response function
        response = saltio.checkfornone(response)
        if response:
            log.message('Loading response from %s' % response)
            response = readresponse(response)

        # Identify the lines in each file
        for img, ofile in zip(infiles, outfiles):

            # open the image
            hdu = saltio.openfits(img)

            for i in range(startext, len(hdu)):
                if hdu[i].name == 'SCI':
                    log.message('Normalizing extension %i in  %s' % (i, img))
                    # things that will change for each slit

                    # set up the data for the source
                    try:
                        data = hdu[i].data
                    except Exception as e:
                        message = \
                            'Unable to read in data array in %s because %s' % \
                            (img, e)
                        raise SALTSpecError(message)

                    if response is None:
                        response = create_response(data,
                                                   spatial_axis=1,
                                                   order=order,
                                                   conv=conv,
                                                   niter=niter)
                        if response_output:
                            write_response(response, clobber=clobber)
                    else:
                        # add a check that the response is the same shape as
                        # the data
                        if len(response) != data.shape[0]:
                            raise SALTSpecError(
                                'Length of response function does not equal size of image array'
                            )

                    # correct the data
                    data = data / response

                    # correct the variance frame
                    if saltkey.found('VAREXT', hdu[i]):
                        vhdu = saltkey.get('VAREXT', hdu[i])
                        hdu[vhdu].data = hdu[vhdu].data / response

                saltio.writefits(hdu, ofile, clobber=clobber)
Beispiel #18
0
def specidentify(images,
                 linelist,
                 outfile,
                 guesstype='rss',
                 guessfile='',
                 automethod='Matchlines',
                 function='poly',
                 order=3,
                 rstep=100,
                 rstart='middlerow',
                 mdiff=5,
                 thresh=3,
                 niter=5,
                 smooth=0,
                 subback=0,
                 inter=True,
                 startext=0,
                 clobber=False,
                 textcolor='black',
                 preprocess=False,
                 logfile='salt.log',
                 verbose=True):

    with logging(logfile, debug) as log:

        # set up the variables
        infiles = []
        outfiles = []

        # Check the input images
        infiles = saltio.argunpack('Input', images)

        # create list of output files
        outfiles = saltio.argunpack('Output', outfile)

        # open the line lists
        slines, sfluxes = st.readlinelist(linelist)

        # Identify the lines in each file
        for img, ofile in zip(infiles, outfiles):

            # open the image
            hdu = saltio.openfits(img)

            # get the basic information about the spectrograph
            dateobs = saltkey.get('DATE-OBS', hdu[0])
            try:
                utctime = saltkey.get('UTC-OBS', hdu[0])
            except SaltError:
                utctime = saltkey.get('TIME-OBS', hdu[0])

            instrume = saltkey.get('INSTRUME', hdu[0]).strip()
            grating = saltkey.get('GRATING', hdu[0]).strip()
            grang = saltkey.get('GR-ANGLE', hdu[0])
            grasteps = saltkey.get('GRTILT', hdu[0])
            arang = saltkey.get('AR-ANGLE', hdu[0])
            arsteps = saltkey.get('CAMANG', hdu[0])
            rssfilter = saltkey.get('FILTER', hdu[0])
            specmode = saltkey.get('OBSMODE', hdu[0])
            masktype = saltkey.get('MASKTYP', hdu[0]).strip().upper()
            slitname = saltkey.get('MASKID', hdu[0])
            xbin, ybin = saltkey.ccdbin(hdu[0], img)

            for i in range(startext, len(hdu)):
                if hdu[i].name == 'SCI':
                    log.message('Proccessing extension %i in  %s' % (i, img))
                    # things that will change for each slit

                    if masktype == 'LONGSLIT':
                        slit = st.getslitsize(slitname)
                        xpos = -0.2666
                        ypos = 0.0117
                        objid = None
                    elif masktype == 'MOS':
                        slit = 1.
                        #slit=saltkey.get('SLIT', hdu[i])

                        # set up the x and y positions
                        miny = hdu[i].header['MINY']
                        maxy = hdu[i].header['MAXY']
                        ras = hdu[i].header['SLIT_RA']
                        des = hdu[i].header['SLIT_DEC']
                        objid = hdu[i].header['SLITNAME']

                        # TODO: Check the perfomance of masks at different PA
                        rac = hdu[0].header['MASK_RA']
                        dec = hdu[0].header['MASK_DEC']
                        pac = hdu[0].header['PA']

                        # these are hard wired at the moment
                        xpixscale = 0.1267 * xbin
                        ypixscale = 0.1267 * ybin
                        cx = int(3162 / xbin)
                        cy = int(2050 / ybin)

                        x, y = mt.convert_fromsky(ras,
                                                  des,
                                                  rac,
                                                  dec,
                                                  xpixscale=xpixscale,
                                                  ypixscale=ypixscale,
                                                  position_angle=-pac,
                                                  ccd_cx=cx,
                                                  ccd_cy=cy)
                        xpos = 0.015 * 2 * (cx - x[0])
                        ypos = 0.0117
                    else:
                        msg = '%s is not a currently supported masktype' % masktype
                        raise SALTSpecError(msg)

                    if instrume not in ['PFIS', 'RSS']:
                        msg = '%s is not a currently supported instrument' % instrume
                        raise SALTSpecError(msg)

                    # create RSS Model
                    rss = RSSModel.RSSModel(grating_name=grating.strip(),
                                            gratang=grang,
                                            camang=arang,
                                            slit=slit,
                                            xbin=xbin,
                                            ybin=ybin,
                                            xpos=xpos,
                                            ypos=ypos)
                    res = 1e7 * rss.calc_resolelement(rss.alpha(), -rss.beta())
                    dres = res / 10.0
                    wcen = 1e7 * rss.calc_centralwavelength()
                    R = rss.calc_resolution(wcen / 1e7, rss.alpha(),
                                            -rss.beta())
                    logmsg = '\nGrating\tGR-ANGLE\tAR-ANGLE\tSlit\tWCEN\tR\n'
                    logmsg += '%s\t%8.3f\t%8.3f\t%4.2f\t%6.2f\t%4f\n' % (
                        grating, grang, arang, slit, wcen, R)
                    if log:
                        log.message(logmsg, with_header=False)

                    # set up the data for the source
                    try:
                        data = hdu[i].data
                    except Exception, e:
                        message = 'Unable to read in data array in %s because %s' % (
                            img, e)
                        raise SALTSpecError(message)

                    # set up the center row
                    if rstart == 'middlerow':
                        ystart = int(0.5 * len(data))
                    else:
                        ystart = int(rstart)

                    rss.gamma = 0.0
                    if masktype == 'MOS':
                        rss.gamma = 180.0 / math.pi * math.atan(
                            (y * rss.detector.pix_size * rss.detector.ybin -
                             0.5 * rss.detector.find_height()) /
                            rss.camera.focallength)

                    # set up the xarr array based on the image
                    xarr = np.arange(len(data[ystart]), dtype='int64')

                    # get the guess for the wavelength solution
                    if guesstype == 'rss':
                        # set up the rss model
                        ws = st.useRSSModel(xarr,
                                            rss,
                                            function=function,
                                            order=order,
                                            gamma=rss.gamma)
                        if function in ['legendre', 'chebyshev']:
                            ws.func.func.domain = [xarr.min(), xarr.max()]
                    elif guesstype == 'file':
                        soldict = {}
                        soldict = readsolascii(guessfile, soldict)
                        timeobs = enterdatetime('%s %s' % (dateobs, utctime))
                        exptime = saltkey.get('EXPTIME', hdu[0])
                        filtername = saltkey.get('FILTER', hdu[0]).strip()
                        try:
                            slitid = saltkey.get('SLITNAME', hdu[i])
                        except:
                            slitid = None

                        function, order, coef, domain = findlinesol(soldict,
                                                                    ystart,
                                                                    True,
                                                                    timeobs,
                                                                    exptime,
                                                                    instrume,
                                                                    grating,
                                                                    grang,
                                                                    arang,
                                                                    filtername,
                                                                    slitid,
                                                                    xarr=xarr)
                        ws = WavelengthSolution.WavelengthSolution(
                            xarr, xarr, function=function, order=order)
                        ws.func.func.domain = domain
                        ws.set_coef(coef)
                    else:
                        raise SALTSpecError(
                            'This guesstype is not currently supported')

                    # identify the spectral lines
                    ImageSolution = identify(data,
                                             slines,
                                             sfluxes,
                                             xarr,
                                             ystart,
                                             ws=ws,
                                             function=function,
                                             order=order,
                                             rstep=rstep,
                                             mdiff=mdiff,
                                             thresh=thresh,
                                             niter=niter,
                                             method=automethod,
                                             res=res,
                                             dres=dres,
                                             smooth=smooth,
                                             inter=inter,
                                             filename=img,
                                             subback=0,
                                             textcolor=textcolor,
                                             preprocess=preprocess,
                                             log=log,
                                             verbose=verbose)

                    if outfile and len(ImageSolution):
                        writeIS(ImageSolution,
                                outfile,
                                dateobs=dateobs,
                                utctime=utctime,
                                instrume=instrume,
                                grating=grating,
                                grang=grang,
                                grasteps=grasteps,
                                arsteps=arsteps,
                                arang=arang,
                                rfilter=rssfilter,
                                slit=slit,
                                xbin=xbin,
                                ybin=ybin,
                                objid=objid,
                                filename=img,
                                log=log,
                                verbose=verbose)
Beispiel #19
0
def prepare(struct, badpixelstruct):
    """Prepare a structure for spectroscopic processing

    """

    # identify instrument
    infile = struct._HDUList__file.name

    nextend = len(struct)

    if badpixelstruct is not None:
        bpfile = badpixelstruct._HDUList__file.name
        # Check that the image is the same number of extensions as the
        # badpixelmap
        if len(struct) != len(badpixelstruct):
            message = '%s and %s are not the same length' % (infile, bpfile)
            raise SALTSpecError(message)

    # Add variance frames and bad pixel maps
    # If no variance frame exists, add the file at the end of the
    # extensions.  If a variance file does exist, do nothing
    # Add a keyword to the Science extension indication what
    # extension the variance from is on

    j = 0
    for i in range(nextend):
        if struct[i].size() > 0 and struct[i].name == 'SCI':
            # Check to see if the variance frame exists
            try:
                key = struct[i].header['VAREXT']
            except:
                try:
                    hdu = createvariance(struct[i], i, nextend + j)
                    struct[i].header.update(
                        'VAREXT',
                        nextend + j,
                        comment='Extension for Variance Frame')
                    struct.append(hdu)
                    j = j + 1
                except Exception as e:
                    message = 'Could not create variance extension in ext %i of %s because %s' \
                        % (i, infile, e)
                    raise SALTSpecError(message)

            # Check to see if the BPM  frame exists
            try:
                key = struct[1].header['BPMEXT']
            except:
                try:
                    hdu = createbadpixel(
                        struct,
                        badpixelstruct,
                        i,
                        nextend +
                        j)
                except Exception as e:
                    message = 'Could not create bad pixel extension in ext %i of %s because %s' \
                        % (i, infile, e)
                    raise SALTSpecError(message)
                if (1):
                    struct[i].header.update(
                        'BPMEXT',
                        nextend + j,
                        comment='Extension for Bad Pixel Mask')
                    struct.append(hdu)
                    j = j + 1

    return struct
Beispiel #20
0
def specslit(image,
             outimage,
             outpref,
             exttype='auto',
             slitfile='',
             outputslitfile='',
             regprefix='',
             sections=3,
             width=25,
             sigma=2.2,
             thres=6,
             order=3,
             padding=5,
             yoffset=0,
             inter=False,
             clobber=True,
             logfile='salt.log',
             verbose=True):

    with logging(logfile, debug) as log:

        # check all the input and make sure that all the input needed is provided
        # by the user

        # read the image or image list and check if each in the list exist
        infiles = saltio.argunpack('Input', image)

        # unpack the outfiles
        outfiles = saltio.listparse('Outimages', outimage, outpref, infiles,
                                    '')

        # from the extraction type, check whether the input file is specified.
        # if the slitfile parameter is specified then use the slit files for
        # the extraction. if the extraction type is auto then use image for the
        # detection and the slit extraction

        if exttype == 'rsmt' or exttype == 'fits' or exttype == 'ascii' or exttype == 'ds9':
            slitfiles = saltio.argunpack('Slitfile', slitfile)
            if len(slitfiles) == 1:
                slitfiles = slitfiles * len(infiles)
            saltio.comparelists(infiles, slitfiles, 'image', 'slitfile')
        elif exttype == 'auto':
            slitfiles = infiles
            log.message(
                'Extraction type is AUTO. Slit detection will be done from image'
            )

        # read in if an optional ascii file is requested
        if len(outputslitfile) > 0:
            outslitfiles = saltio.argunpack('Outslitfiles', outputslitfile)
            saltio.comparelists(infiles, outslitfiles, 'image',
                                'outputslitfile')
        else:
            outslitfiles = [''] * len(infiles)

        # check if the width and sigma parameters were specified.
        # default is 25 and 2.2
        if width < 10.:
            msg = 'The width parameter needs be a value larger than 10'
            raise SALTSpecError(msg)

        if sigma < 0.0:
            msg = 'Sigma must be greater than zero'
            raise SaltSpecError(msg)

        # check the treshold parameter. this needs to be specified by the user
        if thres <= 0.0:
            msg = 'Threshold must be greater than zero'
            raise SaltSpecError(msg)

        # check to make sure that the sections are greater than the order
        if sections <= order:
            msg = 'Number of sections must be greater than the order for the spline fit'
            raise SaltSpecError(msg)

        # run through each of the images and extract the slits
        for img, oimg, sfile, oslit in zip(infiles, outfiles, slitfiles,
                                           outslitfiles):
            log.message('Proccessing image %s' % img)

            # open the image
            struct = saltio.openfits(img)
            ylen, xlen = struct[1].data.shape
            xbin, ybin = saltkey.ccdbin(struct[0], img)
            # setup the VARIANCE and BPM frames
            if saltkey.found('VAREXT', struct[1]):
                varext = saltkey.get('VAREXT', struct[1])
                varlist = []
            else:
                varext = None

            # setup the BPM frames
            if saltkey.found('BPMEXT', struct[1]):
                bpmext = saltkey.get('BPMEXT', struct[1])
                bpmlist = []
            else:
                bpmext = None

            # open the slit definition file or identify the slits in the image
            slitmask = None
            ycheck = False
            if exttype == 'rsmt':
                log.message('Using slits from %s' % sfile)
                if yoffset is None:
                    yoffset = 0
                    ycheck = True
                slitmask = mt.read_slitmask_from_xml(sfile)
                xpos = -0.3066
                ypos = 0.0117
                cx = int(xlen / 2.0)
                cy = int(ylen / 2.0) + ypos / 0.015 / ybin + yoffset
                order, slit_positions = mt.convert_slits_from_mask(
                    slitmask,
                    order=1,
                    xbin=xbin,
                    ybin=ybin,
                    pix_scale=0.1267,
                    cx=cx,
                    cy=cy)
                sections = 1
            elif exttype == 'fits':
                log.message('Using slits from %s' % sfile)
                order, slit_positions = read_slits_from_fits(sfile)
            elif exttype == 'ascii':
                log.message('Using slits from %s' % sfile)
                order, slit_positions = mt.read_slits_from_ascii(sfile)
            elif exttype == 'ds9':
                log.message('Using slits from %s' % sfile)
                order, slit_positions, slitmask = mt.read_slits_from_ds9(
                    sfile, order=order)
                slitmask = None
                sections = 1
            elif exttype == 'auto':
                log.message('Identifying slits in %s' % img)
                # identify the slits in the image
                order, slit_positions = identify_slits(struct[1].data, order,
                                                       sections, width, sigma,
                                                       thres)

                # write out the slit identifications if ofile has been supplied
                if oslit:
                    log.message('Writing slit positions to %s' % oslit)
                    mt.write_outputslitfile(slit_positions, oslit, order)

            if ycheck:
                slit_positions, dy = check_ypos(slit_positions, struct[1].data)
                log.message('Using an offset of {}'.format(dy))

            # extract the slits
            spline_x = mt.divide_image(struct[1].data, sections)
            spline_x = 0.5 * (np.array(spline_x[:-1]) + np.array(spline_x[1:]))
            extracted_spectra, spline_positions = mt.extract_slits(
                slit_positions,
                spline_x,
                struct[1].data,
                order=order,
                padding=padding)
            if varext:
                extracted_var, var_positions = mt.extract_slits(
                    slit_positions,
                    spline_x,
                    struct[varext].data,
                    order=order,
                    padding=padding)
            if bpmext:
                extracted_bpm, bpm_positions = mt.extract_slits(
                    slit_positions,
                    spline_x,
                    struct[bpmext].data,
                    order=order,
                    padding=padding)

            # write out the data to the new array
            # create the new file
            hdulist = fits.HDUList([struct[0]])

            # log the extracted spectra if needed
            log.message('', with_stdout=verbose)

            # setup output ds9 file
            if regprefix:
                regout = open(
                    regprefix + os.path.basename(img).strip('.fits') + '.reg',
                    'w')
                regout.write('# Region file format: DS9 version 4.1\n')
                regout.write('# Filename: %s\n' % img)
                regout.write(
                    'global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1\nphysical\n'
                )

            # add each
            imglist = []
            nslits = len(spline_positions)
            for i in range(nslits):
                y1 = spline_positions[i][0].min()
                y2 = spline_positions[i][1].max()
                msg = 'Extracted Spectra %i between %i to %i' % (i + 1, y1, y2)
                # log.message(msg, with_header=False, with_stdout=verbose)
                sdu = fits.ImageHDU(extracted_spectra[i],
                                    header=struct[1].header)
                if varext:
                    vdu = fits.ImageHDU(extracted_var[i],
                                        header=struct[varext].header)
                    sdu.header['VAREXT'] = i + nslits + 1
                    varlist.append(vdu)
                if bpmext:
                    bdu = fits.ImageHDU(extracted_bpm[i],
                                        header=struct[bpmext].header)
                    sdu.header['BPMEXT'] = i + 2 * nslits + 1
                    bpmlist.append(bdu)
                imglist.append(sdu)

                # add in some additional keywords
                imglist[i].header['MINY'] = (y1,
                                             'Lower Y value in original image')
                imglist[i].header['MAXY'] = (y2,
                                             'Upper Y value in original image')
                if regprefix:
                    xsize = struct[1].data.shape[1]
                    xsize = int(0.5 * xsize)
                    rtext = ''
                    if slitmask:
                        # rtext='%s, %8.7f, %8.7f, %3.2f' % (slitmask.slitlets.data[i]['name'], slitmask.slitlets.data[i]['targ_ra'], slitmask.slitlets.data[i]['targ_dec'], slitmask.slitlets.data[i]['slit_width'])
                        pass
                    regout.write('box(%i,%i, %i, %i) #text={%s}\n' %
                                 (xsize, 0.5 *
                                  (y1 + y2), 2 * xsize, y2 - y1, rtext))

                # add slit information
                if slitmask:
                    imglist[i].header['SLITNAME'] = (
                        slitmask.slitlets.data[i]['name'], 'Slit Name')
                    imglist[i].header['SLIT_RA'] = (
                        slitmask.slitlets.data[i]['targ_ra'], 'Slit RA')
                    imglist[i].header['SLIT_DEC'] = (
                        slitmask.slitlets.data[i]['targ_dec'], 'Slit DEC')
                    imglist[i].header['SLIT'] = (
                        slitmask.slitlets.data[i]['slit_width'], 'Slit Width')

            # add to the hdulist
            hdulist += imglist
            if varext:
                hdulist += varlist
            if bpmext:
                hdulist += bpmlist

            # write the slit positions to the header
            # create the binary table HDU that contains the split positions
            tbhdu = mt.slits_HDUtable(slit_positions, order)
            bintable_hdr = tbhdu.header

            # add the extname parameter to the extension
            tbhdu.header['EXTNAME'] = 'BINTABLE'

            # add the extname parameter to the extension
            hdulist[0].header['SLITEXT'] = len(hdulist)
            hdulist.append(tbhdu)

            # add addition header information about the mask
            if slitmask:
                hdulist[0].header['MASKNAME'] = (slitmask.mask_name,
                                                 'SlitMask Name')
                hdulist[0].header['MASK_RA'] = (slitmask.center_ra,
                                                'SlitMask RA')
                hdulist[0].header['MASK_DEC'] = (slitmask.center_dec,
                                                 'SlitMask DEC')
                hdulist[0].header['MASK_PA'] = (slitmask.position_angle,
                                                'SlitMask Position Angle')

            # write out the image
            saltio.writefits(hdulist, oimg, clobber)