Viewing contents of file '../idllib/contrib/buie/clscan.pro'
;+
; NAME: 
;  clscan
; PURPOSE:
;  Scan a group of raw OSIRIS XD frames and find rough spectral location.
; DESCRIPTION:
; CATEGORY:
;  Spectroscopy
; CALLING SEQUENCE:
;  clscan,calib,root,start,last,frno,mate,RANGE=range,PATH=path
; INPUTS:
;  calib- Anonymous structure containing all pertinent calibration
;           information.  This structure is usually loaded beforehand using
;           the routine, "ldcalir"
;  root - string containing the root of the file name (with leading path
;         if desired).  DO NOT include the . between the root and suffix.
;  start  - First spectrum number of sequence to scan.
;  last   - Last spectrum number of sequence to scan, if negative, this number
;             is taken to be the number of spectra to scan.
; OPTIONAL INPUT PARAMETERS:
; KEYWORD INPUT PARAMETERS:
;  PATH - optional string that points to the directory containing the data.
;           This information is not used if the root already begins with '/'.
;           If root is not an absolute pathname, then PATH is prepended to
;           root for READ operations.  This path is not used for saving.
;           This allows reading from one directory (possible a read only area)
;           and then saving to the current directory.
;  XRANGE - range of column numbers to average in extracted spectral slice to
;           find rough location of spectrum.  Default is all columns.
;  YRANGE - range of rows that are valid locations.  Default is all rows but the
;           first and last.
;  EXCLUDE- List of frames in the indicated range that should be excluded from
;           consideration.
;
; OUTPUTS:
;  frno - A vector of frame numbers.
;  mate - A vector that gives a suggested frame number from this set for
;           a sky pair match that does not overlap the object.
;  
;  Also, information on location for each spectrum is printed to the console.
;
; KEYWORD OUTPUT PARAMETERS:
; COMMON BLOCKS:
; SIDE EFFECTS:
; RESTRICTIONS:
;  Specifically written for OSIRIS cross-dispersed spectral data.
; PROCEDURE:
; MODIFICATION HISTORY:
;  95/09/27, Written by Marc W. Buie, Lowell Observatory
;  96/05/29, MWB, changed 4th argument from NSPEC to LAST.
;  97/08/07, MWB, removed RANGE (buggy) and added XRANGE and YRANGE
;  97/12/10, MWB, fixed a really nasty bug that corrupt the location for
;                   very high signal-to-noise data.
;  98/07/01, MWB, added code to skip over missing files in sequence.
;-
pro clscan,calib,root,start,last,frno,mate, $
   PATH=path,XRANGE=xrange,YRANGE=yrange,EXCLUDE=exclude

if badpar(calib,8,1,CALLER='clscan (calib) ') then return
if badpar(root,7,0,CALLER='clscan (root) ') then return
if badpar(start,[2,3],0,CALLER='clscan (start) ') then return
if badpar(last,[2,3],0,CALLER='clscan (last) ') then return
if badpar(xrange,[0,2,3],1,CALLER='clscan (XRANGE) ',DEFAULT=[0,calib.npts-1]) then return
if badpar(yrange,[0,2,3],1,CALLER='clscan (YRANGE) ',DEFAULT=[1,calib.height-2]) then return
if badpar(exclude,[0,2,3],[0,1],CALLER='clscan (EXCLUDE) ',DEFAULT=-1) then return
if badpar(path,[0,7],0,caller='clscan: (PATH) ',default='./') then return

; If the first character of the file name root is / then it is assumed the
;   root contains a full path as well and the PATH value is NOT prepended.
;   Otherwise, the file name becomes PATH+ROOT+.+suffix.
if strmid(root,0,1) eq '/' then begin
   newroot = root
endif else begin
   newroot = addslash(path)+root
endelse

; find the number of spectra to examine, last<0 is the number, otherwise range.
if last lt 0 then $
   nspec=abs(last) $
else $
   nspec =  last - start + 1

; Build the index list of frames to do.  This starts with a list of all spectra
;   in range.  Later, these numbers may be set to -1 which indicates frame is
;   not to be looked at.
frno=indgen(nspec)+start

