@lucicreatemidline.fnc
@lucirejection1d.fnc
@lucilinedetect.fnc
@luciplotlines.pro
// image:      image to analize
// linelist:   line list (wavelengths)
// identifylinespars [1]: expected dispersion (disp)
//                   [2]: size of sub-longslit to median (midgausssize)
//                   [3]: tolerance of the expected dispersion (disp_tol)
//                   [4]: tolerance for interval ratio comparison (interval_tol)
//                   [5]: number of pixels to omit at left and right end of midline (omitpixels)
//                   [6]: maximum number of lines to expect (200 should be enough)
// method:     background removal method:
//             "polynomial": fit background with polynomial (should be default)
//             "boxcar": subtract boxcar'd signal 
// backgroundpars:   method = "polynomial"      method = "boxcar"
//                   [1]: simga threshold       [1]: simga threshold
//                   [2]: smoothfactor          [2]: smoothfactor
//                   [3]: rejection window      [3]: boxfactor
//                   [4]: sigma for rejection
//                   [5]: number of iterations for rejection
//                   [6]: order for background polynomial fit
// plot:       plot analysis of identified lines:        plot = plotdevice
//             don't plot analysis of identified lines:  plot = ""
function luciidentify, image, linelist, identifypars, method, backgroundpars, plot {
    disp = identifypars[1]
    midgausssize = int(identifypars[2])
    disp_tol = identifypars[3]
    interval_tol = identifypars[4]
    omitpixels = int(identifypars[5])
    maxlines = int(identifypars[6])

    sigma = backgroundpars[1]
    smoothfactor = backgroundpars[2]
    if (method == "boxcar") {
        if (nelements(backgroundpars) != 3) {
            print "ERROR: method=boxcar needs exactly 3 paramneters"
        }
        boxfactor = backgroundpars[3]
    }
    if (method == "polynomial") {
        if (nelements(backgroundpars) != 6) {
            print "ERROR: method=polynomial needs exactly 6 paramneters"
        }
        window = int(backgroundpars[3])
        sigmarej = backgroundpars[4]
        iter = int(backgroundpars[5])
        order = int(backgroundpars[6])
    }

    imagewidth = naxis1(image)
    imageheight = naxis2(image)

    /* create midline */
    midlineA = lucicreatemidline(image, midgausssize, 0)

    // smooth median'd line and calc threshold
    
    if (method == "boxcar") {
        midline = midlineA - boxcar(midlineA, boxfactor, /median)
        smooth midline, smoothfactor
    }
    if (method == "polynomial") {
        x = [1:imagewidth]
        r = lucirejection1d(midlineA, sigmarej, iter, window)

        pos = where(r > 0)
        xx = x[pos]
        rr = r[pos]

        par = polyfitxy(xx, rr, order)[*,1]
        bkgr = poly([1:imagewidth], par)

        // subtract background
        midline = midlineA - bkgr
        smooth midline, smoothfactor
    }
    
    /* extract edges */
    midgausspos = lucilinedetect(midline, sigma, omitpixels, maxlines)
    nrfound = naxis1(midgausspos)

    /* do a first line identification and work only on identified lines afterwards */
    identified = identifylines(midgausspos, linelist, disp-disp*disp_tol/2, disp+disp*disp_tol/2, interval_tol)
    nr_identified = naxis1(identified[1,*])

    if (plot != "") {
        luciplotlines midline, linelist, midgausspos, identified, plot
    }

    print ">>> # Extracted:    " + nrfound + " candidates. first @: " + midgausspos[1] + ", last @: " + midgausspos[nrfound]
    print ">>> # Identified:   " + nr_identified + " candidates. first @: " + identified[1,1] + ", last @: " + identified[1,nr_identified]

    if (nr_identified < nelements(linelist)) {
        a=midgausspos
        ii = 1

        // identifizierte midgausspos linien weg
        for jj=1,naxis2(identified) {
            for kk=1,nelements(a) {
                if (identified[1,jj] == a[kk]) {
                    a[kk] = -1
                    ii++
                }
            }
        }
        a=a[sort(a)]
        a=a[ii:nelements(a)]

        b=linelist
        ii = 1
        // identifizierte linelist linien weg
        for jj=1,naxis2(identified) {
            for kk=1,nelements(b) {
                if (identified[2,jj] == b[kk]) {
                    b[kk] = -1
                    ii++
                }
            }
        }
        b=b[sort(b)]
        b=b[ii:nelements(b)]

        /* now find the remaining non-detected lines using the fitted polynomial */
        tmp = polyfitxy(identified[2,*], identified[1,*], 2)
        calline = poly(b, tmp[*,1])

        newidentified=identified
        resize newidentified, 2, naxis2(newidentified)+ii
        
        nn = naxis2(identified)
        for jj=1,nelements(calline) {
            for kk=1,nelements(a) {
                if (abs(calline[jj]-a[kk]) < 1) {
                    nn++
                    newidentified[1,nn] = a[kk]
                    newidentified[2,nn] = b[jj]
                }
            }
        }
        // falls nicht alle übrigen linelist einträge in midgausspos gefunden wurden
        identified = newidentified[*,1:nn]
        gg = identified[1,*]
        s=sort(gg)
        gg = gg[s]
        identified[1,*] = gg
        gg = identified[2,*]
        gg = gg[s]
        identified[2,*] = gg

        nr_identified = naxis2(identified)
        print ">>> # Reidentified: " + nr_identified + " candidates. first @: " + identified[1,1] + ", last @: " + identified[1,nr_identified]

        if (plot != "") {
            luciplotlines midline, linelist, midgausspos, identified, plot
        }
    }    
    luciidentify = identified

    copyheader luciidentify, image
    setfitskey luciidentify, "EXPDISP", disp, "Expected spectral dispersion (e.g. pixels/um depending on the units used)"
    setfitskey luciidentify, "MIDGAUSS", midgausssize, "Size of sub-longslit in the middle of the image to take the median of"
    setfitskey luciidentify, "OMITPIX", getfitskey(midgausspos, "OMITPIX"), "No. of pixels to omit at each end of spectrum"
    setfitskey luciidentify, "DISPTOL", disp_tol, "Tolerance of the expected dispersion"
    setfitskey luciidentify, "INTERTOL", interval_tol, "Tolerance for interval ratio comparison"
    setfitskey luciidentify, "EXTRLIN", nrfound, "No. of extracted lines"
    setfitskey luciidentify, "EXTRLIN1", midgausspos[1], "First extracted line at pixel position"
    setfitskey luciidentify, "EXTRLIN2", midgausspos[nrfound], "Last extracted line at pixel position"
    setfitskey luciidentify, "IDENLIN", nr_identified, "No. of identified lines"
    setfitskey luciidentify, "IDENLIN1", luciidentify[1,1], "First identified line at pixel position"
    setfitskey luciidentify, "IDENLIN2", luciidentify[1,nr_identified], "Last identified line at pixel position"
    setfitskey luciidentify, "IDENWAV1", luciidentify[2,1], "First identified line at wavelength"
    setfitskey luciidentify, "IDENWAV2", luciidentify[2,nr_identified], "Last identified line at wavelength"
    setfitskey luciidentify, "SIGMATHR", sigma, "Sigma for threshold calculation"
    setfitskey luciidentify, "SMOOFAC", smoothfactor, "Smoothfactor"
    setfitskey luciidentify, "BKGRMETH", method, "Method for background subtraction"
    if (method == "boxcar") {
        setfitskey luciidentify, "BOXFAC", boxfactor, "Boxcarfactor"
    }
    if (method == "polynomial") {
        setfitskey luciidentify, "SIGMAREJ", sigmarej, "Sigma for rejection"
        setfitskey luciidentify, "ITER", sigmarej, "Number of iterations for rejection"
        setfitskey luciidentify, "ORDER", order, "Order for baxground polynomial"
    }

    print "FINISHED IDENTIFYING LINES"
}
