*file member=alt_eca_calib_channel library=snoman language=fortran
    *file date=6:Oct:2000
 <<<      subroutine alt_eca_calib_channel( ccc, cell,
         +                              q_lx, q_hl, q_hs, tim, mask, mode )
     
    *     Apply ECA calibration constants to a given channel
     
    *     Contact:  J.Cameron (Oxford).
     
    *     Parameters:-
    *     ==========
     
    *     ccc       in      Card/Crate/Channel
    *                       or -(Card/Crate/Channel+1) to uncalibrate
    *     cell      in      Cell number
    *     q_lx      in      Uncalibrated low gain charge
    *               out     Calibrated   low gain charge
    *     q_hl      in      Uncalibrated high gain long charge
    *               out     Calibrated   high gain long charge
    *     q_hs      in      Uncalibrated low gain long charge
    *               out     Calibrated   low gain long charge
    *     tim       in      Uncalibrated time
    *               out     Calibrated   time
    *     mask      in      Set of 1-bit flags. Meaning if set:-
    *                           B0  Calibrate q_lx
    *                           B1  Calibrate q_hl
    *                           B2  Calibrate q_hs
    *                           B3  Calibrate tim
    *     mode      in      KCAL_TCAL Calibrate/uncalibrate as set in
    *                                 the TCAL bank ( KCAL_TCAL is set
    *                                 in cal_com.inc )
    *                       or a two digit code eg 13
    *                       First digit- Charge
    *                          0       counts above pedastel
    *                          1       counts above intercept
    *                          2       linear charge correction
    *                          3       Old ECA - quadratic charge correction
    *                                  New ECA - linear charge correction
    *                          4       counts above pedastel for PCA
    *                       Second digit- Time
    *                          0       counts above pedastel
    *                          1       counts above intercept
    *                          2       Old ECA - linear time correction
    *                                  New ECA - full ECA time correction
    *                          3       full ECA time correction
    *                          4       full ECA time correction for PCA
     
    *     Note:    q_lx, q_hl, q_hs, ti must be reals on input!
     
     
    *     Common Block Access:-
    *     ===================
    *     (ignoring internal and environmental access)
     
    *     /CAL_CONST0/  in/out      *.
    *     /CAL_CONST1/  in/out      *.
    *     /MT/          in/out      Banks:  TCAL, Q1SL, Q1AV, Q2SL, Q2AV,
    *                                             Q3SL, Q3AV, TMSL, TMAV
    *                                             Q1SQ, Q2SQ, Q3SQ, TMSQ,
    *                                             Q1FL, Q2FL, Q3FL, TMFL,
    *                                             Q1SI, Q2SI, Q3SI, TMSI,
    *                                             Q1QC, Q2QC, Q3QC, TMQC,
    *                                             TMCC
     
    *     Specification:-
    *     =============
     
    * o   On first entry, load titles control bank TCAL.
     
    * o   Load titles banks for ECA and PCA calibration, selecting reference
    *     version (bank number 1000001) if dictated by TCAL.
     
    * o   On each entry, calibrate data as selected by mask using the calibration
    *     mode flags from the TCAL bank.
     
    *     Program Notes:-
    *     =============
     
    *     This is a utility that can be used from any software unit.  However,
    *     it uses calibration mode information from the control bank of CAL (TCAL).
     
    *     Revision History:-
    *     ================
     
    *     3.02  N. West     First version extracted from cal_calibration_ini
    *                       and cal_calibration_pmt.
    *           D. Wark     Change sign of charge for linear calibrations.
    *           D. Wark     Add mode for cubic T's and ped. corr. raw ADC Q's.
    *           D. Wark     Trap zero slopes.
    *           M. Thorman  Add another mode for linear T, ped corrected Q. For
    *                       linear T, use correct sign of slope and include offset.
    *           S. Biller   Re-dubbed as an alternate application of calibration
    *                       constants using files generated by older version of ECA
    *           S. Biller   TCAL, QTCA and CST0 now loaded previously
    *           S. Biller   Algorithm made more compact
    *                       and a negative CCC now results in an uncalibration
    *           N. West     Use -(CCC+1) to signal uncalibration to allow for ccc=0
    *                       Add support for reference constants.
    *           J. Cameron  Allow a more flexible numbering scheme in the TCAL bank.
    *           J. Cameron  Hardwire the uncalibration to go from counts above
    *                       pedastel to ADC counts for charges and from ECA ns
    *                       to ADC counts for time
    *           J. Cameron  Add mode to allow overriding the TCAL bank
    *	    N. Tagg     Bug fix, symptoms seen on linux systems.
    *           J. Cameron  Remove hardwired uncalibration mode.
    *                       Remove nint()s from uncalibration.
    *     4.01  J. Cameron  Get calibration mode from subroutine cal_mode.
    *                       Removed local modes.
    *                       Change -999 to KCAL_MODE (defined in cal_com.inc)
     
          IMPLICIT NONE
     
          INCLUDE 'id_errors.inc'
          INCLUDE 'mt_mnemonics.inc'
          INCLUDE 'su_mnemonics.inc'
          INCLUDE 'cal_com.inc'
          INCLUDE 'cal_const0.inc'
          INCLUDE 'cal_const1.inc'
          INCLUDE 'mt.inc'
          INCLUDE 'q_t_calib.inc'
          INCLUDE 'zunit.inc'
     
          real              c_fit(4)
          common /bcubefit/ c_fit
     
     
    *     Argument Declarations:-
    *     =====================
     
          integer           ccc, cell, mask, mode
          real              q_lx, q_hl, q_hs, tim
     
     
    *     Local Variable Declarations:-
    *     ===========================
     
          integer           loc, loc_lcn,map_ccc_lcn,n,
         +                  lnkfl,lnksq,lnkav,lnksi,lnksl,lnkqc,
         +                  i_bkno
          integer           qcal_mode,tcal_mode
          logical           first,btest,cal,uncal,requested_banks(10)
          real              aq, bq, cq, tim_org,eca_t_fn_dig,xx
     
          save              first,i_bkno
          data              first/ .true. /
          data              requested_banks/ .false. , .false. , .false. ,
         +                                   .false. , .false. , .false. ,
         +                                   .false. , .false. , .false. ,
         +                                   .false. /
     
     
    **    On every entry, calibrate data as required.
     
          cal=.true.
          uncal=.false.             ! See whether calibration
          if(ccc.lt.0) then         ! or uncalibration
            cal=.false.             ! is requested
            uncal=.true.
            ccc=-ccc-1
          endif
     
    **    On first entry, load required titles banks
     
          if ( first ) then
             first = .false.
     
    *        Select standard or reference set.
             i_bkno = 1
             if ( ICONS(LDTCAL+KTCAL_REF_CONSTS) .eq. 1 ) i_bkno = 1000001
     
    *        *      Translate the modes in TCAL bank
    *        *      into the following two numbers:
    c        tcal_mode        setting
    c        0       counts above pedastel
    c        1       counts above intercept
    c        2       linear time correction (old ECA)
    c        3       full ECA time correction
    c        qcal_mode        setting
    c        0       counts above pedastel
    c        1       counts above intercept
    c        2       linear charge correction
    c        3       quadratic charge correction (old ECA)
     
    *        Get the mode in the TCAL bank
             call cal_mode(qcal_mode,tcal_mode)
    *        provide the right charge and time for the pca
             if (qcal_mode.eq.4) qcal_mode=0
             if (tcal_mode.eq.4) tcal_mode=3
     
    ***      Check to see if the calibration mode is in the right limits
             if (qcal_mode.lt.0 .or. qcal_mode.gt.3 .or.
         +       tcal_mode.lt.0 .or. tcal_mode.gt.3 ) then
                if (qcal_mode.lt.0) qcal_mode=0
                if (qcal_mode.gt.3) qcal_mode=3
                if (tcal_mode.lt.0) tcal_mode=0
                if (tcal_mode.gt.3) tcal_mode=3
                call add_warning(' CAL: The calibration requested in the'//
         +           ' TCAL bank is not provided by the old ECA')
             endif
          endif
     
    *     Set the calibration mode according to mode request
          if (mode.eq.KCAL_TCAL) then
             call cal_mode(qcal_mode,tcal_mode)
    *        provide the right charge and time for the pca
             if (qcal_mode.eq.4) qcal_mode=0
             if (tcal_mode.eq.4) tcal_mode=3
          else
             qcal_mode=mode/10
             tcal_mode=mode-qcal_mode*10
    ***      Check to see if the calibration mode is in the right limits
             if (qcal_mode.lt.0 .or. qcal_mode.gt.3 .or.
         +        tcal_mode.lt.0 .or. tcal_mode.gt.3 ) then
                if (qcal_mode.lt.0) qcal_mode=0
                if (qcal_mode.gt.3) qcal_mode=3
                if (tcal_mode.lt.0) tcal_mode=0
                if (tcal_mode.gt.3) tcal_mode=3
                call add_warning(' CAL: The calibration requested in the'//
         +           ' TCAL bank is not provided by the old ECA')
             endif
          endif
     
    c     Get charge pedastel and quality flag
          if (qcal_mode.eq.0.and.(.not.requested_banks(1))) then
             requested_banks(1)=.false.
             LAQ1AV(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1AV',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1AV , KSU_UCL )
             LAQ2AV(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2AV',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2AV , KSU_UCL )
             LAQ3AV(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3AV',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3AV , KSU_UCL )
             LAQ1FL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1FL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1FL , KSU_UCL )
             LAQ2FL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2FL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2FL , KSU_UCL )
             LAQ3FL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3FL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3FL , KSU_UCL )
          endif
    c     Get charge slope intercepts
          if (qcal_mode.ge.1.and.(.not.requested_banks(2))) then
             requested_banks(2)=.false.
             LAQ1SI(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1SI',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1SI , KSU_UCL )
             LAQ2SI(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2SI',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2SI , KSU_UCL )
             LAQ3SI(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3SI',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3SI , KSU_UCL )
          endif
    c     Get charge slopes
          if (qcal_mode.ge.2.and.(.not.requested_banks(3))) then
             requested_banks(3)=.false.
             LAQ1SL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1SL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1SL , KSU_UCL )
             LAQ2SL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2SL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2SL , KSU_UCL )
             LAQ3SL(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3SL',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3SL , KSU_UCL )
          endif
    c     Get quadratic charge terms
          if (qcal_mode.eq.3.and.(.not.requested_banks(4))) then
             requested_banks(4)=.false.
             LAQ1QC(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1QC',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1QC , KSU_UCL )
             LAQ2QC(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2QC',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2QC , KSU_UCL )
             LAQ3SQ(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3QC',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3QC , KSU_UCL )
          endif
    c     Get charge quality integer
          if (qcal_mode.ge.1.and.(.not.requested_banks(5))) then
             requested_banks(5)=.false.
             LAQ1SQ(8) = 0
             CALL MT_REQUEST_TITLES( 'Q1SQ',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ1SQ , KSU_UCL )
             LAQ2SQ(8) = 0
             CALL MT_REQUEST_TITLES( 'Q2SQ',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ2SQ , KSU_UCL )
             LAQ3SQ(8) = 0
             CALL MT_REQUEST_TITLES( 'Q3SQ',  i_bkno,  KMTT_COMPULSORY,
         +        LAQ3SQ , KSU_UCL )
          endif
     
    c     Get time pedastel and quality flag
          if (tcal_mode.eq.0.and.(.not.requested_banks(6))) then
             requested_banks(6)=.false.
             LATMAV(8) = 0
             CALL MT_REQUEST_TITLES( 'TMAV',  i_bkno,  KMTT_COMPULSORY,
         +        LATMAV , KSU_UCL )
             LATMFL(8) = 0
             CALL MT_REQUEST_TITLES( 'TMFL',  i_bkno,  KMTT_COMPULSORY,
         +        LATMFL , KSU_UCL )
          endif
    c     Get time intercept
          if (tcal_mode.ge.1.and.(.not.requested_banks(7))) then
             requested_banks(7)=.false.
             LATMSI(8) = 0
             CALL MT_REQUEST_TITLES( 'TMSI',  i_bkno,  KMTT_COMPULSORY,
         +        LATMSI , KSU_UCL )
          endif
    c     Get linear time term
          if (tcal_mode.ge.2.and.(.not.requested_banks(8))) then
             requested_banks(8)=.false.
             LATMSL(8) = 0
             CALL MT_REQUEST_TITLES( 'TMSL',  i_bkno,  KMTT_COMPULSORY,
         +        LATMSL , KSU_UCL )
          endif
    c     Get quadratic and cubic time terms
          if (tcal_mode.eq.3.and.(.not.requested_banks(9))) then
             requested_banks(9)=.false.
             LATMQC(8) = 0
             CALL MT_REQUEST_TITLES( 'TMQC',  i_bkno,  KMTT_COMPULSORY,
         +        LATMQC , KSU_UCL )
             LATMCC(8) = 0
             CALL MT_REQUEST_TITLES( 'TMCC',  i_bkno,  KMTT_COMPULSORY,
         +        LATMCC , KSU_UCL )
          endif
    c     Get time quality integer
          if (tcal_mode.ge.1.and.(.not.requested_banks(10))) then
             requested_banks(10)=.false.
             LATMSQ(8) = 0
             CALL MT_REQUEST_TITLES( 'TMSQ',  i_bkno,  KMTT_COMPULSORY,
         +        LATMSQ , KSU_UCL )
          endif
     
    *     Get index into banks by converting to logical circuit no and adding
    *     one (as lcn starts at zero.
          loc_lcn = map_ccc_lcn(ccc)
     
    *     Change to allow for 16 cells
          loc = 16*(loc_lcn) + cell + 1
     
          do N=1,3
            if(.not.btest(mask,N-1)) goto 100
            if(N.eq.1) then          ! Calibrate low gain charge
              lnkfl=ldq3fl
              lnksq=ldq3sq
              lnkav=LDQ3AV
              lnksi=LDQ3SI
              lnksl=LDQ3SL
              lnkqc=LDQ3QC
              XX=Q_LX
            elseif(N.eq.2) then      ! Calibrate high gain long charge
              lnkfl=ldq2fl
              lnksq=ldq2sq
              lnkav=LDQ2AV
              lnksi=LDQ2SI
              lnksl=LDQ2SL
              lnkqc=LDQ2QC
              XX=Q_HL
            elseif(N.eq.3) then      ! Calibrate high gain short charge
              lnkfl=ldq1fl   ! pedastel quality flag
              lnksq=ldq1sq   ! slope quality flag
              lnkav=LDQ1AV   ! pedastel value
              lnksi=LDQ1SI   ! intercept
              lnksl=LDQ1SL   ! linear term
              lnkqc=LDQ1QC   ! quadratic term
              XX=Q_HS
            endif
            if(uncal.and.XX.eq.-9999.) goto 100
            if( (qcal_mode.eq.0 .and. icons(lnkfl+loc).ne.0) .or.
         +      icons(lnksq+loc).ne.0 ) then
              XX= -9999.
              call ztell(IDZT_CAL_MISSING_CAL,0)
            else
              if(cal) then
                if(qcal_mode.eq.0) then
                  XX=XX-RCONS(LNKAV+LOC)
                else
                  XX=XX-RCONS(LNKSI+LOC)
                endif
              endif
              if(qcal_mode.eq.2) then
                if(abs(RCONS(LNKSL+LOC)).gt.0.1) then
                  if(cal) XX = XX/RCONS(LNKSL+LOC)
                  if(uncal) XX = XX*RCONS(LNKSL+LOC)
                else
                  XX = -9999.
                  call ztell(idzt_cal_zero_slope,0)
                endif
              else if(qcal_mode.eq.3) then
                if(abs(RCONS(LNKSL+LOC)).lt.0.1) then
                  XX = -9999.
                  call ztell(idzt_cal_zero_slope,0)
                else
                  if(cal) then
                    cq = -XX
                    bq = RCONS(LNKSL+LOC)
                    aq = RCONS(LNKQC+LOC)
                    XX = bq**2 - 4.*aq*cq
                    if(XX .lt. 0.) then
                      XX = 0.
                    else
                      XX = 2*cq/(-bq - sqrt(XX))
                    endif
                  elseif(uncal) then
                    XX=RCONS(LNKSL+LOC)*XX+RCONS(LNKQC+LOC)*XX*XX
                  endif
                endif
              endif
              if(uncal) then
                if(qcal_mode.eq.0) then
                  XX=XX+RCONS(LNKAV+LOC)
                else
                  XX=XX+RCONS(LNKSI+LOC)
                endif
              endif
            endif
            if(N.eq.1) Q_LX=XX
            if(N.eq.2) Q_HL=XX
            if(N.eq.3) Q_HS=XX
     100    continue
          end do
     
    **    Calibrate time
     
          if ( btest( mask, 3 ) ) then
     
            tim_org = tim
            if(uncal.and.tim.eq.-9999.) return
            if(uncal) tim=rcons(ldtcal+ktcal_time_offset)-tim
            if((tcal_mode.eq..0.and.icons(ldtmfl+loc).ne.0) .or.
         +    icons(ldtmsq+loc).ne.0) then
                TIM = -9999.
                call ztell(IDZT_CAL_MISSING_CAL,0)
            else
                if(tcal_mode.eq.0) then
                  if(cal) TIM = TIM-RCONS(LDTMAV+LOC)
                  c_fit(1) = RCONS(LDTMAV+LOC)
                else
                  if(cal) TIM = TIM-RCONS(LDTMSI+LOC)
                  c_fit(1) = RCONS(LDTMSI+LOC)
                endif
                if(tcal_mode.ge.2) then
                  if(abs(RCONS(LDTMSL+LOC)).gt.1.) then
                    if(cal) TIM = TIM/RCONS(LDTMSL+LOC)
                    if(uncal) TIM = TIM*RCONS(LDTMSL+LOC) + c_fit(1)
                  else
                    TIM = -9999.
                    call ztell(idzt_cal_zero_slope,0)
                  endif
                else if(tcal_mode.ge.3) then
                  c_fit(2) = RCONS(LDTMSL+LOC)
                  c_fit(3) = RCONS(LDTMQC+LOC)
                  c_fit(4) = RCONS(LDTMCC+LOC)
                  if(cal) TIM = ECA_T_FN_DIG(tim_org)
                  if(uncal) TIM=c_fit(1)+c_fit(2)*TIM+
         +                      c_fit(3)*TIM*TIM+c_fit(4)*TIM*TIM*TIM
                endif
                if(cal.and.TIM.gt.-9998) then
                   if (tcal_mode.ge.2) then
                     TIM = rcons(ldtcal+ktcal_time_offset) - TIM
                   else
                     TIM = -TIM
                   endif
                endif
            endif
     
          endif
     
          RETURN
     
          END
    *ENDFILE MEMBER=ALT_ECA_CALIB_CHANNEL