; Scan through the exclude keyword array.  Any numbers in exclude that match
;   a number in the FRNO array will be set to -1 in FRNO.
for i=0,nspec-1 do begin
   z=where(frno[i] eq exclude,count)
   if count ne 0 then frno[i]=-1
endfor

; Check to see that each file not excluded exist.  If it doesn't, exclude it.
for i=0,nspec-1 do begin
   if frno[i] ne -1 then begin
      fname = newroot+'.'+string(frno[i],format='(i3.3)')
      if not exists(fname) then frno[i] = -1
   endif
endfor

; Construct file name

; Sanity check to make sure there is still stuff to do.
z=where(frno ne -1,count)
if count eq 0 then $
   message,'Error ** you have excluded all frames, nothing to do.'

; Collapse the frame list to only those to be done.
frno = frno[z]

; This is the number of spectra to scan.
nsp = n_elements(frno)

; This array will contain the row location of the object for each frame.
loc = intarr(nsp)

; This array will indicate ...
perloc = fltarr(nsp)

; If there is no object
ranper = 1.0/float(calib.height)

; Loop over the frames to process.
for i=0,nsp-1 do begin

   ; Construct file name
   fname = root+'.'+string(frno[i],format='(i3.3)')

   ; Get the strip image of this frame.
   getstrip,calib,newroot,frno[i],strip

   ; Scan the strip sub-region for the local maximum in each column (x)
   ;   at this point xpos and ypos are relative to the sub-region.
   maxloc,strip[xrange[0]:xrange[1],yrange[0]:yrange[1]],xpos,ypos,/x

   ; Compute a histogram of the y positions returned.  The premise is that
   ;   the object is basically in the same spot and is located where the
   ;   histogram is seen to peak.  As a check, compute the fraction of the
   ;   columns that contain this peak.  If this fraction is near ranper then
   ;   it's likely that there is no object.
   hist=histogram(ypos,min=0,max=yrange[1]-yrange[0])
   hloc = where(hist eq max(hist))
   loc[i] = hloc[0]
   perloc[i] = float(hist[loc[i]])/float(n_elements(ypos))

;   if perloc(i) lt 2.0*ranper then begin
;      sz=size(strip)
;      for j=0,sz(1)-1 do begin
;         med = median(strip(j,*))
;         strip(j,*) = strip(j,*)-med
;      endfor
;      asdf
;   endif
endfor

; Convert from sub-region relative to absolute coordinates.
loc = loc + yrange[0]

minsep=9
mate = intarr(nsp)
matedis = intarr(nsp)

; Rule one, find nearest frame number spectrum that is further than MINSEP
;   away from current spectrum.
for i=0,nsp-1 do begin
   fname = root+'.'+string(frno[i],format='(i3.3)')
   ; distance in frame number from current frame
   fdist = abs(frno - frno[i])
   ; distance in pixels from current frame location.
   ydist = abs(loc - loc[i])

   ; find those that are further than MINSEP
   z = where(ydist ge minsep,count)

   ; there are frames futher than minsep, get the closest in frame distance.
   if count ne 0 then begin
      ydistz = ydist[z]
      fdistz = fdist[z]
      specz  = frno[z]
      z = where(fdistz eq min(fdistz))
      mate[i] = specz[z[0]]
      matedis[i] = ydistz[z[0]]

   ; nothing is further than minsep, take the furthest but still closest in frame #.
   endif else begin
      z = where(ydist eq max(ydist))
      ydistz = ydist[z]
      fdistz = fdist[z]
      specz  = frno[z]
      z = where(fdistz eq min(fdistz))
      mate[i] = specz[z[0]]
      matedis[i] = ydistz[z[0]]
   endelse
   if perloc[i] lt 2.5*ranper then $
      comment = 'sig  very faint check location' $
   else $
      comment ='sig'
   print,fname,mate[i],loc[i],matedis[i],perloc[i]/ranper,comment, $
      format='(a," - ",i3.3,4x,"@",i3,2x,i3,3x,f5.1,1x,a)'

endfor

end