; Name:
; refsub_h4rg.pro
;
; PURPOSE:
; This program performs a reference pixel correction
; on Rockwell HAWAII-4RG detector data when read out using 32
; outputs.
;
; CALLING SEQUENCE:
;       refsub_h4rg, input_data, output_data, scaName
;
; INPUTS:
;       input_data      - A 4096x4096 array containing the image data.
;       output_data     - A 4096x4096 fltarr for the result
;     scaName       - The name of the device that generated the input data
;
; KEYWORD PARAMETERS:
;       fwindow       - The size of the filter window.
;       order         - Filter order, see the SAVGOL help page
;       degree        - Filter degree, see the SAVGOL help page
;       plot          - Set this =1 to plot the fits
;       simple        - Set this =1 for Maximal Spatial Averaging
;                       (subtract a median reference pixel)
;
;       verbose       - Set this =1 for verbose mode.
;
;
; EXAMPLE
;        IDL> fits_read, 'theImage.fits', myData, myHeader
;        IDL> myNewDate = fltarr(4096, 4096)
;        IDL> refsub_h4rg, myData, myNewData
;
;
; REFERENCE:
;
;
; MODIFICATION HISTORY:
;       Written by:
;       Modified:    B.J. Rauscher, IDTL, January 20, 2002
;                    Initial release based on most recent
;                    version of refsub_h1rg
;
;                    B.J. Rauscher, IDTL, February 12, 2003 1/f
;                    noise correlates across all 4 outputs.
;                    Use row reference pixels to make DC
;                    corrections to each output. Use columns to
;                    remove 1/f
;
;             Ernie Morse, IDTL, April 11, 2003 (v2.1)
;             added scaName as input parameter
;             added code block specific to device H2RG-003-4.8mu
;             performed general code cleanup
;
;             Don Figer, RIDL, April 28, 2007
;             modified for H4RG device;
;

; Define a function to return the mean of pixels in reference rows of
; one output. The output number ranges from 0-3.
function Get_RefRow_Mean, Data, Output

    X_size = 4096./32.	     ; Number of pixels in x-dimension of an output
    _Data = fltarr(X_size, 8); Create an array to hold the reference pixel data
    X_start = Output * X_size; First column to extract
    X_stop = (Output + 1) * X_size - 1; Last column to extract
    _Data[0:X_size-1,0:3] = Data[X_start:X_stop,0:3]; Get bottom rows of reference pixels
    _Data[0:X_size-1,4:7] = Data[X_start:X_stop,4092:4095]; Get top rows of refernce pixels

    DJS_Iterstat, _Data, mean = The_Mean
    return, The_Mean

end


