;+
; PROJECT:
;	SDAC
;
; NAME: 
;	CALIBRATE
;
; PURPOSE:
;     This subroutine calculates the energies corresponding to the channel
; boundaries for the BATSE Spectral Detectors.  
;	
; METHOD:
; The calibration is assumed
; to consist of two parts:  a calculation of the light output from the NaI
; crystal from the channel number, and a calculation of the energy loss in
; the crystal that produces that light.  The SLED is mitigated by an addition
; to the channel number in the term linear in channel number.  The subroutine
; also calculates the effective uncompressed channel numbers.
;
;  There are calibration fiducials for the lld's, those obtained by schwartz
;  are the defaults.  To change to the Preece fiducials, set which_fiducials
;  to 0 in  read_coef_com, spec_lld_old, which_fiducials
;
; INPUTS:
;      ndet---the detector number
;      width64---the variable width of the 64th channel
;      spec_lld---LLD settings for all 8 detectors
;      nlines---the number of lines used for calibration
;      chan---vector of location of calibration lines in uncompressed channels
;      en---vector of location of calibration lines in energy
;
; KEYWORD INPUTS:
;	MAXCHAN - calibrate only up to this channel to save time.
;      /discsp - edges are only those needed for discsp edges, lld/2, lld, max(evec)
;      /report_calibration if set then the input arguments
;	are set from the common block cal_sher_com and the outputs are 
;	calculated
;      /noevec - don't compute the evec for output, just go as far as xvec
;
;   Output:
;      evec---the vector of energies, 257 values normally, 3 for /discsp
;      unevec - energies w/o sled correction
;      xvec---the vector of effective uncompressed channel boundaries
;      pre_olight - vector of light outputs/channel before sled amp correction
;      olight     - vector of light outputs/channel after sled
;
;   Common blocks:
;     common spline_com, break,c0,c1,c2,c3
;      common sled_com, sb,sc,sd,scut
;      common fiducial_com,af,bf,cf,xf
;      common read_coef_com, spec_lld_old, which_fiducials
;	;common block for passing 511 line position out to the top level
;	common cal_sher_com, pass511, w64_used, spec_lld_used
;
; Category: CGRO/BATSE
;
; Calls:
;	READ_COEF, SLED, EDGE_PRODUCTS, FCRYSTAL, DELTA_CONTROL, FCHECK
;	GAIN_COR, CHANNELS, LLD_CHAN
; History:
;   Written 10/2/91 DLB; Revised 12/6/91 laf; Last modified 4/7/92 DLB
;   Translated to IDL by RAS, 92/6/5
;	
;   ras, 13-March-94, fixed discsp settings
;   ras, 19-aug-94, default fiducials for lld changed to ras's
;   ras, 19-oct-94, corrected energy calibration for spec discriminators, discsp
;   ras, 29-mar-95, added cal_sher_com and communication for this common block
;   ras, 29-dec-95, include sled correction in DISCSP calculation since
;	the 511 line is in the pha calibration which includes the 
;	sled pedestal which can be several channels wide
;       also switched to Preece's lld calibrations as default
;   Version 2, ras, 15-March-1996, added maxchan
;   Version 3, ras, 8-Nov-1996, changed fiducial in Schwartz calibration for
;	det 2.
;   Version 4, ras, 11-Nov-1996, changed defaults to Schwartz fiducials 
;   Version 5, ras, 27-nov-1996, calling LLD_CHAN for Skelton fiducial calibration
;	and using DATE for discsp_edges because of SPEC1 change on 3-Oct-1993
;   Version 6, richard.schwartz@gsfc.nasa.gov, 
;	added SPEC_LLD keyword to LLD_CHAN call 1-apr-1998.
;	
;
;-

;
pro calibrate, ndet, width64, spec_lld, nlines, chan, en, evec, xvec, $
pre_olight=pre_olight, olight=olight, unevec=unevec, discsp=discsp,$
report_calibration=report_calibration, noevec=noevec, $
maxchan=maxchan, error=error, date=date


error = 1
;common block for passing 511 line position, width of channel 64, and 
;the spec lower-level discriminator settings out to the top level.
;This facilitates adjusting the calibration in the top-level routines.

