next up previous contents
Next: Extending the Data Structure Up: Adding a New Fitter Previous: Step 7:- FT1_FITTER_TRM.FOR   Contents

Step 8:- FT1_FIT_EVENT.FOR

The real guts of the FT1 fitter. It does the maths and calls subroutines as required.

*file member=ft1_fit_event library=snoman language=fortran77
*file                                         date=24:Nov:1994
 
      subroutine ft1_fit_event(iretc)
 
                      :
                      :
                      :
                    HEADER
                      :
                      :
                      :
 
*     Local Variable Declarations:-
*     ===========================
 
      integer           I_FIT_MASK_BIT
      parameter        (I_FIT_MASK_BIT = KPF_FT_MASK + KFT_USER1)
 
      integer           num_pmt_avail , num_pmt_used ,
     +                  i_pmt_dr_max , i_pmt , i_pmt_id
      real              sum_x , sum_y , sum_z , sum_t , sum_dr2 ,
     +                  fit_xyz(3) , fit_r , dr , dr_max , rms ,
     +                  vdist
 
                                                                  --
      iretc = KSU_NO_DATA                                           |
                                                                    |
***   If no EV quit with KSU_NO_DATA.                               |
                                                                    |
      if (lev .le. 0) return                                        |
                                                                    |
***   Create FT1, also creating FT if necessary, but quit if not    |
***   not enough data to start fit.                                 |
                                                                    |
      lft = lq(lev - KEV_FT)                                        1
      if (lft .eq. 0)                                               |
     +   call mzlift( IDIV_EVENT , lft , lev , -KEV_FT , mmft , 0 ) |
      call mzlift( IDIV_EVENT , lft1 , lft , -KFT_FT1 , mmft1 , 0 ) |
      iq(lft1 + KFTX_METHOD) = KFT_USER1                            |
      iq(lft1 + KFTX_RETC)   = iretc                                |
                                                                    |
      lpf = lq(lev - KEV_PF)                                        |
      lpn = lq(lev - KEV_PN)                                        |
      lpt = lq(lev - KEV_PT)                                        |
      if (lpf .eq. 0 .or. lpn .eq. 0 .or. lpt .eq. 0) return        |
                                                                  --
      num_pmt_avail = 0                                           --
      sum_x         = 0.                                            |
      sum_y         = 0.                                            2
      sum_z         = 0.                                            |
      sum_t         = 0.                                            |
                                                                  --
      do i_pmt = 1 , iq(lpf-1)                                    --
*       The FT1 mask bit ought not to be set, but just in case...   |
        iq(lpf + i_pmt) = ibclr( iq(lpf + i_pmt) , I_FIT_MASK_BIT ) |
        if (.not. btest( iq(lpf + i_pmt) , KPF_DIS ) ) then         |
          num_pmt_avail = num_pmt_avail + 1                         |
          i_pmt_id      = iq(lpn + i_pmt)                           |
          sum_x         = sum_x + rge_pmt_xyz(1,i_pmt_id)           |
          sum_y         = sum_y + rge_pmt_xyz(2,i_pmt_id)           3
          sum_z         = sum_z + rge_pmt_xyz(3,i_pmt_id)           |
          sum_t         = sum_t + rq(lpt + i_pmt)                   |
        endif                                                       |
      enddo                                                         |
                                                                    |
      if (num_pmt_avail .lt. icons(ldtft1 + KTFT1_MIN_PMT) ) return |
                                                                  --
                                                                  --
***   Fit vertex and iterate dropping points until RMS acceptable   |
***   or too many points dropped.                                   |
                                                                    |
      num_pmt_used = num_pmt_avail                                  |
      iretc        = KSU_NOOP                                       |
                                                                    |
      do while (iretc .eq. KSU_NOOP)                                |
                                                                    |
**      Compute fit vertex as the C of G. of all PMT hits.          |
                                                                    |
        fit_xyz(1) = sum_x / num_pmt_used                           |
        fit_xyz(2) = sum_y / num_pmt_used                           |
        fit_xyz(3) = sum_z / num_pmt_used                           4
                                                                    |
