; +
; NAME: 
;   inms_make_ion_spectra - determines the ion species abundances from raw counts
;
pro inms_make_ion_spectra,  axRawSpectra, $ ;; (i) the input spectra 
                            axIonSpectra, $ ;; (o) the resulting ion abundances  
                            test=test,    $ ;; (i) inhibits sensitivity adjustment
                            noqlens=noqlens, $ ;; (i) inhibits sensitivity adjustment
                            noangle=noangle, $ ;; (i) inhibits sensitivity adjustment
                            debug=debug
; ARGUMENTS:
;  OUTPUTS:
;   axIonSpectra - The resulting array of ion abundance spectra structures,
;                  see inms_define_xSpecRec for details. The count fields 
;                  contain the ion abundances in cm^(-3). Returns a scalar zero
;                  if the input parameters are incorrect in number or type.
;  INPUTS:
;   axRawSpectra -  An array of spectra records containing the ion counts to
;                   be converted to abundances. 
;   /test        -  When set the program assumes the sensitivity is exactly
;                   the value obtained during pre-launch FM calibration. No
;                   adjustments are made for quad lens mis-tuning or off-axis
;                   pointing. Equivalent to setting /noqlens and /noangle  
;   /noqlens     -  When set the program does not apply the adjustment for
;                     quad lens miss-tuning 
;   /noangle     -  When set the program does not apply the adjustment for
;                     off-axis pointing
;
; METHOD:
;     Apply calibration factor to raw spectral counts to obtain ion densities
;     Note that the ion densities are not corrected for ram angle
;
; CHANGES:
;   28 Jul 2006   D.A. Gell   Initial coding
;   11 Sep 2006   D.A. Gell   Corrected ion abundance calculation.  Arrays
;                               were of improper shape.
;   20-Sep-2006  DAG          Use error handler and inms_post_message
;    4-Dec-2006   D.A. Gell   Pass date to inms_ion_sensitivity
;                               and supply /test  keyword  
;    4-Jan-2007   D.A. Gell   Add special handling for ion data collection
;                               interspersed with energy scans
;                             Reversed order of arguments to confirm with other
;                                routines usage. 
;    8-Jan-2007   D.A. Gell   Added angle response factor (inms_ion_transmission) 
;    9-Jan-2007   D.A. Gell   correct typo in call to inms_ion_transmission
;   17-Jan-2007   D.A. Gell   wrong switch supplied to inms_ion_transmission to
;                                 inhibit quad lens tuning adjustment
;-
;-------------------------------------------------------------------------------

    ;; establish error handler
    ;;
    bDebugSw = keyword_set(debug)
    nError = 0
    catch, nError
    if nError ne 0 then begin
        catch, /cancel
        inms_post_message, traceback=bDebugSw, console=inms_is_image() or bDebugSW
        if bDebugSw then stop
        return
    endif 

    ;;
    ;;validate arguments

    axIonSpectra = 0            ;; assume failure

    if n_params() ne 2 then begin
        message,  'You must supply an input raw spectra and a variable'$
                   + ' to receive the result'
    endif 
    if not inms_validate_spectra_data(axRawSpectra) then begin
        message, 'The supplied input structure does not appear to be a '$
                  + 'valid spectra structure'
    endif 
    if not arg_present(axIonSpectra) then begin
        message, 'You must supply a writeable variable to receive'$
                  +' the result abundance spectra'
    endif

    ;; check switches
    bNoQLens = 0
    bNoAngle = 0  
    if keyword_set(test) then begin
        bNoQLens = 1
        bNoAngle = 1  
    endif	
    if keyword_set(noQLens) then bNoQLens=1	 
    if keyword_set(noAngle) then bNoAngle=1

    ;; make a copy of the input specra array to fill ancilliary quantities

    axIonSpectra            = axRawSpectra
    axIonSpectra.sType      = 'Ion Abundance Spectra'
    axIonSpectra.anC1Counts = fltarr(n_elements(axIonSpectra[0].anMassBins))
    axIonSpectra.anC1Error  = axIonSpectra.anC1Counts
    axIonSpectra.anC2Counts = axIonSpectra.anC1Counts
    axIonSpectra.anC2Error  = axIonSpectra.anC1Counts

    ;; check for exceptions in ion calibration

    ;;  T17 has ion measurements with velocity compensation controlled
    ;;  by a switching table based on pre-T5 coefficients.

    if strcmp(axIonSpectra[0].sFirstDOYtime, '2006-282', 8) eq 1 then begin
        ;; this is T17 data
        ;;  are ion measurements interspersed with energy scans?

        anIDX=where(axIonSpectra.nCycTable ne 56, nOK, $
                    complement=an56Idx, nComplement=n56count) 
        anSens = fltarr(n_elements(axIonSpectra[0].anMassBins),$
                        n_elements(axIonSpectra))

        if nOK gt 0 then begin
            anSens[*,anIDX]= inms_ion_sensitivity(axIonSpectra[anIDX].anMassBins, $
                                                  axIonSpectra[anIDX].nSpeed, $
                                                  axIonSpectra[0].sFirstDOYtime, $
                                                  test=bNoQlens, debug=debug)
        endif

        if n56count gt 0 then begin
            anSens[*,an56IDX]= inms_ion_sensitivity(axIonSpectra[an56IDX].anMassBins, $
                                                    axIonSpectra[an56IDX].nSpeed, $
                                                    axIonSpectra[0].sFirstDOYtime, $ 
                                                    /escan, $
                                                    test=bNoQlens, debug=debug)
        endif

    endif 

    ;; compute sensitivities (089-0062)
    anSens = inms_ion_sensitivity(axIonSpectra.anMassBins, $
                                  axIonSpectra.nSpeed, $
                                  axIonSpectra[0].sFirstDOYtime, $
                                  test=bNoQlens, debug=debug)

    ;; compute effect of angle on transmission
    if bNoAngle eq 1 then  begin
        anTrans = 1.0
    endif else begin
        anTrans = inms_ion_transmission(axIonSpectra.anMassBins,$
                                        axIonSpectra.nVelx, $
                                        axIonSpectra.nVely, $
                                        axIonSpectra.nVelz,debug=debug) > 0.0001  
    endelse 

    ;; form matrix used to ensure that the denominator of
    ;;  the following expressions are the same size and shape 
    ;;  as the counts array
    anDist = replicate(1.0, n_elements(axIonSpectra[0].anMassBins))

    ;; densities and standard deviations
    axIonSpectra.anC1counts = 1e-5 * axRawSpectra.anC1counts         $
                               /  (anDist # (axRawSpectra.nIntPeriod $
                                   * axRawSpectra.nSpeed * anTrans)  $
                                   * anSens )
    axIonSpectra.anC1error = 1e-5 * axRawSpectra.anC1error           $
                              /  (anDist # (axRawSpectra.nIntPeriod  $
                                  * axRawSpectra.nSpeed * anTrans)   $
                                  * anSens )
    axIonSpectra.anC2counts = 1e-5 * axRawSpectra.anC2counts         $
                               /  (anDist # (axRawSpectra.nIntPeriod $
                                   * axRawSpectra.nSpeed * anTrans)  $
                                   * anSens )
    axIonSpectra.anC2error = 1e-5 * axRawSpectra.anC2error          $
                              /  (anDist # (axRawSpectra.nIntPeriod $
                                  * axRawSpectra.nSpeed * anTrans)  $
                                  * anSens )

end