pro RefSub_H4rg, Input_Data, Output_Data, SCAName, Fwindow=Fwindow, $
	Order=Order, Degree=Degree, Plot=Plot, Simple=Simple, $
	Verbose=Verbose, Help=Help

  ; The reference pixels on the Rockwell HAWAII-4RG SCA are the
  ; outermost 4 pixels all around the chip.
  ; create variables to hold the dimensions of the H2RG SCA (in pixels)
  Xsize = long(4096)
  Ysize = long(4096)
  NumOutputs = 32

  ; Set defaults
  if (not keyword_set(plot)) then plot = 0 ; Default is no plots
  if (not keyword_set(verbose)) then verbose = 0; Default is quiet mode
  if (not keyword_set(help)) then help = 0; Default does not print help message
  if (not keyword_set(simple)) then simple = 0

  ; Print a help message and exit if requested
  if (help) then $
     stop, 'Usage: refsub_h4rg, input_data, output_data [, fwindow=fwindow, order=order, degree=degree, /plot, /simple, /verbose, /help]'

  ; Adjust all NumOutputs outputs to have the same mean as output #0 in
  ; the reference rows.
  for Output = 1, 31 do begin

    ; Get first and last columns of output to correct
    X_Start = Output * Xsize/NumOutputs 	   ; First column of output
    X_Stop = (Output + 1) * (Xsize/NumOutputs) - 1 ; Last column of output

    ; Offset the output
    Input_Data[X_start:X_stop,*] = Input_Data[X_start:X_stop,*] $
      + Get_RefRow_Mean(Input_Data, Output - 1) $
      - Get_RefRow_Mean(Input_Data, Output)
  endfor

  ; We will use a Savitzky-Golay filter to smooth the reference pixel data.
  ; See the SAVGOL procedure's help page for more information on
  ; the following.
  ; Default uses 64 pixels on either side of current pixel for smoothing

  If (not(keyword_set(fwindow))) then fwindow = 64  ; Default uses 64 pixels
  If (not(keyword_set(order))) then order = 0; Use zero to smooth
  If (not(keyword_set(degree))) then degree=3; Three seems reasonable

  ; Extract and average reference pixels
  If (verbose) then $
     print, 'Extracting averaged reference columns on left and right hand sides of SCA'
  Row = intarr(Ysize)            ; Y values vector. Undersize
  Mean_RefCol_L = fltarr(Ysize)  ; Signals vector on left
  Mean_RefCol_R = fltarr(ysize)  ; Signals vector on right
  For y=0, ysize-1 do begin

     Row[y] = y
     ; Do not use the first reference pixel on each
     ; output. Rockwell's HAWAII-1RG worked best like this. For
     ; now, assume that HAWAII-2RG will do the same.
     Mean_RefCol_L[y] = mean(Input_Data[1:3,y])  ; Average left side reference pixels
     Mean_RefCol_R[y] = mean(Input_Data[Xsize-4:Xsize-2,y]) ; Average right side reference pixels

  Endfor

  ; Sigma clip to get rid of outliers
  If (verbose) then $
       print, 'Sigma clipping reference columns to remove outliers'
  Sigclip, Mean_RefCol_L, threshold=3.0, maxiter=5
  Sigclip, Mean_RefCol_R, threshold=3.0, maxiter=5
  If (verbose) then begin
     print, 'Mean reference pixel on left = ', mean(input_data[0:3,*])
     print, 'Mean reference pixel on right = ', mean(input_data[xsize-4:xsize-2,*])
  Endif

  ; Apply reference pixel correction
  ; Create arrays to hold columns of values to be subtracted from the science pixels
  RefPixCol_Left = Mean_RefCol_L
  RefPixCol_Right = Mean_RefCol_R
  If (not Simple) then begin
     ; Apply Spatial Averaging reference pixel correction using
     ; Savitzky-Golay filter. See the SAVGOL help page for
     ; more information.
     ;
     ; Exclude the first and last 4 rows from convolution with the kernel. 
     ; These are reference rows and they need to be handled differently 
     ; for unknown physical reasons.
     savgol_filter = savgol(fwindow, fwindow, order, degree)
     refpixcol_left[4:ysize-5] = convol(mean_refcol_l[4:ysize-5], $
				savgol_filter, /EDGE_TRUNCATE)
     refpixcol_right[4:ysize-5] = convol(mean_refcol_r[4:ysize-5], $
				savgol_filter, /EDGE_TRUNCATE)
     stop
   Endif else begin

     ; Apply Maximal Spatial Averaging reference pixel correction. As before,
     ; exclude outtermost reference pixels in columns.
     ;
     ; The approach will be to create a 1D array containing
     ; reference pixel values. Loop over all pixels and load
     ; the reference pixel array

     refrows_bottom = reform(input_data[4:xsize-5, 0:3], $
		    n_elements(input_data[4:xsize-5, 0:3]))
     refrows_top    = reform(input_data[4:xsize-5, ysize-4:ysize-1], $
		    n_elements(input_data[4:xsize-5, ysize-4:ysize-1]))
     refcols_left   = reform(input_data[1:3, 4:ysize-5], $
		    n_elements(input_data[1:3, 4:ysize-5]))
     refcols_right  = reform(input_data[xsize-4:xsize-2, 4:ysize-5], $
		    n_elements(input_data[xsize-4:xsize-2, 4:ysize-5]))

     ; add all the reference pixels into one array
     ; allrefpix = [refrows_bottom, refrows_top, refcols_left, refcols_right]
     ; as a test, exclude the bottom row this seems to be bad for the first read
     allrefpix = [refrows_top, refcols_left, refcols_right]

     ; Calculate mean of all reference pixels using
     ; djs_iterstat and 3 sigma clipping (the default)
     djs_iterstat, allrefpix, mean=mean_refpix

     ; Both reference columns are the same for Maximal Spatial Averaging
     RefPixcol_Left[*] = Mean_Refpix
     RefPixcol_Right   = RefPixCol_Left

   endelse

    ; Make plots if requested

    if (plot) then begin

       set_device = 'WIN'
 ;      window, retain=2; Necessary on some x displays
       !P.MULTI = [0,1,2]   ; Plot 1 plot over the other

       ; First plot left hand reference pixels
       plot, row, mean_refcol_l, $
        title = 'Mean Reference Column [1:3,*]', $
        xtitle = 'Row Number', $
        ytitle = 'Signal (ADU)', $
        xrange = [0,xsize-1], $
        xstyle = 1

       ; Draw a smooth curve through pixels
       oplot, row, refpixcol_left, thick=3

       ; Now plot right hand reference pixels
       plot, row, mean_refcol_r, $
        title = 'Mean Reference Column [2044:2046,*]', $
        xtitle = 'Row Number', $
        ytitle = 'Signal (ADU)', $
        xrange = [0,xsize-1], $
        xstyle = 1

       ; Draw a smooth curve through points.
       oplot, row, refpixcol_right, thick=3

       !P.MULTI = 0 ; Return to default plotting mode

    endif
;    print, "avg of left ref pixels ",avg(refpixcol_left)
    ;Perform reference pixel correction
;     if (not simple) then begin
        for x=0, (xsize/2)-1 do begin
            output_data[x,*] = input_data[x,*] - refpixcol_left
            output_data[(xsize-1)-x,*] = input_data[(xsize-1)-x,*] - refpixcol_right
        endfor
;     endif else begin
;       output_data = input_data - mean_refpix
;     endelse

end