**      Find mean radial distance from fit to each hit.             |
                                                                    |
        fit_r = 0.                                                  |
        do i_pmt = 1 , iq(lpf-1)                                    |
          if (      .not. btest( iq(lpf + i_pmt) , KPF_DIS )        |
     +        .and. .not. btest( iq(lpf + i_pmt) , I_FIT_MASK_BIT ) |
     +       ) then                                                 |
            i_pmt_id = iq(lpn + i_pmt)                              |
            fit_r= fit_r + vdist(fit_xyz,rge_pmt_xyz(1,i_pmt_id),3) |
          endif                                                     |
        enddo                                                       |
        fit_r = fit_r / num_pmt_used                                |
                                                                    |
**      Find fit RMS and worst residual.                            |
                                                                    |
        sum_dr2 = 0.                                                |
        dr_max  = 0.                                                |
        do i_pmt = 1 , iq(lpf-1)                                    |
          if (      .not. btest( iq(lpf + i_pmt) , KPF_DIS )        |
     +        .and. .not. btest( iq(lpf + i_pmt) , I_FIT_MASK_BIT ) |
     +       ) then                                                 |
            i_pmt_id = iq(lpn + i_pmt)                              |
            dr = vdist(fit_xyz,rge_pmt_xyz(1,i_pmt_id),3) - fit_r   |
            sum_dr2 = sum_dr2 + dr**2                               |
            if (abs(dr) .gt. dr_max) then                           |
              dr_max       = abs(dr)                                |
              i_pmt_dr_max = i_pmt                                  |
            endif                                                   |
          endif                                                     |
        enddo                                                       |
        rms = sqrt( sum_dr2  / num_pmt_used )                       |
                                                                    |
**      If fit RMS O.K., accept fit.                                4
                                                                    |
        if (RMS .le. rcons(ldtft1 + KTFT1_MAX_RMS) ) then           |
          iretc = KSU_OK                                            |
                                                                    |
**      If enough hits left, drop worst and continue.               |
                                                                    |
        elseif (num_pmt_used .gt. icons(ldtft1+KTFT1_MIN_PMT)) then |
          i_pmt           = i_pmt_dr_max                            |
          i_pmt_id        = iq(lpn + i_pmt)                         |
          num_pmt_used    = num_pmt_used - 1                        |
          sum_x           = sum_x - rge_pmt_xyz(1,i_pmt_id)         |
          sum_y           = sum_y - rge_pmt_xyz(2,i_pmt_id)         |
          sum_z           = sum_z - rge_pmt_xyz(3,i_pmt_id)         |
          sum_t           = sum_t - rq(lpt + i_pmt)                 |
          iq(lpf + i_pmt) = ibset(iq(lpf + i_pmt), I_FIT_MASK_BIT)  |
                                                                    |
**      Otherwise fail.                                             |
                                                                    |
        else                                                        |
          iretc = KSU_FAILED                                        |
                                                                    |
        endif                                                       |
                                                                    |
      enddo                                                       --
                                                                  --
      iq(lft1 + KFTX_RETC)      = iretc                             |
      if (iretc .ne. KSU_OK) return                                 |
                                                                    |
***   Fit O.K.; complete FT1, store results in an FT1V and FT1T and |
***   point currently selected FTx to FT1.                          |
                                                                    |
                                                                    |
      iq(lft1 + KFTX_PMT_AVAIL) = num_pmt_avail                     |
      iq(lft1 + KFTX_PMT_USED)  = num_pmt_used                      |
      iq(lft1 + KFTX_ITER)      = num_pmt_avail - num_pmt_used      |
*     At least this word is meaningful!                             |
      rq(lft1 + KFTX_PROB)      = 0.0                               |
