;+ THIS MODULE CONTAINS TWO SUBROUTINES
;       pro mygauss() and function brl_find511()
;
;
;  
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; evaluate gaussian + linear model for use with curvefit()
; 
; model is f(x) = a[0]*exp(-((x-a[1])/a[2])^2) + a[3]x + a[4]
;
; INPUT: x is where the model is to be evaluated
;        a is the current list of 5 parameter values; these
;          must be initialized by the caller
;
; OUTPUT: f is evaluated as a linear+gaussian model
;        pder is a list of 5 partial derivatives of f wrt a
;
; WARNING: for speed, no checks for foolish function evaluation
;        requests. Caller is responsible! For instance,
;        if one sets a[2]=0 or (x-a[1])/a[2]=1000 for some x,
;        expect error msgs and/or nonsense output.
;-

pro mygauss, x, a, f, pder

  cnt = n_elements(x)
  z = (x-a[1])/a[2]
  temp = exp(-z*z)
  hold = (a[0]*2./a[2])*temp*z

  f = a[0]*temp + a[3]*x + a[4]
  pder = [[temp], [hold], [hold*z], [x], [fltarr(cnt)+1.]]

end
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;
;+ find the slow spectrum bin value of the 511 line
;
; INPUT: slo list of 256 slow spectrum count rates (counts/second)
;        the slo list should not be normalized by bin widths
;
; OUTPUT: bin value for the 511 peak (usually not an integer)
;         -1 on failure (511 peak not found)
;
; OPTIONS: offset=offset low bdy for 511 search region (default is 100)
;          err=err 1-sigma uncertainties for each slo value;
;                  this should be should be a list of
;                  sqrt(# of counts)/(integration time in seconds)
;
; ACTION: limit the search to a reasonable part of the
;         entire spectrum. Fit a line to the two endpoints
;         of the search region, and subtract off the line.
;         Then find the midpoint position of the list of
;         values exceeding 50% of the max residual. That
;         becomes a start guess for the peak location,
;         modeled by a line+Gaussian. Amplitude and width are
;         hard-coded typical values. Fit model to data and
;         get best fit peak location. If the fit looks good,
;         return its position; else return -1 to signal failure.
;
; HISTORY: first version working 31Dec2012/mm
;
; FUTURE: might need to adjust testing for valid 511 peak
;
; EXAMPLE: peak = brl_find511(spec, offset=95)
;          peak = brl_find511(spec, err=sigmas)
;-

function brl_find511, slow, offset=offset, err=err

if n_elements(slow) ne 256 then return, -1
if (not keyword_set(err)) then err=fltarr(256)+1.
if (not keyword_set(offset)) then offset=100

widths=[intarr(64)+1,intarr(32)+2,intarr(32)+4,intarr(32)+8, $
  intarr(32)+16,intarr(32)+32,intarr(32)+64]
x= [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, $
    11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5, 19.5, 20.5, $
    21.5, 22.5, 23.5, 24.5, 25.5, 26.5, 27.5, 28.5, 29.5, 30.5, $
    31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, $
    41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, $
    51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, $
    61.5, 62.5, 63.5, 65, 67, 69, 71, 73, 75, 77, 79, 81, $
    83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, $
    107, 109, 111, 113, 115, 117, 119, 121, 123, 125, $
    127, 130, 134, 138, 142, 146, 150, 154, 158, 162, $
    166, 170, 174, 178, 182, 186, 190, 194, 198, 202, $
    206, 210, 214, 218, 222, 226, 230, 234, 238, 242, $
    246, 250, 254, 260, 268, 276, 284, 292, 300, 308, $
    316, 324, 332, 340, 348, 356, 364, 372, 380, 388, $
    396, 404, 412, 420, 428, 436, 444, 452, 460, 468, $
    476, 484, 492, 500, 508, 520, 536, 552, 568, 584, $
    600, 616, 632, 648, 664, 680, 696, 712, 728, 744, $
    760, 776, 792, 808, 824, 840, 856, 872, 888, 904, $
    920, 936, 952, 968, 984, 1000, 1016, 1040, 1072, 1104, $
    1136, 1168, 1200, 1232, 1264, 1296, 1328, 1360, 1392, $
    1424, 1456, 1488, 1520, 1552, 1584, 1616, 1648, 1680, $
    1712, 1744, 1776, 1808, 1840, 1872, 1904, 1936, 1968, $
    2000, 2032, 2080, 2144, 2208, 2272, 2336, 2400, 2464, $
    2528, 2592, 2656, 2720, 2784, 2848, 2912, 2976, 3040, $
    3104, 3168, 3232, 3296, 3360, 3424, 3488, 3552, 3616, $
    3680, 3744, 3808, 3872, 3936, 4000, 4064] 

; nominal range for 511 line
  width=25
  select=indgen(width)+offset
  y = slow[select]/widths[select]
  x = x[select]
  err = err[select]/widths[select]
  usersym,[-.5,.5,.5,-.5,-.5],[-.5,-.5,.5,.5,-.5],/fill

; describe a line through endpoints of the selected range
  y1 = y[0]
  y2 = y[width-1]
  x1 = x[0]
  x2 = x[width-1]
  m = (y2-y1)/(x2-x1)
  b = y1 - m*x1

;
; find approximate peak location after subtracting linear bkgd
;
  peakregion = y - (m * x + b)
  apex=max(peakregion)
  higharea=where(peakregion gt 0.5*apex,cnt)
  if (cnt lt 2) then return, -1
  peaklocation = x[floor(median(higharea))]

  guess=[1., peaklocation, 10., m, b]
  yfit=curvefit(x,y,1./err^2,guess, $
       chisq=chisq,sigma,function_name='mygauss',status=stat)
  if (guess[2] gt 20 or guess[0] lt 0.2) then return, -1

;  some diagnostics (might need to adjust above tests)
;
;  print,guess
;  plot,x,y,psym=8,yrange=[0,3]
;  oplot,x,yfit
;  oploterr,x,y,err

  return,guess[1]

end