common cal_sher_com, ndet_used, chan_used, en_used, w64_used, spec_lld_used


common sled_com, sb,sc,sd,scut
common fiducial_com,af,bf,cf,xf
common read_coef_com, spec_lld_old

if keyword_set(report_calibration) then begin
    if n_elements(ndet_used) eq 0 then return
    ndet = ndet_used
    chan = chan_used
    nlines = n_elements(chan)
    en   = en_used
    width64 = w64_used
    spec_lld=spec_lld_used
    endif
;
; Read in coefficients if the first time through

checkvar,spec_lld_old, intarr(8)
new = where( spec_lld eq spec_lld_old, ncount)

if total(abs(spec_lld-spec_lld_old)) ne 0 then begin
    read_coef,spec_lld
    spec_lld_old=spec_lld
    endif
;
; Set up an array of channel boundaries
channel,width64,xvec

if keyword_set(noevec) then return

;Make the routine more tolerant of non-vector arguments for the cal line
chan = fltarr(nlines) + chan
en   = fltarr(nlines) + en

;
; Get gain corrected coefficients

gain_cor,ndet,nlines,chan,en,a,b,c,x_0

;
; Loop over all channel boundaries
; First calculate the light from the NaI crystal

olight = a+b*xvec
iless = where(xvec lt x_0, ncount)
if ncount ge 1 then $
olight(iless)=olight(iless)+c*(xvec(iless)-x_0)^2

pre_olight = olight ;olight prior to sled correction
;
; Make correction for SLED
sled,ndet,b,xvec,olight

; Finally, calculate the energy
evec = olight(0:fcheck(maxchan,256))*0.0
unevec = evec
case keyword_set(discsp) of
    0: begin
        if fcheck(maxchan,256) gt 100 then begin
            for i=0,n_elements(evec)-1 do begin
                evec(i) = fcrystal(olight(i))
                unevec(i) = fcrystal(pre_olight(i))
                endfor
            endif else begin    ;Use fast interpolation scheme!!!
            evec = fcrystal1(olight)
            unevec = fcrystal1(pre_olight)
            endelse
        end
    1: begin ;3 values for discsp
        fratio = (fast_ratio(spec_lld))(ndet)
        nval   = [lld_chan( date, ndet, spec_lld=spec_lld, /skelton), n_elements(evec)-1]
        ;Something happened to SPEC1 during reboost on 3-Oct-1993 that changed
        ;the slld->lld_chan conversion
        if ndet eq 1 then if anytim(fcheck(date,0.0),/sec) gt anytim('3-oct-1993',/sec) then $
        nval(0)=nval(0)-4
        nval = [nval(0)/2,nval]  ; > 0.01
        evec = evec(nval)
        evec(2) = fcrystal(pre_olight(nval(2)))
        olight1 = a + b*nval(1)
        if nval(1) lt x_0 then olight1 = olight1 + c*(nval(1)-x_0)^2
        if olight1 le 0 then printx,'Danger in DISCSP calibration!!! Calibrate.pro'
        pre_olight1=olight1
        sled, ndet, b, nval(1), olight1
        unevec(1) = fcrystal(pre_olight1)
        unevec(0) = fcrystal(pre_olight1/fratio)
        evec(1) = fcrystal(olight1)
        evec(0) = fcrystal(olight1/fratio)
        ;print, 'olight1, evec(0:2)', olight1, evec(0:2)
        
        end
    endcase

;if delta_control is set to 0, then the pha energy widths are in energy loss units
;which is the bdas analysis standard, the spex default is to use the light widths

if not delta_control() then begin
    olight = evec
    if fcheck(ndet,1) eq 0 and not keyword_set(discsp) then $
    printx,'Channel widths set to Energy loss units, BDAS standard.'
    endif else if fcheck(ndet,1) eq 0 and not keyword_set(discsp) then $
printx,'Channel widths set to PHA widths, SPEX SHERB standard.'

;save the current arguments in common to be able to report them
ndet_used = ndet
en_used = en
chan_used = chan
w64_used = width64
spec_lld_used = spec_lld
error=0


end