*     Store data in fitter specific extension.                      5
      rq(lft1 + KFT1_RMS)       = RMS                               |
                                                                    |
      call mzlift( IDIV_EVENT, lft1v, lft1, -KFTX_FTXV, mmft1v, 0 ) |
      rq(lft1v + KFTXV_X) = sum_x / num_pmt_used                    |
      rq(lft1v + KFTXV_Y) = sum_y / num_pmt_used                    |
      rq(lft1v + KFTXV_Z) = sum_z / num_pmt_used                    |
      rq(lft1v + KFTXV_T) = sum_t / num_pmt_used                    |
                                                                    |
      call mzlift(IDIV_EVENT, lft1t, lft1v, -KFTXV_FTXT, mmft1t, 0) |
      rq(lft1t + KFTXT_U) = 0.57735                                 |
      rq(lft1t + KFTXT_V) = 0.57735                                 |
      rq(lft1t + KFTXT_W) = 0.57735                                 |
                                                                    |
      lq(lft - KFT_FTX_CUR) = lft1                                  |
                                                                    |
      return                                                        |
      end                                                           |
                                                                  --
*endfile member=ft1_fit_event

To facilitate explanation the code above has been split into 5 parts as indicated by the bracketing.

PART 1: Here a few checks are made, pointers set up and the FT1 bank is lifted. The user should not change anything.

PART 2: This is just some initialisation specific to this particular fitting method. It should be removed.

PART 3: This part comprises a loop over the hits (iq(lpf-1) holds the number of hits in the trigger as opposed to the number of hit PMTs). Users may find it useful to keep and modify this section, iq(lpn + N) holds the PMT ID of the Nth hit and the array rge_pmt_xyz holds the XYZ coordinates of all PMTs, with the time of the Nth hit being held in rq(lpt+ N). The variables sum_x, sum_y etc. are specific to this particular fitting method and can be discarded. The PF bank contains a set of flags for each hit and it is possible to set one of these flags so that the hit is not used by a particular fitter or to set another flag to discard it entirely for all fits. The second line within the loop carries out a check to see if a hit is to be discarded generally and the line above it clears all the PF flags that indicate discarding for this particular fitter. Notice also the check on the number of hits available at the end of this part using the titles bank address mnemonic set up in FT1_COM.INC.

PART 4: Here is the real mathematics of the fit. To describe this particular fitting method Nick West's comments are appropriate:

``Calling this fitter Micky Mouse would be deeply insulting to Walt Disney for there is no justification for the method, which attempts to find a point equidistant between all hit PMTs (ignoring time differences!), throwing away points with a large RMS to the fitted radial distance. However the fitter does demonstrate all the features that a real fitter must have.''
This part should be ripped out entirely and replaced by the fitting method of the user's choice with calls to subroutines if required and access to the PMT data having been already obtained in the loop of part 3. Two things should be noted, however. Firstly the setting of the bit flag towards the end of part 4 to discard a hit may be useful and secondly the call argument iretc should be set appropriately before returning to the calling routine FT1_FITTER. This is to enable run statistics to be printed by FT1_FITTER_TRM. The available values for iretc, which are defined in SU_MNEMONICS.INC, are:
KSU_OK Fit OK
KSU_NOOP No operation (output already exists)
KSU_UNSUPPORTED Unsupported operation
KSU_NO_DATA Not enough data to fit
KSU_TOO_MUCH_DATA Too much data to fit
KSU_FAILED Fit failed

PART 5: In this final part the output from the fitter is loaded into the data structure. See the FTX, FTXV and FTXT documentation refered to in the BANK_FT1.INC section for the predefined slots and mnemonics. It is here also that the FT1 specific fit bank mnemonics that were defined in BANK_FT1.INC are used. Remember also to store each data word in the appropriate array iq or rq depending on whether it is integer or floating point. If a fit vertex or fit track bank is required it should be lifted with an MZLIFT call. As can be seen in the code above both are currently lifted and the call arguments do not need to be changed. The final line assigns to currently selected fitter to FT1 and should not be changed.


next up previous contents
Next: Extending the Data Structure Up: Adding a New Fitter Previous: Step 7:- FT1_FITTER_TRM.FOR   Contents
sno Guest Acct 2009-09-09