[KLOE] [Offline Doc] [TRK Files]

Track Reconstruction Library

vtxfin_lib.kloe


c=======================================================================
      SUBROUTINE VTXFIT
c=======================================================================
c
c This is the driving routine of the vertex fitting package ;
c it looks for vertex candidates and calls the minimization routine.
c If the fit is succsefull the candidate vertex is temporary stored
c in routine VTXCAN for later use (in VTXMERG).
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      22-9-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c      
c External declarations
c

c
c Local declarations
c
      INTEGER Iextrvc, Iextrbp, iii, Iextr, Ipoinvc(20), Ipoinbp(20)
      INTEGER ifi, ise, Ilist(2), IERRCR, Ifit, Nflag
      INTEGER itk, ktk, Nreg, Ntrfit, i
      REAL    Qfi, Qse, Xint(3), Xcn(3), Chisq, Xstor(3)
      REAL    X1F, Y1F, Z1F, X1L, Y1L, Z1L, X2F, Y2F ,Z2F, X2L, Y2L, Z2L
      REAL    D1F2F, Z1F2F, D1F2L, Z1F2L, D1L2F, Z1L2F, D1L2L, Z1L2L
      LOGICAL Tangent, Constr
      LOGICAL FlagIP(50)        ! common VTXFIT-VTXEXTR
      COMMON /VTXCLOSIP/ FlagIP
c
c=======================================================================
c
c Initialize variables
c
      Ntrfit = 2   ! Assume a "2 tracks fit" as default
      Nvxfit = 0     ! Number of fitted vertices
c
c ===================================================================
c
c Organize tracks according to their extrapolated inner point:
c IEXTRVC are the tracks whose innermost extrapolated point falls
c inside the Vertex Chamber region; although KLOE has not a Vertex
c Chamber (as now) this is the zone included between the inner DC and
c the BP walls
c IEXTRBP are the tracks whose innermost extrapolated point falls
c inside the Beam Pipe
c
      iextrvc = 0
      iextrbp = 0
      do iii = 1, TOTTRK
         IEXTR = IW(INDVWRK + VWRNCO*(iii-1) + VWREG)

         if (iextr.eq.NVC) then
            iextrvc = iextrvc+1
            ipoinvc(iextrvc) = iii

         elseif(iextr.gt.NVC) then
            iextrbp = iextrbp+1
            ipoinbp(iextrbp) = iii

         endif
      enddo
cmi
C
C === LOOK FOR VERTICES NOW ======================================
C
c =================================
c (1) start from vertices inside BP 
c =================================
c
c loop on first track

      do 200 ifi = 1, iextrbp-1

         QFI = SIGN(1.,
     +        RW(INDVWRK+VWRNCO*(IPOINBP(ifi)-1)+VWCUBI)) ! track charge

c check if track has already been used (unless it passes close to the
c Interaction Point; these tracks can be used for more than one vertex)

         if ( .not.FlagIP(IPOINBP(ifi)) .and.
     + IW(INDVWRK+VWRNCO*(IPOINBP(ifi)-1)+VWFLF).eq.FITGOLD) goto 200

c loop on second track 

         do 180 ise = iextrbp, ifi+1, -1

            QSE = SIGN(1.,
     +           RW(INDVWRK+VWRNCO*(IPOINBP(ise)-1)+VWCUBI)) ! track charge

c Check total charge (must be zero). 

            if ( abs(QSE+QFI) .gt. 0.5 ) goto 180

c check if track has already been used (unless it passes close to the
c Interaction Point; these tracks can be used for more than one vertex)

            if ( .not.FlagIP(IPOINBP(ise)) .and.
     + IW(INDVWRK+VWRNCO*(IPOINBP(ise)-1)+VWFLF).eq.FITGOLD) goto 180
c
           ILIST(1) = IPOINBP(ifi)*ISWMBACK
           ILIST(2) = IPOINBP(ise)*ISWMBACK
           Nreg = 3
c
           call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 180

c call fitting routine with two tracks 
c
c if the tracks are parallel then:
c 1 - assume that they come from the origin (K+K- or Bhabha ...)
c
           if ( TANGENT ) then
              CONSTR = TANGENT
              do i = 1, 3
                 xstor(i) = XINT(i)
                 XCN(i) = 0.
                 XINT(i) = 0.
              enddo
           endif
c
c call minimization procedure
c
           NFLAG = 1            ! convergence occurred in loop (1)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
c
c if (1) fails then:
c 2 - fix the constraint at the crossing point
c
           if (IFIT.ne.FITGOLD .and. TANGENT) then
              XCN(1) = xstor(1)
              XCN(2) = xstor(2)
              XCN(3) = xstor(3)
              XINT(1) = xstor(1)
              XINT(2) = xstor(2)
              XINT(3) = xstor(3)
              CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           endif
           CONSTR = .false.
c
 180    continue
 200  continue
C
C ====================================================================
C
c =================================
c (2) now vertices in VC region
c =================================
c
c loop on first track; it has to be of type IEXTRVC

      do 201 ifi = 1, iextrvc

         QFI = SIGN(1.,
     +        RW(INDVWRK+VWRNCO*(IPOINVC(ifi)-1)+VWCUDC)) ! track charge

c check if the track has aready been used


            if ( .not.FlagIP(IPOINVC(ifi)) .and.
     + IW(INDVWRK+VWRNCO*(IPOINVC(ifi)-1)+VWFLF).eq.FITGOLD) goto 201

c loop on second track: it can be either of type IEXTRVC or IEXTRBP

c first pass: IEXTRVC track
         do 181 ise = 1, ifi-1

            QSE = SIGN(1.,
     +           RW(INDVWRK+VWRNCO*(IPOINVC(ise)-1)+VWCUDC)) ! track charge
            if ( abs(QSE+QFI) .gt. 1. ) goto 181


            if ( .not.FlagIP(IPOINVC(ise)) .and.
     + IW(INDVWRK+VWRNCO*(IPOINVC(ise)-1)+VWFLF).eq.FITGOLD) goto 181
c
            ILIST(1) = IPOINVC(ifi)*ISWMBACK
            ILIST(2) = IPOINVC(ise)*ISWMBACK
            Nreg = 2
c
           call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 181

c call fitting routine with two tracks 
cmi
cmi Apply a constrained fit if two tangents are parallel
cmi         ===============
cmi
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 2            ! convergence occurred in loop (2)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.
c
 181    continue

c second pass: IEXTRBP tracks
         do 182 ise = 1, iextrbp

            QSE = SIGN(1.,
     +           RW(INDVWRK+VWRNCO*(IPOINBP(ise)-1)+VWCUBI)) ! track charge
            if ( abs(QSE+QFI) .gt. 1. ) goto 182

c check if track has already been used (unless it passes close to the
c Interaction Point; these tracks can be used for more than one vertex)

            if ( .not.FlagIP(IPOINBP(ise)) .and.
     + IW(INDVWRK+VWRNCO*(IPOINBP(ise)-1)+VWFLF).eq.FITGOLD) goto 182
c
            ILIST(1) = IPOINVC(ifi)*ISWMBACK
            ILIST(2) = IPOINBP(ise)*ISWMBACK
            Nreg = 2            ! Vertex in VC region
c
           call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 182

c call fitting routine with two tracks 
cmi
cmi Apply a constrained fit if two tangents are parallel - MI sep 97
cmi         ===============
cmi
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 2            ! convergence occurred in loop (2)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.
c
 182    continue

 201  continue
C
C ======================================================================
C
c =================================
c (3) now vertices in DC region
c =================================
C
c In this section ALL tracks are combined to look for vertices. The 
c distance, in r-phi and in z, of the First points, Last points and
c First-to-Last points are evaluated;  a fit is attempted if DeltaR<RCUTM
c and DeltaZ<ZCUTM .  A succesfull fit in previous sections is treated
c by putting Ztrack to a fake value, unless the track passes close 
c to the IP (FlagIP.eq..true.).
c 
      do 85 itk = 1, TOTTRK-1

         QFI = SIGN(1.,RW(INDVWRK+VWRNCO*(itk-1)+VWCUFH))   ! track charge
         Z1F = 999.
         Z1L = 999.
         if ( IW(INDVWRK+VWRNCO*(itk-1)+VWFLF).ne.FITGOLD .or.
     +        (FlagIP(itk) .and.
     +       IW(INDVWRK+VWRNCO*(itk-1)+VWFLF).eq.FITGOLD) ) then
            X1F = RW(INDVWRK+VWRNCO*(itk-1)+VWXFH)
            Y1F = RW(INDVWRK+VWRNCO*(itk-1)+VWYFH)
            Z1F = RW(INDVWRK+VWRNCO*(itk-1)+VWZFH)
         endif
         if ( IW(INDVWRK+VWRNCO*(itk-1)+VWFLL).ne.FITGOLD ) then
            X1L = RW(INDVWRK+VWRNCO*(itk-1)+VWXLH)
            Y1L = RW(INDVWRK+VWRNCO*(itk-1)+VWYLH)
            Z1L = RW(INDVWRK+VWRNCO*(itk-1)+VWZLH)
         endif
c
         do 82 ktk = ITK+1, TOTTRK

            QSE = SIGN(1.,RW(INDVWRK+VWRNCO*(ktk-1)+VWCUFH)) ! track charge
            Z2F = -999.
            Z2L = -999.
            if ( IW(INDVWRK+VWRNCO*(ktk-1)+VWFLF).ne.FITGOLD .or.
     +        (FlagIP(ktk) .and.
     +       IW(INDVWRK+VWRNCO*(ktk-1)+VWFLF).eq.FITGOLD) ) then
               X2F = RW(INDVWRK+VWRNCO*(ktk-1)+VWXFH)
               Y2F = RW(INDVWRK+VWRNCO*(ktk-1)+VWYFH)
               Z2F = RW(INDVWRK+VWRNCO*(ktk-1)+VWZFH)
            endif
            if ( IW(INDVWRK+VWRNCO*(ktk-1)+VWFLL).ne.FITGOLD ) then
               X2L = RW(INDVWRK+VWRNCO*(ktk-1)+VWXLH)
               Y2L = RW(INDVWRK+VWRNCO*(ktk-1)+VWYLH)
               Z2L = RW(INDVWRK+VWRNCO*(ktk-1)+VWZLH)
            endif

c distances first-first first-last last-last

            D1F2F = sqrt( (X1F-X2F)**2+(Y1F-Y2F)**2 )
            Z1F2F = abs ( Z1F - Z2F )
            D1F2L = sqrt( (X1F-X2L)**2+(Y1F-Y2L)**2 )
            Z1F2L = abs ( Z1F - Z2L )
            D1L2F = sqrt( (X1L-X2F)**2+(Y1L-Y2F)**2 )
            Z1L2F = abs ( Z1L - Z2F )
            D1L2L = sqrt( (X1L-X2L)**2+(Y1L-Y2L)**2 )
            Z1L2L = abs ( Z1L - Z2L )

c check if tracks from same vertex ; if yes then try to fit and store
c the check is done with all 4 combinations First-First, First-Last, ...
c note that in these combinations I check also the charge: for 
c First-First and Last-Last the net charge has to be 0 (opposite sign)
c for First-Last combination the net charge has to be 2 (same sign)

c (1) 1 FIRST - 2 FIRST

            if ( D1F2F.lt.RCUTMI .and. Z1F2F.lt.ZCUTMI .and.
     +           abs(QFI+QSE).lt.1.                          ) then
c
c initial conditions for fitting routine (including swim direction)
c
               ILIST(1) = itk*ISWMBACK
               ILIST(2) = ktk*ISWMBACK
               Nreg = 1
               call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 82
c
c Apply a constrained fit if two tangents are parallel - MI sep 97
c         ===============
c
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 3            ! convergence occurred in loop (3)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.

c If minimization procedure converged then put fake Z value (=exclude
c this track end for next vertex searches); if fit is SILVER skip the
c rest of this section, but don't exclude other combinations (VTXMERG
c will eventually select the best one)

           if (IFIT.eq.FITGOLD) then
              Z1F =  999.
              Z2F = -999.
              goto 82
           elseif (IFIT.eq.FITSILVER) then
              goto 82
           endif
c
c (2) 1 FIRST - 2 LAST
c
        elseif ( D1F2L.lt.RCUTMI .and. Z1F2L.lt.ZCUTMI  .and.
     +           abs(QFI+QSE).gt.1.                        ) then
c
c initial conditions for fitting routine (including swim direction)
c
               ILIST(1) = itk*ISWMBACK
               ILIST(2) = ktk*ISWMFORW
               Nreg = 1
               call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 82
c
c Apply a constrained fit if two tangents are parallel - MI sep 97
c         ===============
c
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 3            ! convergence occurred in loop (3)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.

c If minimization procedure converged then put fake Z value (=exclude
c this track end for next vertex searches); if fit is SILVER skip the
c rest of this section, but don't exclude other combinations (VTXMERG
c will eventually select the best one)

           if (IFIT.eq.FITGOLD) then
              Z1F =  999.
              Z2L = -999.
              goto 82
           elseif (IFIT.eq.FITSILVER) then
              goto 82
           endif
c
c (3) 1 LAST - 2 FIRST

        elseif ( D1L2F.lt.RCUTMI .and. Z1L2F.lt.ZCUTMI  .and.
     +           abs(QFI+QSE).gt.1.                        ) then
c
c initial conditions for fitting routine (including swim direction)
c
               ILIST(1) = itk*ISWMFORW
               ILIST(2) = ktk*ISWMBACK
               Nreg = 1
               call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 82
c
c Apply a constrained fit if two tangents are parallel - MI sep 97
c         ===============
c
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 3            ! convergence occurred in loop (3)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.

c If minimization procedure converged then put fake Z value (=exclude
c this track end for next vertex searches); if fit is SILVER skip the
c rest of this section, but don't exclude other combinations (VTXMERG
c will eventually select the best one)

           if (IFIT.eq.FITGOLD) then
              Z1L =  999.
              Z2F = -999.
              goto 82
           elseif (IFIT.eq.FITSILVER) then
              goto 82
           endif
c
c (4) 1 LAST - 2 LAST

        elseif ( D1L2L.lt.RCUTMI .and. Z1L2L.lt.ZCUTMI  .and.
     +           abs(QFI+QSE).lt.1.                        ) then
c
c initial conditions for fitting routine (including swim direction)
c
               ILIST(1) = itk*ISWMFORW
               ILIST(2) = ktk*ISWMFORW
               Nreg = 1
               call VTXCRSS(Nreg,ILIST,XINT,IERRCR,TANGENT)

c don't look for vertex if VTXCRSS doesn't find any intersection nor a
c "tangency within cuts" (see VTXCRSS for this definition)
           if ((IERRCR.gt.1) .or.
     +         (IERRCR.eq.1 .and. .not. TANGENT)) goto 82
c
c Apply a constrained fit if two tangents are parallel - MI sep 97
c         ===============
c
           if ( TANGENT ) then
              CONSTR = TANGENT
              XCN(1) = XINT(1)
              XCN(2) = XINT(2)
              XCN(3) = XINT(3)
           endif
c
c call minimization procedure
c
           NFLAG = 3            ! convergence occurred in loop (3)
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.

c If minimization procedure converged then put fake Z value (=exclude
c this track end for next vertex searches); if fit is SILVER skip the
c rest of this section, but don't exclude other combinations (VTXMERG
c will eventually select the best one)

           if (IFIT.eq.FITGOLD) then
              Z1L =  999.
              Z2L = -999.
              goto 82
           elseif (IFIT.eq.FITSILVER) then
              goto 82
           endif
c
        endif
 82   continue
 85   continue
c
      return
      end
c

c=======================================================================
      INTEGER FUNCTION VTXINIT(iii,TRKDTFS)
c=======================================================================
c
c This function fills the work bank for iii-th DTFS track (having track
c number TRKDTFS) by reading DTFS and by calling the extrapolation
c routine VTXEXTR
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      18-9-1997
c     ==============
c
c     Input:
c     ======
c              iii        Track scalar number
c              TRKDTFS    DTFS track number
c
c     Output:
c     =======
c              VWRK bank is filled for this track
c
c=======================================================================
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:DTFS.INC'
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c
c External declarations
c
      integer BOPTN, WBANK, BLOCAT, IWdata, Wsetd
c
c Local declarations
c
      integer III, DIMVWRK, ISTAT, TRKDTFS, IND, INDTFS, I
      real    PHI, COT, SINTHE, COSTHE, Xfh, Yfh, Rfh
      character*80 message
      REAL    Rdc
      EQUIVALENCE (TIRGVX(1),Rdc)
c
c=======================================================================
c
c Set initial value to failure
c
      VTXINIT = -1
      IWdata = INDVWRK + VWRNCO*(iii-1)

c Start filling Work bank (the extrap region is the innermost region 
c reached by the particle)

      IW(IWdata + VWDTFS) = TRKDTFS ! DTFS trk number
      IW(IWdata + VWREG)  = NFH     ! Extrapolation region
c
c Read DTFS and continue filling work bank
c
      ISTAT = BLOCAT(IW,'DTFS',TRKDTFS,IND,INDTFS)
      INDTFS = INDTFS + IW(INDTFS+DTFHDS)
c
c First hit position, tangent, Q/Pt and track length
c
      RW(IWdata + VWXFH) = RW(INDTFS + DTFXCO)
      RW(IWdata + VWYFH) = RW(INDTFS + DTFYCO)
      RW(IWdata + VWZFH) = RW(INDTFS + DTFZCO)
      Rfh = sqrt( RW(IWdata + VWXFH)**2 + RW(IWdata + VWYFH)**2 )
      if (Rfh.lt.RDC .or. Rfh.gt.Rcal) return

      phi = RW(INDTFS + DTFPHI)
      cot = RW(INDTFS + DTFCTT)
      sinthe = 1./sqrt(1.+cot**2)
      costhe = SIGN(sqrt(1.-sinthe**2),cot)

      RW(IWdata + VWTXFH) = sinthe * cos(phi)
      RW(IWdata + VWTYFH) = sinthe * sin(phi)
      RW(IWdata + VWTZFH) = costhe

      RW(IWdata + VWCUFH) = RW(INDTFS + DTFCUR)

      RW(IWdata + VWTLFH) = RW(INDTFS + DTFLNG)
c
c Last hit position, tangent, Q/Pt and track length
c
      RW(IWdata + VWXLH) = RW(INDTFS + DTFXLP)
      RW(IWdata + VWYLH) = RW(INDTFS + DTFYLP)
      RW(IWdata + VWZLH) = RW(INDTFS + DTFZLP)

      phi = RW(INDTFS + DTFPLP)
      cot = RW(INDTFS + DTFTLP)
      sinthe = 1./sqrt(1.+cot**2)
      costhe = SIGN(sqrt(1.-sinthe**2),cot)

      RW(IWdata + VWTXLH) = sinthe * cos(phi)
      RW(IWdata + VWTYLH) = sinthe * sin(phi)
      RW(IWdata + VWTZLH) = costhe

      RW(IWdata + VWCULH) = SIGN(RW(INDTFS+DTFCLP),RW(INDTFS+DTFCUR))

      RW(IWdata + VWTLLH) = RW(INDTFS + DTFLNG)
c
c Copy error matrix at FH
c 
      do i = 1, 15
         RW(IWdata+VWERRF+i-1) = RW(INDTFS+DTFCVM+i-1)
      enddo      
c
c Now extrapolate track IF its First Hit is "close enough" to z axis
c
      If ( Rfh .lt. RPCAMAX )  call VTXEXTR(iii)
c
c Set function to success
c
      VTXINIT = YESUCC
c
 999  return
      end

c=======================================================================
      INTEGER FUNCTION VTXEXTR(iii)
c=======================================================================
c
c This function extrapolates track iii toward the interaction point,
c calling the appropriate routine to evaluate the dE/dx when it crosses
c boundaries. The energy loss is evaluated in the pion mass hypothesis.
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      18-9-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c
c External declarations
c
      INTEGER IWDATA
c
c Local declarations
c      
      integer FLGDIR, Nsurf, iii
      real    COSTHE, SINTHE, COTTHE, COSPHI, SINPHI, RHO, Q
      real    Xc, Yc, D2, S2, Delta, X1, X2, Dist1, Dist2, Dist
      real    Xdc, Ydc, Txdc, Tydc, Alpha, Arc, Zdc, Tzdc
      real    Pin, Pout, Rmass, Xbp, Ybp, Zbp, Txbp, Tybp, Tzbp
      REAL    Rdc, Rbp, Bfield, Y1, Y2, XR(3)
      EQUIVALENCE (TIRGVX(1),Rdc),(TIRGVX(2),Rbp)
      LOGICAL FlagIP(50)        ! common VTXFIT-VTXEXTR
      COMMON /VTXCLOSIP/ FlagIP
c
c=======================================================================
c
c -------------------------
c 0 - Initialize parameters
c -------------------------
c
      Bfield = 6.               ! Magnetic field
      Flgdir = -1               ! Backward direction
      VTXEXTR = YESUCC
      IWDATA = INDVWRK + VWRNCO*(iii-1) ! Data index for track iii in VWRK
      FlagIP(iii) = .false.     ! track is "distant" from IP (see below)
c
c ---------------------------------------
c 1 - Intersection with DC inner boundary
c ---------------------------------------
c
c Find track circle parameters (center and radius):
c
      costhe = RW(IWDATA + VWTZFH)
      sinthe = sqrt(1-costhe**2)
      cotthe = costhe / sinthe
      cosphi = RW(IWdata+VWTXFH) / sinthe
      sinphi = RW(IWdata+VWTYFH) / sinthe
      rho = CONVERS * Bfield *  RW(IWdata+VWCUFH)
      Q = SIGN(1.,rho)
      rho = 1./rho
      Xc  = RW(IWdata+VWXFH) + rho*sinphi
      Yc  = RW(IWdata+VWYFH) - rho*cosphi

c intersect

      D2 = Xc**2 + Yc**2 
      S2 = D2 + Rdc**2 - rho**2
      Delta = D2 * Rdc**2 - S2**2 / 4.
      If (Delta .lt. 0.) then          ! No intersections with DC inner wall
         IW(IWDATA + VWREG) = NFH
         return
      Endif
c
      X1 = (Xc*S2 + 2.*Yc*sqrt(Delta)) / (2.*D2)
      X2 = (Xc*S2 - 2.*Yc*sqrt(Delta)) / (2.*D2)
      if (abs(Yc).lt.1.E-6) then
         Y1 = sqrt( Rdc**2 - X1**2 )
         Y2 = Y1
      else
         Y1 = S2/(2.*Yc) - X1*Xc/Yc
         Y2 = S2/(2.*Yc) - X2*Xc/Yc
      endif

c Select the appropriate intersection as the closest to First Hit

      Dist1 = (X1 - RW(IWdata+VWXFH))**2 +
     +        (Y1 - RW(IWdata+VWYFH))**2
      Dist2 = (X2 - RW(IWdata+VWXFH))**2 +
     +        (Y2 - RW(IWdata+VWYFH))**2
      If (dist1.lt.Dist2) then
         Dist = sqrt(Dist1)
         Xdc = X1
         Ydc = Y1
      else
         Dist = sqrt(Dist2)
         Xdc = X2
         Ydc = Y2
      endif

c Now find rotation angle to get "z" and new tangent.
c Note that, since the track is swimmed back, this angle is POSITIVE
c (counterclockwise) for positive tracks and viceversa.
c Since rho is signed, this means that ALPHA HAS THE SAME SIGN AS RHO
c The "-" in the z evaluation has a similar motivation.

      Alpha = 2 * ASIN(0.5*Dist/Rho)
c
      Arc = rho*Alpha
      Zdc = RW(IWdata+VWZFH) - Arc*Cotthe
c
      Txdc = ( cosphi*cos(Alpha) - sinphi*sin(alpha) ) * sinthe
      Tydc = ( sinphi*cos(Alpha) + cosphi*sin(alpha) ) * sinthe
      Tzdc = costhe

c Write quantities in Work bank

      IW(IWdata+VWREG) = NVC
      RW(IWdata+VWXDC) = Xdc
      RW(IWdata+VWYDC) = Ydc
      RW(IWdata+VWZDC) = Zdc
      RW(IWdata+VWTXDC) = Txdc
      RW(IWdata+VWTYDC) = Tydc
      RW(IWdata+VWTZDC) = Tzdc
      RW(IWdata+VWTLDC) = arc

c And now dE/dx correction
      
      Nsurf = NVC                                        ! DC inner wall
      Rmass = PION_MASS
      call VTXDEDX(iii,Nsurf,Flgdir,Rmass)

c the following flag will be used in VTXFIT. It flags wether the track
c passes or not "close enough" to the Interaction Point (in particular
c it checks the z-coordinate). These tracks are of interest for the
c interference analysis, so they will be treated with particular care.
c So start finding closest point to origin

      xr(1) = 0.
      xr(2) = 0.
      xr(3) = 0.
      call VTXSWM(iii,NVC,xr)
c
c now check its (z) position
c
      If ( abs(RW(IWdata+VWZVX)) .lt. ZclosIP ) FlagIP(iii) = .true.
c
c ---------------------------------------
c 2 - Inward intersection with BP 
c ---------------------------------------
c
c The method is the same as before, however, due to the curvature variation
c caused by the energy loss, all quantities on transverse plane have
c to be revaluated.
c
c Find track circle parameters (center and radius):
c
      cosphi = RW(IWdata+VWTXDC) / sinthe
      sinphi = RW(IWdata+VWTYDC) / sinthe
      rho = CONVERS * Bfield *  RW(IWdata+VWCUDC)
      rho = 1./rho
      Xc  = RW(IWdata+VWXDC) + rho*sinphi
      Yc  = RW(IWdata+VWYDC) - rho*cosphi
 
c intersect

      D2 = Xc**2 + Yc**2 
      S2 = D2 + Rbp**2 - rho**2
      Delta = D2 * Rbp**2 - S2**2 / 4.
      If (Delta .lt. 0.) then          ! No intersections with BP
         IW(IWDATA + VWREG) = NVC
         return
      Endif
c
      X1 = (Xc*S2 + 2.*Yc*sqrt(Delta)) / (2.*D2)
      X2 = (Xc*S2 - 2.*Yc*sqrt(Delta)) / (2.*D2)
      if (abs(Yc).lt.1.E-6) then
         Y1 = sqrt( Rbp**2 - X1**2 )
         Y2 = Y1
      else
         Y1 = S2/(2.*Yc) - X1*Xc/Yc
         Y2 = S2/(2.*Yc) - X2*Xc/Yc
      endif

c Select the appropriate intersection as the closest to First Hit

      Dist1 = (X1 - RW(IWdata+VWXDC))**2 +
     +        (Y1 - RW(IWdata+VWYDC))**2
      Dist2 = (X2 - RW(IWdata+VWXDC))**2 +
     +        (Y2 - RW(IWdata+VWYDC))**2
      If (dist1.lt.Dist2) then
         Dist = sqrt(Dist1)
         Xbp = X1
         Ybp = Y1
      else
         Dist = sqrt(Dist2)
         Xbp = X2
         Ybp = Y2
      endif

c Now find rotation angle to get "z" and new tangent.
c Note that, since the track is swimmed back, this angle is POSITIVE
c (counterclockwise) for positive tracks and viceversa.
c Since rho is signed, this means that ALPHA HAS THE SAME SIGN AS RHO
c The "-" in the z evaluation has a similar motivation.

      Alpha = 2 * ASIN(0.5*Dist/Rho)
c
      Arc = rho*Alpha
      Zbp = RW(IWdata+VWZDC) - Arc*Cotthe
c
      Txbp = ( cosphi*cos(Alpha) - sinphi*sin(alpha) ) * sinthe
      Tybp = ( sinphi*cos(Alpha) + cosphi*sin(alpha) ) * sinthe
      Tzbp = costhe

c Write quantities in Work bank

      IW(IWdata+VWREG) = NBI
      RW(IWdata+VWXBI) = Xbp
      RW(IWdata+VWYBI) = Ybp
      RW(IWdata+VWZBI) = Zbp
      RW(IWdata+VWTXBI) = Txbp
      RW(IWdata+VWTYBI) = Tybp
      RW(IWdata+VWTZBI) = Tzbp
      RW(IWdata+VWTLBI) = arc

c And now dE/dx correction
      
      Nsurf = NBI                                        ! BP wall entrance
      Rmass = PION_MASS
      call VTXDEDX(iii,Nsurf,Flgdir,Rmass)
c
c ---------------------------------------
c 3 - Outward intersection with BP 
c ---------------------------------------
c
c It may happen that the track crosses twice the Beam Pipe, so it is
c nevessary to evaluate also the second intersection of the track with
c the Beam Pipe (if one exist, than also a second one does). Since we
c are tracing back, this intersection is called the "outward intersection"
c even if, when the vertex is in the VC region and the track crosses 
c twice the BP, the "outward intersection" corresponds to the charged
c particle "entering" the BP.
c As before, transverse quantities need to be re-evaluated.
c
c Find track circle parameters (center and radius):
c
      cosphi = RW(IWdata+VWTXBI) / sinthe
      sinphi = RW(IWdata+VWTYBI) / sinthe
      rho = CONVERS * Bfield *  RW(IWdata+VWCUBI)
      rho = 1./rho
      Xc  = RW(IWdata+VWXBI) + rho*sinphi
      Yc  = RW(IWdata+VWYBI) - rho*cosphi
 
c intersect

      D2 = Xc**2 + Yc**2 
      S2 = D2 + Rbp**2 - rho**2
      Delta = D2 * Rbp**2 - S2**2 / 4.
      If (Delta .lt. 0.) then   !This shouldn't happen; left as protection
         IW(IWDATA + VWREG) = NBI
         return
      Endif
c
      X1 = (Xc*S2 + 2.*Yc*sqrt(Delta)) / (2.*D2)
      X2 = (Xc*S2 - 2.*Yc*sqrt(Delta)) / (2.*D2)
      if (abs(Yc).lt.1.E-6) then
         Y1 = sqrt( Rbp**2 - X1**2 )
         Y2 = Y1
      else
         Y1 = S2/(2.*Yc) - X1*Xc/Yc
         Y2 = S2/(2.*Yc) - X2*Xc/Yc
      endif

c Select the appropriate intersection as the FAREST to First Hit

      Dist1 = (X1 - RW(IWdata+VWXBI))**2 +
     +        (Y1 - RW(IWdata+VWYBI))**2
      Dist2 = (X2 - RW(IWdata+VWXBI))**2 +
     +        (Y2 - RW(IWdata+VWYBI))**2
      If (Dist1.gt.Dist2) then 
         Dist = sqrt(Dist1)
         Xbp = X1
         Ybp = Y1
      else
         Dist = sqrt(Dist2)
         Xbp = X2
         Ybp = Y2
      endif

c Now find rotation angle to get "z" and new tangent.
c Note that, since the track is swimmed back, this angle is POSITIVE
c (counterclockwise) for positive tracks and viceversa.
c Since rho is signed, this means that ALPHA HAS THE SAME SIGN AS RHO
c The "-" in the z evaluation has a similar motivation.

      Alpha = 2 * ASIN(0.5*Dist/Rho)
c
      Arc = rho*Alpha
      Zbp = RW(IWdata+VWZBI) - Arc*Cotthe
c
      Txbp = ( cosphi*cos(Alpha) - sinphi*sin(alpha) ) * sinthe
      Tybp = ( sinphi*cos(Alpha) + cosphi*sin(alpha) ) * sinthe
      Tzbp = costhe

c Write quantities in Work bank

      IW(IWdata+VWREG) = NBU
      RW(IWdata+VWXBU) = Xbp
      RW(IWdata+VWYBU) = Ybp
      RW(IWdata+VWZBU) = Zbp
      RW(IWdata+VWTXBU) = Txbp
      RW(IWdata+VWTYBU) = Tybp
      RW(IWdata+VWTZBU) = Tzbp
      RW(IWdata+VWTLBU) = arc

c And now dE/dx correction
      
      Nsurf = NBU                                        ! BP wall at exit
      Rmass = PION_MASS
      call VTXDEDX(iii,Nsurf,Flgdir,Rmass)
c
c ------------------------------------------------
c End of extrapolation procedure
c ------------------------------------------------
c
      return
      end

c=======================================================================
      SUBROUTINE VTXDEDX(iii,Nsurf,Flgdir,Rmass)
c=======================================================================
c
c This routine evaluates dE/dx loss due to surface crossing
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      18-9-1997
c     ==============
c
c     Input data:
c     ===========
c                 iii            Track scalar number (not DTFS)
c                 NSurf          Surface number (2=DC; 3=BP in; 4=BP out)
c                 Flgdir         -1 for backward swimming ; otherwise +1
c                 RMass          Particle mass (normally pion)
c
c     Output data:
c     ============
c                RW(...+VWCUxx) the new curvature (defined as Q/Pt) of track
c                               iii at surface Nsurf is evaluated  
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c      
      INTEGER IWdata
      INTEGER i, iii, nsurf, flgdir
      REAL Rdc, Rbp, Rmass, Pin, Ptin, Pfin, Ptfin, dgdx, Q, sinthe
      REAL C1Epxy, C2Epxy, C1Al, C2Al, C1Fe, C2Fe, C1Cu, C2Cu
      REAL C1Pb, C2Pb, C1Be, C2Be, C1Ag, C2Ag
      REAL XEpxydc, XAldc, XBebp
      REAL C1,C2, GAM, GAMOUT, Delx, rx, ry, tx, ty, cosgamma
      REAL dgdx1,dgdx2,dgdx3,dgdx4
      CHARACTER*80 Message
c
c Bethe-Block constants C1, C2 for seven materials are stored
c in CTIDRI include file (C-epoxy,Al,Fe,Cu,Ag,Pb,Be).
c Not all of them are of interest for KLOE, however. 
c C1 = 4 * pi * N_av * rad_el**2 * m_el * c**2 * Z / A    (Gev*cm**2/gr)
c C2 = 2 * m_el * c**2 / I     (I=mean excitation energy - adimensional)
c
      EQUIVALENCE
     +(TIDEVX(1,1),C1Epxy),(TIDEVX(2,1),C2Epxy),
     +(TIDEVX(1,2),C1Al),  (TIDEVX(2,2),C2Al),
     +(TIDEVX(1,3),C1Fe),  (TIDEVX(2,3),C2Fe),
     +(TIDEVX(1,4),C1Cu),  (TIDEVX(2,4),C2Cu),
     +(TIDEVX(1,5),C1Ag),  (TIDEVX(2,5),C2Ag),
     +(TIDEVX(1,6),C1Pb),  (TIDEVX(2,6),C2Pb),
     +(TIDEVX(1,7),C1Be),  (TIDEVX(2,7),C2Be)
c
      EQUIVALENCE (TIRGVX( 1),Rdc),(TIRGVX( 2),Rbp)
c
c Thickness, in gr/cm**2, of the materials that make up the walls
c
      EQUIVALENCE (TIRGVX( 3),XEpxydc),(TIRGVX( 6),XAldc)
      EQUIVALENCE (TIRGVX(11),XBebp)
c
c Temporary solution to be corrected as soon as possible!!! (19-feb-1998)
c
      real xxxaldc
      PARAMETER (XXXAldc=0.11025)
C
c dGAMMA/dx function to be integrated (statement function)
c
      dgdx(GAM) = -C1*(GAM**2/(GAM**2-1)*log(C2*(GAM**2-1))-1)
c
c=======================================================================
c
c 1 - DC wall
c ----------
c
      If (Nsurf.eq.NVC) then
         
c get pointer to data and thickness crossed by particle
         
         IWdata = Indvwrk + Vwrnco*(iii-1)
         Ptin = 1. / RW(IWdata+VWCUFH)             ! Starting Pt in GeV (signed)
         Q = SIGN(1.,Ptin)
         Pin = Ptin / sqrt(1-RW(IWdata+VWTZFH)**2) ! Starting P in GeV

c get spatial angle momentum-surface

         rx = RW(IWdata+VWXDC)
         ry = RW(IWdata+VWYDC)
         tx = RW(IWdata+VWTXDC)
         ty = RW(IWdata+VWTYDC)
         cosgamma = abs(rx*tx+ry*ty)/sqrt(rx*rx+ry*ry)
         if (cosgamma.lt.0.0001) cosgamma=0.0001

c     prepare variables for dE/dx integration (flgdir determines the
c     integration sign)

         C1 = float(Flgdir) * C1Al/Rmass
         C2 = C2Al
         GAM = sqrt(Pin**2+Rmass**2)/Rmass
         DELX = XAldc/cosgamma
         sinthe =  sqrt(1-RW(IWdata+VWTZDC)**2)
c
c 2 - BP wall (enter)
c ------------------
c
      Elseif (Nsurf.eq.NBI) then
         
c get pointer to data and thickness crossed by particle
         
         IWdata = Indvwrk + Vwrnco*(iii-1)
         Ptin = 1. / RW(IWdata+VWCUDC)             ! Starting Pt in GeV (signed)
         Q = SIGN(1.,Ptin)
         Pin = Ptin / sqrt(1-RW(IWdata+VWTZDC)**2) ! Starting P in GeV

c get spatial angle momentum-surface

         rx = RW(IWdata+VWXBI)
         ry = RW(IWdata+VWYBI)
         tx = RW(IWdata+VWTXBI)
         ty = RW(IWdata+VWTYBI)
         cosgamma = abs(rx*tx+ry*ty)/sqrt(rx*rx+ry*ry)
         if (cosgamma.lt.0.0001) cosgamma=0.0001

c     prepare variables for dE/dx integration (flgdir determines the
c     integration sign)

         C1 = float(Flgdir) * C1Be/Rmass
         C2 = C2Be
         GAM = sqrt(Pin**2+Rmass**2)/Rmass
         DELX = XBebp/cosgamma
         sinthe =  sqrt(1-RW(IWdata+VWTZBI)**2)
c
c 3 - BP wall (exit)
c ------------------
c
      Elseif (Nsurf.eq.NBU) then
         
c get pointer to data and thickness crossed by particle
         
         IWdata = Indvwrk + Vwrnco*(iii-1)
         Ptin = 1. / RW(IWdata+VWCUBI)             ! Starting Pt in GeV (signed)
         Q = SIGN(1.,Ptin)
         Pin = Ptin / sqrt(1-RW(IWdata+VWTZBI)**2) ! Starting P in GeV

c get spatial angle momentum-surface

         rx = RW(IWdata+VWXBU)
         ry = RW(IWdata+VWYBU)
         tx = RW(IWdata+VWTXBU)
         ty = RW(IWdata+VWTYBU)
         cosgamma = abs(rx*tx+ry*ty)/sqrt(rx*rx+ry*ry)
         if (cosgamma.lt.0.0001) cosgamma=0.0001

c     prepare variables for dE/dx integration (flgdir determines the
c     integration sign)

         C1 = float(Flgdir) * C1Be/Rmass
         C2 = C2Be
         GAM = sqrt(Pin**2+Rmass**2)/Rmass
         DELX = XBebp/cosgamma
         sinthe =  sqrt(1-RW(IWdata+VWTZBU)**2)
c
      Else
              message = 'Non exixting surface'
	      call ERLOGR ('VTXDEDX',ERWARN,0,0,message)
      Endif
c
c =========================================================================
c Now perform integration of dGdx function using the 4th order Runge-Kutta 
c method (see "Numerical Recipes" by Press,Flannery,Teukolsky,Vetterling,
c 1986, pag.550 - Cambridge University Press)
c ==========================================================================
c
      dgdx1 = DELX * DGDX(GAM)
      dgdx2 = DELX * DGDX(GAM+dgdx1/2.)
      dgdx3 = DELX * DGDX(GAM+dgdx2/2.)
      dgdx4 = DELX * DGDX(GAM+dgdx3)
c      
      GAMOUT = GAM + dgdx1/6. + dgdx2/3. + dgdx3/3. + dgdx4/6.
      if (GAMOUT.lt.1.) then
              message = 'Gamma .lt. 1 !'
	      call ERLOGR ('VTXDEDX',ERWARN,0,0,message)
              GAMOUT = GAM
      endif
c
      Pfin = Rmass * sqrt(GAMOUT**2-1.)         ! Final momentum
      Ptfin = Pfin * sinthe                     ! Final Pt (unsigned)
c
c Write out informations
c
      if (Nsurf.eq.2) then
         RW(IWdata+VWCUDC) = Q/Ptfin
      elseif (Nsurf.eq.3) then
         RW(IWdata+VWCUBI) = Q/Ptfin
      elseif (Nsurf.eq.4) then 
         RW(IWdata+VWCUBU) = Q/Ptfin
      endif
c
      return
      end
c

c=======================================================================
      subroutine vtxmerg
c=======================================================================
c
c final part of vertex fitting alorythm: the candidate vertices are
c compared in order to:
c 1 - select the best in chi2 if 2 of them are within the bp and use
c     the same tracks
c 2 - merge 2 tracks vertices and build up a 3 or 4 tracks vertex if
c     two vertices have a track in common .or. if they are in region
c     NDC and are close (i.e. four tracks vertex split in 2 two tracks
c     vertices)
c 3 - Order the DVFS banks (=remove holes)
c 4 - try to assign the left over particles - to the DVFS banks obtained
c     (no new vertex at this stage)
c
c     author:             marco incagli
c     =======
c
c     creation date:      3-10-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$implicit none
$$include 'k$inc:bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$include 'k$itrk:ctidri.inc'
$$include 'k$itrk:cconst.inc'
$$include 'K$ITRK:vwrk.inc'
$$include 'K$ITRK:vtxfin.inc'
$$include 'K$ITRK:dvcs.inc'
c      
      integer blocat, ind, inddat, idummy, ii1, ii2, ii3, ii4
      integer status, canvtx, i1, i2, vtxctov, ntrfit, ifit
      integer fltr(2,50), flvtx(50), idv(50), ilist(10), thisdtfs
      integer dhds, dtrp, dtrb, indvcs(50), nflag, vtxflg(50)
      integer ndtfs1(50), ndtfs2(50), flend1(50), flend2(50)
      integer IWDATA
      real    c2dvcs(50), vxcan(50), vycan(50), vzcan(50)
      real    xcn(3), xint(3), chisq, qpt, px1, py1, pz1, ee1
      real    px2, py2, pz2, ee2, rmass, dist
      character*80 message
      logical constr
c
c=======================================================================
c
c number of candidate vertices
c
      canvtx = nvxfit
c
c Get informations from each vertex
c
      do i1 = 1, canvtx
         IDV(i1) = i1           ! Pointer to vertex candidate
         STATUS = BLOCAT(IW,'DVCS',i1,IND,INDDAT)
         DHDS =  IW(INDDAT+DVCHDS) ! header size
         DTRP =  IW(INDDAT+DVCTRK) ! pointer to track data
         DTRB =  IW(INDDAT+DVCBLK) ! track data block size

         C2DVCS(i1) = RW(INDDAT+DHDS+DVCCSQ)! track Chi squared
c decrease track CHI2 if two particles invariant mass is close to Kl mass
           Qpt = RW(INDDAT+DHDS+DTRP+DVCQPT)
           Pz1 = RW(INDDAT+DHDS+DTRP+DVCCOT)/abs(Qpt)
           Px1 = cos(RW(INDDAT+DHDS+DTRP+DVCPHI))/abs(Qpt)
           Py1 = sin(RW(INDDAT+DHDS+DTRP+DVCPHI))/abs(Qpt)
           Ee1 = sqrt( PION_MASS**2 + Px1**2 + Py1**2 + Pz1**2 )
           Qpt = RW(INDDAT+DHDS+DTRP+DTRB+DVCQPT)
           Pz2 = RW(INDDAT+DHDS+DTRP+DTRB+DVCCOT)/abs(Qpt)
           Px2 = cos(RW(INDDAT+DHDS+DTRP+DTRB+DVCPHI))/abs(Qpt)
           Py2 = sin(RW(INDDAT+DHDS+DTRP+DTRB+DVCPHI))/abs(Qpt)
           Ee2 = sqrt( PION_MASS**2 + Px2**2 + Py2**2 + Pz2**2 )
           Rmass = (Ee1+Ee2)**2-(Px1+Px2)**2-(Py1+Py2)**2-(Pz1+Pz2)**2
           Rmass = sqrt(Rmass)
           If (abs(Rmass-KAON_MASS).lt.0.05) C2DVCS(i1) = C2DVCS(i1)/2.
c
         INDVCS(i1) = INDDAT + DHDS! index to data
         VTXFLG(i1) = IW(INDDAT + DHDS + DVCVFL) ! Vtx flag (VTXFIN structure)
         VXCAN(i1)  = RW(INDDAT+DHDS+DVCVX)  ! Vertex x coordinate
         VYCAN(i1)  = RW(INDDAT+DHDS+DVCVY)  ! Vertex y coordinate
         VZCAN(i1)  = RW(INDDAT+DHDS+DVCVZ)  ! Vertex z coordinate
         NDTFS1(i1) = IW(INDDAT+DHDS+DTRP+DVCTRN)  ! track number
         FLEND1(i1) = IW(INDDAT+DHDS+DTRP+DVCFFL)  ! "end" flag (FH vs LH)
         NDTFS2(i1) = IW(INDDAT+DHDS+DTRP+DTRB+DVCTRN) ! as before for
         FLEND2(i1) = IW(INDDAT+DHDS+DTRP+DTRB+DVCFFL) ! second track

c   Set initial flags for vertex and tracks.
c   For vertices FLVTX=1 means "good", while FLVTX=0 means "bad"
c for tracks FLTR( Track_end , DTFS_num ) = 1 means that this end of
c the track (First or Last hit) is used in more than one vertex candidate.
c   Start by assuming vertices good and tracks used in just one vertex.

         FLVTX(i1) = 1
         ii1 = (FLEND1(i1)+3)/2   ! 1 if FH; 2 if LH
         ii2 = (FLEND2(i1)+3)/2   ! 1 if FH; 2 if LH
         FLTR(ii1,NDTFS1(i1)) = 0 ! flag for end ii1 of track 1
         FLTR(ii2,NDTFS2(i1)) = 0 ! flag for end ii2 of track 2

      enddo
c
c Sort vertices according to CHI2
c
      do 32 i1 = 1, canvtx-1
         do 33 i2 = i1+1, canvtx
            if ( C2DVCS(IDV(i1)) .gt. C2DVCS(IDV(i2)) ) then !switch tracks
               IDUMMY = IDV(i1)
               IDV(i1) = IDV(i2)
               IDV(i2) = IDUMMY
            endif
 33      enddo
 32   enddo
c
c ---------- Start loop on vertices -------------
c
      do 35 i1 = 1, canvtx-1

c First vertex MUST have both tracks NOT FLAGGED

         II1 = (FLEND1(IDV(i1))+3)/2    ! this is 1 for FH and 2 for LH
         II2 = NDTFS1(IDV(i1))
         II3 = (FLEND2(IDV(i1))+3)/2 
         II4 = NDTFS2(IDV(i1))
         if ( FLTR(ii1,ii2)+FLTR(ii3,ii4) .gt. 0) goto 35

        do 36 i2 = i1+1 , canvtx

c check if this is the same vertex found in two different parts of the
c algorithm if this is the case kill second vertex

           if ( ( (ndtfs1(IDV(i1))+ndtfs1(IDV(i2))).eq.
     &            (ndtfs2(IDV(i1))+ndtfs2(IDV(i2))) ).and.
     &          ( (ndtfs1(IDV(i1))-ndtfs1(IDV(i2))).eq.
     &            (ndtfs2(IDV(i2))-ndtfs2(IDV(i1))) ) ) then

c flag bad vertex and release tracks 1 and 2 of vertex 2

              FLVTX(IDV(i2)) = 0              ! flag for bad vertex
              II1 = (FLEND1(IDV(i2))+3)/2
              II2 = (FLEND2(IDV(i2))+3)/2
              FLTR(II1,NDTFS1(IDV(i2))) = 0   ! flag for "free" track
              FLTR(II2,NDTFS2(IDV(i2))) = 0   ! flag for "free" track

c flag good vertex and "used" tracks (tracks 1 and 2 of vertex 1) 
              II1 = (FLEND1(IDV(i1))+3)/2
              II2 = (FLEND2(IDV(i1))+3)/2

              FLVTX(IDV(i1)) = 1              ! flag for good vertex
              FLTR(ii1,NDTFS1(IDV(i1))) = 1       ! flag for  tracks in common
              FLTR(ii2,NDTFS2(IDV(i1))) = 1       ! with more VTCS vertices

              goto 36
         endif

c Second vertex MUST have both tracks NOT FLAGGED
         II1 = (FLEND1(IDV(i2))+3)/2    ! this is 1 for FH and 2 for LH
         II2 = NDTFS1(IDV(i2))
         II3 = (FLEND2(IDV(i2))+3)/2 
         II4 = NDTFS2(IDV(i2))
         if ( FLTR(ii1,ii2)+FLTR(ii3,ii4) .gt. 0) then
            FLVTX(IDV(i2)) = 0
            goto 36
         endif

         dist = sqrt( (vxcan(IDV(i1))-vxcan(IDV(i2)))**2 + 
     +                (vycan(IDV(i1))-vycan(IDV(i2)))**2 +
     +                (vzcan(IDV(i1))-vzcan(IDV(i2)))**2 )

c --- Step 1 ---   Check if there is a track in common 
c (FLEND=-1 for FH and +1 for LH) between two vertices.
c Start with track 2 of vtx 2.

         if ( NDTFS1(IDV(i1))*FLEND1(IDV(i1)) .eq.  
     +        NDTFS2(IDV(i2))*FLEND2(IDV(i2)) .or.  
     +        NDTFS2(IDV(i1))*FLEND2(IDV(i1)) .eq.  
     +        NDTFS2(IDV(i2))*FLEND2(IDV(i2)) ) then

c call fitting routine with three tracks; do a constrained fit 
c note that the minimization routine needs the "track number" and
c not the "DTFS number"; this is the reason of the following loop

            ilist(1) = 0
            ilist(2) = 0
            ilist(3) = 0
            do ii1=1, tottrk
               thisdtfs = IW(INDVWRK+VWRNCO*(ii1-1)+VWDTFS)
               if ( thisdtfs.eq.NDTFS1(IDV(i1)) ) then
                  Ilist(1) = ii1*FLEND1(IDV(i1))
               elseif ( thisdtfs.eq.NDTFS2(IDV(i1)) ) then
                  Ilist(2) = ii1*FLEND2(IDV(i1))
               elseif ( thisdtfs.eq.NDTFS1(IDV(i2)) ) then
                  Ilist(3) = ii1*FLEND1(IDV(i2))
               endif
            enddo

c check above assignement
            if ( Ilist(1)*Ilist(2)*Ilist(3) .eq. 0 ) then
               message = 
     +      'Error in DTFS number assignement for 3 tracks vertex'
               call ERLOGR ('VTXMERG',ERWARN,0,0,message)
               CHISQ = 1000.
               goto 998
            endif
c
            ntrfit = 3

            CONSTR = .true.
            XINT(1) = VXCAN(IDV(i1))
            XINT(2) = VYCAN(IDV(i1))
            XINT(3) = VZCAN(IDV(i1))
            XCN(1) = XINT(1)
            XCN(2) = XINT(2)
            XCN(3) = XINT(3)
c
c call minimization procedure
c
           NFLAG = 4            ! convergence occurred in merging procedure
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.
 998       continue
c
c check if three is better than two by looking at REDUCED CHI2
c
           if ( IFIT.eq.FITGOLD .and.
     +          CHISQ/3..lt.C2DVCS(IDV(i1))/2. ) then

c write DVFS bank by merging DVCS banks i1 and i2 using the two tracks
c of bank i1 and track number 1 of bank i2

              ii1 = IDV(i1)
              ii2 = IDV(i2)
              call VTXMRGCAN(ii1,ii2,1)

c flag the two original vertices as "bad"

              FLVTX(IDV(i1)) = 0              ! flag for bad vertex
              FLVTX(IDV(i2)) = 0              ! flag for bad vertex

           else

c Here there is one track in common, but second vertex is bad (large
c CHI2); flag bad vertex and release track 1 of vertex 2

              FLVTX(IDV(i2)) = 0              ! flag for bad vertex
              II1 = (FLEND1(IDV(i2))+3)/2
              FLTR(II1,NDTFS1(IDV(i2))) = 0   ! flag for "free" track
c
c change also flag inside work bank for this end of the track
c
              IWDATA = INDVWRK+VWRNCO*(abs(Ilist(3))-1)+II1+1
              IW(IWDATA) = 0

c flag good vertex and "used" tracks (tracks 1 and 2 of vertex 1) 
              II1 = (FLEND1(IDV(i1))+3)/2
              II2 = (FLEND2(IDV(i1))+3)/2

              FLVTX(IDV(i1)) = 1              ! flag for good vertex
              FLTR(ii1,NDTFS1(IDV(i1))) = 1       ! flag for  tracks in common
              FLTR(ii2,NDTFS2(IDV(i1))) = 1       ! with more VTCS vertices

           endif

c --- Step 2 ---   Check if there is a track in common 
c (FLEND=-1 for FH and +1 for LH) between two vertices.
c Now check track 1 of vtx 2.

         elseif ( NDTFS1(IDV(i1))*FLEND1(IDV(i1)) .eq.  
     +            NDTFS1(IDV(i2))*FLEND1(IDV(i2)) .or.  
     +            NDTFS2(IDV(i1))*FLEND2(IDV(i1)) .eq.  
     +            NDTFS1(IDV(i2))*FLEND1(IDV(i2)) ) then

c call fitting routine with three tracks; do a constrained fit ;
c note that the minimization routine needs the "track number" and
c not the "DTFS number"; this is the reason for the following loop

            ilist(1) = 0
            ilist(2) = 0
            ilist(3) = 0
            do ii1=1, tottrk
               thisdtfs = IW(INDVWRK+VWRNCO*(ii1-1)+VWDTFS)
               if ( thisdtfs.eq.NDTFS1(IDV(i1)) ) then
                  Ilist(1) = ii1*FLEND1(IDV(i1))
               elseif ( thisdtfs.eq.NDTFS2(IDV(i1)) ) then
                  Ilist(2) = ii1*FLEND2(IDV(i1))
               elseif ( thisdtfs.eq.NDTFS2(IDV(i2)) ) then
                  Ilist(3) = ii1*FLEND2(IDV(i2))
               endif
            enddo

c check above assignement
            if ( Ilist(1)*Ilist(2)*Ilist(3) .eq. 0 ) then
               message = 
     +      'Error in DTFS number assignement for 3 tracks vertex'
               call ERLOGR ('VTXMERG',ERWARN,0,0,message)
               CHISQ = 1000.
               goto 997
            endif
c
            ntrfit = 3

            CONSTR = .true.
            XINT(1) = VXCAN(IDV(i1))
            XINT(2) = VYCAN(IDV(i1))
            XINT(3) = VZCAN(IDV(i1))
            XCN(1) = XINT(1)
            XCN(2) = XINT(2)
            XCN(3) = XINT(3)
c
c call minimization procedure
c
           NFLAG = 4            ! convergence occurred in merging procedure
           CALL VTXMIN(Nflag,Ntrfit,ILIST,XINT,CHISQ,IFIT,XCN,CONSTR)
           CONSTR = .false.
 997       continue
c
c check if three is better than two by looking at REDUCED CHI2
c
           if ( IFIT.eq.FITGOLD .and.
     +          CHISQ/3..lt.C2DVCS(IDV(i1))/2. ) then

c write DVFS bank by merging DVCS banks i1 and i2 using the two tracks
c of bank i1 and track number 2 of bank i2

              ii1 = IDV(i1)
              ii2 = IDV(i2)
              call VTXMRGCAN(ii1,ii2,2)

c flag the two original vertices as "bad";

              FLVTX(IDV(i1)) = 0              ! flag for bad vertex
              FLVTX(IDV(i2)) = 0              ! flag for bad vertex

           else

c Here there is one track in common, but second vertex is bad (large
c CHI2); flag bad vertex and release track 2 of vertex 2

              FLVTX(IDV(i2)) = 0              ! flag for bad vertex
              II1 = (FLEND2(IDV(i2))+3)/2
              FLTR(ii1,NDTFS2(IDV(i2))) = 0       ! flag for "free" track
c
c change also flag inside work bank for this end of the track
c
              IWDATA = INDVWRK+VWRNCO*(abs(Ilist(3))-1)+II1+1
              IW(IWDATA) = 0

c flag good vertex and "used" tracks (tracks 1 and 2 of vertex 1)
              II1 = (FLEND1(IDV(i1))+3)/2
              II2 = (FLEND2(IDV(i1))+3)/2

              FLVTX(IDV(i1)) = 1              ! flag for good vertex
              FLTR(ii1,NDTFS1(IDV(i1))) = 1 ! flag for tracks used in more 
              FLTR(ii2,NDTFS2(IDV(i1))) = 1 ! than one candidate vertex

           endif

c --- Step 3 ---   Check if the two vertices are inside DC .and.
c if they are close. When this happens try to build up a 4 tracks vertex.
c
        elseif ( ( vtxflg(IDV(i1)).eq.3.and.vtxflg(IDV(i2)).eq.3 ) .and.
     +            dist .lt. distvtx ) then

c Call fitting routine with four tracks and do a constrained fit.
c Note that the minimization routine needs the "track number" and
c not the "DTFS number"; this is the reason for the following loop

            ilist(1) = 0
            ilist(2) = 0
            ilist(3) = 0
            ilist(4) = 0
            do ii1=1, tottrk
               thisdtfs = IW(INDVWRK+VWRNCO*(ii1-1)+VWDTFS)

               if ( thisdtfs.eq.NDTFS1(IDV(i1)) ) then
                  Ilist(1) = ii1*FLEND1(IDV(i1))

               elseif ( thisdtfs.eq.NDTFS2(IDV(i1)) ) then
                  Ilist(2) = ii1*FLEND2(IDV(i1))

               elseif ( thisdtfs.eq.NDTFS1(IDV(i2)) ) then
                  Ilist(3) = ii1*FLEND1(IDV(i2))

               elseif ( thisdtfs.eq.NDTFS2(IDV(i2)) ) then
                  Ilist(4) = ii1*FLEND2(IDV(i2))

               endif
            enddo

c check above assignement

            if ( Ilist(1)*Ilist(2)*Ilist(3)*Ilist(4) .eq. 0 ) then
               message = 
     +      'Error in DTFS number assignement for 4 tracks vertex'
               call ERLOGR ('VTXMERG',ERWARN,0,0,message)
               goto 779
            endif

c Perform a constrained 4 tracks fit and compare CHI2s

               ntrfit = 4

               CONSTR = .true.
               XINT(1) = ( VXCAN(IDV(i1)) + VXCAN(IDV(i2)) ) / 2.
               XINT(2) = ( VYCAN(IDV(i1)) + VYCAN(IDV(i2)) ) / 2.
               XINT(3) = ( VZCAN(IDV(i1)) + VZCAN(IDV(i2)) ) / 2.
               XCN(1) = XINT(1)
               XCN(2) = XINT(2)
               XCN(3) = XINT(3)
c
c call minimization procedure
c
               NFLAG = 4        ! convergence occurred in merging procedure
               CALL VTXMIN(Nflag, Ntrfit, ILIST,
     +                     XINT, CHISQ, IFIT, XCN, CONSTR)
               CONSTR = .false.
c
c check if FOUR is better than TWO
c
           if ( IFIT.eq.FITGOLD .and.
     +          CHISQ .lt. (C2DVCS(IDV(i1))+C2DVCS(IDV(i2))) ) then

c write DVFS bank by merging DVCS banks i1 and i2 using the two tracks
c of bank i1 and track number 2 of bank i2

              ii1 = IDV(i1)
              ii2 = IDV(i2)
              call VTXMRGCAN(ii1,ii2,2)

c flag the two original vertices as "bad";

              FLVTX(IDV(i1)) = 0              ! flag for bad vertex
              FLVTX(IDV(i2)) = 0              ! flag for bad vertex

            endif
c 
 779        continue
         endif
c
 36      enddo
 35   enddo
c
c 2 - loop on DVCS bank and write out DVFS bank for "good vertices"
c
      do i1 = 1, Canvtx
         if (FLVTX(IDV(i1)) .eq. 1) then
            STATUS = VTXCTOV(IDV(i1))
            IF (STATUS.NE.YESUCC) THEN
               message = 'Error in DVCS_to_DVFS routine'
               call ERLOGR ('VTXMERG',ERWARN,0,0,message)
               return
            ENDIF
         endif
      enddo
c
c 3 - order the DVFS banks (=remove holes)
c 
      i1 = 0
      STATUS = BLOCAT(IW,'DVFS',-1,IND,INDDAT)
      if (STATUS .ne. YESUCC) return          ! no DVFS bank present
c
 10   i1 = i1 + 1
      
c change bank number
      IW(IND-2) = i1

c jump to next bank
      IND = IW(IND-1)

c stop if IND = 0 (last named bank)
      if (IND.eq.0) then
         NVXFIT = i1
         goto 11
      endif
c      
      goto 10
 11   continue
c
c 4 - add tracks to vertices
c
c 4.1) loop on vertices
c
c
      return
      end
c

c=======================================================================
      INTEGER FUNCTION VTXMRGCAN(i1,i2,itrk)
c=======================================================================
c
c Routine that merges DVCS banks number i1 and i2 into a DVFS bank.
c If itrk = 1 .or. itrk = 2 then the DVFS bank has three tracks:
c the 2 tracks of bank i1 and track "itrk" from bank i2.
c Else if itrk = 3, than bank DVFS is composed by four tracks, the two
c from bank i1 and the 2 from bank i2.
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      25-11-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
$$INCLUDE 'K$ITRK:DVCS.INC'
$$INCLUDE 'K$ITRK:DVFS.INC'
c      
      INTEGER STATUS, iii, itrk, IND, INDVCS, INDVFS
      INTEGER i1, i2, i3
      INTEGER BNKSIZ, BLOCAT, BTYMKG, Idvfs, Idvcs, TRKPOI, BLKSIZ
      REAL    tx, ty
      CHARACTER*80 message
c
c=======================================================================
c
c set status to failure
c
      VTXMRGCAN = -1
c
c Open the Vertex Candidate bank DVCS i1
c
      STATUS = BLOCAT(IW,'DVCS',i1,IND,INDVCS)
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in locating bank DVCS'
	 call ERLOGR ('VTXCTOV',ERWARN,0,0,message)
         return
      ENDIF
      TRKPOI = IW(INDVCS+DVCTRK)
      BLKSIZ = IW(INDVCS+DVCBLK)
      INDVCS = INDVCS + IW( INDVCS+DVCHDS )
c
c create the corresponding Vertex bank DVFS 
c at the moment only 3 or 4 tracks banks can be created
c
      if (itrk.lt.3) then
         STATUS = BTYMKG(IW,'DVFS',i1,'3I4,10R4,3I4,3(I4,16R4,2I4)',
     +                BNKSIZ, IND, INDVFS)
      else
         STATUS = BTYMKG(IW,'DVFS',i1,'3I4,10R4,3I4,4(I4,16R4,2I4)',
     +                BNKSIZ, IND, INDVFS)
      endif
c
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in creating bank DVFS'
	 call ERLOGR ('VTXCTOV',ERWARN,0,0,message)
         return
      ENDIF

c fill header

      IW(INDVFS+DVFHDS) = 2
      IW(INDVFS+DVFVRN) = 1
      INDVFS = INDVFS + IW(INDVFS+DVFHDS)

c fill body 1 (vertex)

      IW(indvfs+dvfqfl) = IW(indvcs+dvcqfl)
      RW(indvfs+dvfxco) = RW(indvcs+dvcvx)
      RW(indvfs+dvfyco) = RW(indvcs+dvcvy)
      RW(indvfs+dvfzco) = RW(indvcs+dvcvz)
      RW(indvfs+dvfchi) = RW(indvcs+dvccsq)
      do i1=0,5
         RW(indvfs+dvfcvv+i1) = RW(indvcs+dvccov+i1)
      enddo
      IW(indvfs+dvfidf) = IW(indvcs+dvcvfl)

c fill body 2 (connected tracks). Start from tracks from bank i1.

      do i1 = 1, 2

         idvfs = indvfs + dvfntr + (i1-1)*19     ! pointer to body2 data
         idvcs = indvcs + trkpoi + (i1-1)*blksiz ! pointer to body2 data
         
         IW(idvfs+dvftra) = IW(idvcs+dvctrn)
         RW(idvfs+dvfcrv) = RW(idvcs+dvcqpt)
         RW(idvfs+dvfctv) = RW(idvcs+dvccot)
         RW(idvfs+dvfphv) = RW(idvcs+dvcphi)
         RW(idvfs+dvfchv) = RW(idvcs+dvctch)
         RW(idvfs+dvflnv) = RW(idvcs+dvclen)
c
c now copy covariance matrix after swim; in DVFS this matrix is
c broken into two pieces (the r-z covariance - 3 elements - and 
c the Kur-cot-phi covariance - 6 elements)
c        
         RW(idvfs+dvfc1v+0) = RW(idvcs+dvctcv+0)   ! <r,r>
         RW(idvfs+dvfc1v+1) = RW(idvcs+dvctcv+1)   ! <r,z>
         RW(idvfs+dvfc1v+2) = RW(idvcs+dvctcv+6)   ! <z,z>
c
         do i3 = 0, 5          ! covariance matrix after swim (momentum)
            RW(idvfs+dvfcov+i3) = RW(idvcs+dvctcv+9+i3)
         enddo
c
c now evaluate D0 and Z0 after fit and store them
c
         tx = SIN(RW(idvcs+dvcphi))
         ty = COS(RW(idvcs+dvcphi))
         RW(idvfs+dvfD0v) = ( RW(idvcs+dvctx)-RW(indvcs+dvcvx) )*ty
     &                    + ( RW(idvcs+dvcty)-RW(indvcs+dvcvy) )*tx 
         RW(idvfs+dvfdzv) =   RW(idvcs+dvctz)-RW(indvcs+dvcvz)
c
c finally store the flag First Hit vs Last Hit in DVFPID word (currently 
c not used)
c
         IW(idvfs+dvfpid) = IW(idvcs+dvcffl)
c
      enddo
c
c Now add track (or tracks) bank i2. Open this bank first.
c
      STATUS = BLOCAT(IW,'DVCS',i2,IND,INDVCS)
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in locating bank DVCS'
	 call ERLOGR ('VTXCTOV',ERWARN,0,0,message)
         return
      ENDIF
      TRKPOI = IW(INDVCS+DVCTRK)
      BLKSIZ = IW(INDVCS+DVCBLK)
      INDVCS = INDVCS + IW( INDVCS+DVCHDS )
c
c if itrk<3 than I have to add just one track from bank DVCS, the one
c corresponding to track # itrk; if itrk>=3, than both DVCS tracks have
c to be added to DVFS bank
c
      If (itrk .lt. 3) then     ! build a 3 tracks bank
c     =====================       =====================
c
         IW(indvfs+dvfntr) = 3  ! 3 tracks bank
c
         i1 = 3                 ! add third track to DVFS
         i3 = itrk              ! using track "itrk" from DVCS
         idvfs = indvfs + dvfntr + (i1-1)*19 ! pointer to body2 data
         idvcs = indvcs + trkpoi + (i3-1)*blksiz ! pointer to body2 data
            
         IW(idvfs+dvftra) = IW(idvcs+dvctrn)
         RW(idvfs+dvfcrv) = RW(idvcs+dvcqpt)
         RW(idvfs+dvfctv) = RW(idvcs+dvccot)
         RW(idvfs+dvfphv) = RW(idvcs+dvcphi)
         RW(idvfs+dvfchv) = RW(idvcs+dvctch)
         RW(idvfs+dvflnv) = RW(idvcs+dvclen)
c
c now copy covariance matrix after swim; in DVFS this matrix is
c broken into two pieces (the r-z covariance - 3 elements - and 
c the Kur-cot-phi covariance - 6 elements)
c        
         RW(idvfs+dvfc1v+0) = RW(idvcs+dvctcv+0)   ! <r,r>
         RW(idvfs+dvfc1v+1) = RW(idvcs+dvctcv+1)   ! <r,z>
         RW(idvfs+dvfc1v+2) = RW(idvcs+dvctcv+6)   ! <z,z>
c
         do i3 = 0, 5          ! covariance matrix after swim (momentum)
            RW(idvfs+dvfcov+i3) = RW(idvcs+dvctcv+9+i3)
         enddo
c
c now evaluate D0 and Z0 after fit and store them
c
         tx = SIN(RW(idvcs+dvcphi))
         ty = COS(RW(idvcs+dvcphi))
         RW(idvfs+dvfD0v) = ( RW(idvcs+dvctx)-RW(indvcs+dvcvx) )*ty
     &                    + ( RW(idvcs+dvcty)-RW(indvcs+dvcvy) )*tx 
         RW(idvfs+dvfdzv) =   RW(idvcs+dvctz)-RW(indvcs+dvcvz)
c
c finally store the flag First Hit vs Last Hit in DVFPID word (currently 
c not used)
c
         IW(idvfs+dvfpid) = IW(idvcs+dvcffl)
c            
c
      else                      ! build a 4 tracks bank
c     ====                        =====================
c
         IW(indvfs+dvfntr) = 4  ! number of tracks
c
         do i1 = 3, 4           ! add tracks 3 and 4
            i3 = i1 - 2         ! using tracks 1 and 2 from DVCS
            idvfs = indvfs + dvfntr + (i1-1)*19 ! pointer to body2 data
            idvcs = indvcs + trkpoi + (i3-1)*blksiz ! pointer to body2 data
            
            IW(idvfs+dvftra) = IW(idvcs+dvctrn)
            RW(idvfs+dvfcrv) = RW(idvcs+dvcqpt)
            RW(idvfs+dvfctv) = RW(idvcs+dvccot)
            RW(idvfs+dvfphv) = RW(idvcs+dvcphi)
            RW(idvfs+dvfchv) = RW(idvcs+dvctch)
            RW(idvfs+dvflnv) = RW(idvcs+dvclen)
c
c now copy covariance matrix after swim; in DVFS this matrix is
c broken into two pieces (the r-z covariance - 3 elements - and 
c the Kur-cot-phi covariance - 6 elements)
c        
            RW(idvfs+dvfc1v+0) = RW(idvcs+dvctcv+0) ! <r,r>
            RW(idvfs+dvfc1v+1) = RW(idvcs+dvctcv+1) ! <r,z>
            RW(idvfs+dvfc1v+2) = RW(idvcs+dvctcv+6) ! <z,z>
c
            do i3 = 0, 5        ! covariance matrix after swim (momentum)
               RW(idvfs+dvfcov+i3) = RW(idvcs+dvctcv+9+i3)
            enddo
c
c now evaluate D0 and Z0 after fit and store them
c
            tx = SIN(RW(idvcs+dvcphi))
            ty = COS(RW(idvcs+dvcphi))
            RW(idvfs+dvfD0v) = ( RW(idvcs+dvctx)-RW(indvcs+dvcvx) )*ty
     &                       + ( RW(idvcs+dvcty)-RW(indvcs+dvcvy) )*tx 
            RW(idvfs+dvfdzv) =   RW(idvcs+dvctz)-RW(indvcs+dvcvz)
c
c finally store the flag First Hit vs Last Hit in DVFPID word (currently 
c not used)
c
            IW(idvfs+dvfpid) = IW(idvcs+dvcffl)
c            
         enddo
c
      endif
c
      VTXMRGCAN = YESUCC
c
      return
      end

c=======================================================================
      INTEGER FUNCTION VTXCTOV(iii)
c=======================================================================
c
c routine that translates DVCS into DVFS bank
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      6-10-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
$$INCLUDE 'K$ITRK:DVCS.INC'
$$INCLUDE 'K$ITRK:DVFS.INC'
c      
      INTEGER STATUS, iii, i1, i2, IND, INDVCS, INDVFS, BLKSIZ
      INTEGER BNKSIZ, BLOCAT, BTYMKG, Idvfs, Idvcs, TRKPOI
      REAL    tx, ty
      CHARACTER*80 message
c
c=======================================================================
c
c set status to failure
c
      VTXCTOV = -1
c
c Open the Vertex Candidate bank DVCS
c
      STATUS = BLOCAT(IW,'DVCS',iii,IND,INDVCS)
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in locating bank DVCS'
	 call ERLOGR ('VTXCTOV',ERWARN,0,0,message)
         return
      ENDIF
      TRKPOI = IW(INDVCS+DVCTRK)
      BLKSIZ = IW(INDVCS+DVCBLK)
      INDVCS = INDVCS + IW( INDVCS+DVCHDS )
c
c create the corresponding Vertex bank DVFS 
c
      STATUS = BTYMKG(IW,'DVFS',iii,'3I4,10R4,3I4,2(I4,16R4,2I4)',
     +                BNKSIZ, IND, INDVFS)
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in creating bank DVFS'
	 call ERLOGR ('VTXCTOV',ERWARN,0,0,message)
         return
      ENDIF

c fill header

      IW(INDVFS+DVFHDS) = 2
      IW(INDVFS+DVFVRN) = 1
      INDVFS = INDVFS + IW(INDVFS+DVFHDS)

c fill body 1 (vertex)

      IW(indvfs+dvfqfl) = IW(indvcs+dvcqfl)
      RW(indvfs+dvfxco) = RW(indvcs+dvcvx)
      RW(indvfs+dvfyco) = RW(indvcs+dvcvy)
      RW(indvfs+dvfzco) = RW(indvcs+dvcvz)
      RW(indvfs+dvfchi) = RW(indvcs+dvccsq)
      do i1=0,5
         RW(indvfs+dvfcvv+i1) = RW(indvcs+dvccov+i1)
      enddo
      IW(indvfs+dvfidf) = IW(indvcs+dvcvfl)
      IW(indvfs+dvfntr) = IW(indvcs+dvcntr)

c fill body 2 (connected tracks)

      do i1 = 1, IW(indvcs+dvcntr)

         idvfs = indvfs + dvfntr + (i1-1)*19     ! pointer to body2 data
         idvcs = indvcs + trkpoi + (i1-1)*blksiz ! pointer to body2 data
         
         IW(idvfs+dvftra) = IW(idvcs+dvctrn)
         RW(idvfs+dvfcrv) = RW(idvcs+dvcqpt)
         RW(idvfs+dvfctv) = RW(idvcs+dvccot)
         RW(idvfs+dvfphv) = RW(idvcs+dvcphi)
         RW(idvfs+dvfchv) = RW(idvcs+dvctch)
         RW(idvfs+dvflnv) = RW(idvcs+dvclen)
c
c now copy covariance matrix after swim; in DVFS this matrix is
c broken into two pieces (the r-z covariance - 3 elements - and 
c the Kur-cot-phi covariance - 6 elements)
c        
         RW(idvfs+dvfc1v+0) = RW(idvcs+dvctcv+0)   ! <r,r>
         RW(idvfs+dvfc1v+1) = RW(idvcs+dvctcv+1)   ! <r,z>
         RW(idvfs+dvfc1v+2) = RW(idvcs+dvctcv+6)   ! <z,z>
c
         do i2 = 0, 5          ! covariance matrix after swim (momentum)
            RW(idvfs+dvfcov+i2) = RW(idvcs+dvctcv+9+i2)
         enddo
c
c now evaluate D0 and Z0 after fit and store them
c
         tx = SIN(RW(idvcs+dvcphi))
         ty = COS(RW(idvcs+dvcphi))
         RW(idvfs+dvfD0v) = ( RW(idvcs+dvctx)-RW(indvcs+dvcvx) )*ty
     &                    + ( RW(idvcs+dvcty)-RW(indvcs+dvcvy) )*tx 
         RW(idvfs+dvfdzv) =   RW(idvcs+dvctz)-RW(indvcs+dvcvz)
c
c finally store the flag First Hit vs Last Hit in DVFPID word (currently 
c not used)
c
         IW(idvfs+dvfpid) = IW(idvcs+dvcffl)
c
      enddo 
c
      VTXCTOV = YESUCC
c
      return
      end

c=======================================================================
      SUBROUTINE VTXCAN
c=======================================================================
c
c This routine stores candidate vertices in the candidate vertex bank 
c DVCS. This bank has the same structure as the VERSION 2 of the
c DVFS bank, except that it always assumes a two tracks vertex. 
c (In routine VTXMERG, that actually builds DVFS banks, this assumption
c  is released).
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      18-9-1997
c     ==============
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
$$INCLUDE 'K$ITRK:DVCS.INC'
c      
c External variables
c
      INTEGER BTYMKG, IND, INDDAT, STATUS
c
c Local variables
c
      INTEGER i, ii, Bnksiz, IWdata, ICdata
      REAL    sinphi, cosphi, sinthe, costhe
      CHARACTER*80 message
c
c common passed to VTXCAN from VTXMIN for creating candidate bank DVCS
c
      INTEGER Jfit, Nflg, Jlist(2), Flagfl(2)
      REAL    Vx, Vy, Vz, mixga(3,3), Vchi2, VTrkcsq(2)

      COMMON /DVCS_COM/ Jfit, Nflg, Jlist, Flagfl,
     +                  Vx, Vy, Vz, mixga, Vchi2, VTrkcsq
c
c=======================================================================
c
c create the Vertex Candidate bank DVCS, 
c
      STATUS = BTYMKG(IW,'DVCS',Nvxfit,'5I4,10R4,2I4,2(2I4,23R4)',
     +                BNKSIZ, IND, INDDAT)
      IF (STATUS.NE.YESUCC) THEN
         message = 'Error in creating bank DVCS'
	 call ERLOGR ('VTXCAN',ERWARN,0,0,message)
         return
      ENDIF
c
c fill bank header (parameters defined in DVCS.INC)
c
      IW( INDDAT + DVCHDS ) = DVCHDSIZ  ! Header size
      IW( INDDAT + DVCVRN ) = DVCVERNUM ! Version number
      IW( INDDAT + DVCTRK ) = DVCTRKPOI ! Pointer to connected track data
      IW( INDDAT + DVCBLK ) = DVCBLKSIZ ! Size of track informations block
c
c fill bank Body 1 (infos on vertex)
c
      INDDAT = INDDAT + IW(INDDAT+DVCHDS) 
      IW( INDDAT + DVCQFL ) = JFIT
      RW( INDDAT + DVCVX  ) = Vx
      RW( INDDAT + DVCVY  ) = Vy
      RW( INDDAT + DVCVZ  ) = Vz
      RW( INDDAT + DVCCSQ ) = Vchi2
      RW( INDDAT + DVCCOV + 0 ) = mixga(1,1)
      RW( INDDAT + DVCCOV + 1 ) = mixga(1,2)
      RW( INDDAT + DVCCOV + 2 ) = mixga(1,3)
      RW( INDDAT + DVCCOV + 3 ) = mixga(2,2)
      RW( INDDAT + DVCCOV + 4 ) = mixga(2,3)
      RW( INDDAT + DVCCOV + 5 ) = mixga(3,3)
      IW( INDDAT + DVCVFL ) = Nflg
      IW( INDDAT + DVCNTR ) = 2    ! Assume two tracks at this level
c 
c Fill bank Body 2 (informations on connected tracks)
c Note that the "track length" is defined as the length of the arc
c delimited by the Vertex and the track end used for extrapolation
c (First Hit or Last Hit)
c
      do i = 1, IW(INDDAT+DVCNTR)
  
         IWdata = INDVWRK+VWRNCO*(Jlist(i)-1) ! pointer into VWRK       
         ICdata = INDDAT + DVCTRKPOI + (i-1)*DVCBLKSIZ ! pointer into DVCS
         IW( ICdata + DVCTRN ) = IW( IWdata + VWDTFS )
         IW( ICdata + DVCFFL ) = Flagfl(i)
         RW( ICdata + DVCTCH ) = VTrkcsq(i)

         If ( Flagfl(i) .lt. 0 ) then ! FH of track connected to vertex
            RW( ICdata + DVCTX  ) = RW( IWdata + VWXVX  )
            RW( ICdata + DVCTY  ) = RW( IWdata + VWYVX  )
            RW( ICdata + DVCTZ  ) = RW( IWdata + VWZVX  )
            RW( ICdata + DVCQPT ) = RW( IWdata + VWCUVX )
            costhe = RW( IWdata + VWTZVX )
            sinthe = sqrt( 1 - costhe**2 )
            cosphi = RW( IWdata + VWTXVX ) / sinthe
            sinphi = RW( IWdata + VWTYVX ) / sinthe 
            RW( ICdata + DVCPHI ) = ATAN2(sinphi,cosphi)
            RW( ICdata + DVCCOT ) = costhe/sinthe
            RW( ICdata + DVCLEN ) = RW( IWdata + VWTLDC ) +
     +      RW( IWdata + VWTLBU ) + RW( IWdata + VWTLBI ) +
     +      RW( IWdata + VWTLVX )
            do ii = 0, 14       ! covariance matrix after swim
               RW( ICdata + DVCTCV + ii ) = RW( IWdata + VWERRV + ii)
            enddo
         else                         ! LH of track connected to vertex
            RW( ICdata + DVCTX  ) = RW( IWdata + VWXVL  )
            RW( ICdata + DVCTY  ) = RW( IWdata + VWYVL  )
            RW( ICdata + DVCTZ  ) = RW( IWdata + VWZVL  )
            RW( ICdata + DVCQPT ) = RW( IWdata + VWCUVL )
            costhe = RW( IWdata + VWTZVL )
            sinthe = sqrt( 1 - costhe**2 )
            cosphi = RW( IWdata + VWTXVL ) / sinthe
            sinphi = RW( IWdata + VWTYVL ) / sinthe 
            RW( ICdata + DVCPHI ) = ATAN2(sinphi,cosphi)
            RW( ICdata + DVCCOT ) = costhe/sinthe
            RW( ICdata + DVCLEN ) = RW( IWdata + VWTLVL )
            do ii = 0, 14       ! covariance matrix after swim
               RW( ICdata + DVCTCV + ii ) = RW( IWdata + VWERRV + ii)
            enddo
         endif
c
      enddo     
c
      return
      end
c

c=======================================================================
      SUBROUTINE VTXCRSS(Nreg,ilist,XINT,IERR,TANGENT)
c=======================================================================
c
c This routine looks for an intersection between two helices and, if
c found (within cuts), it perform a geometrical iterative procedure
c to find the best CANDITATE VERTEX to be fed to the minimization routine
c (this iterative procedure is described below, in this routine).
c This routine has been obtained by "cannibalizing" some sections of
c a previous routine by D.Coppage, from ARGUS, modified by A.Calcaterra,
c that was operating just on the transverse plane.
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      23-9-1997
c     ==============
c
c     Input data:
c     ===========
c     Nreg           region of extrapolation (1 is DC ;  >1 is VC.or.BP)
c     ilist          track numbers (with sign! "-" means "backward swim")
c
c     Output data:
c     ============
c     XINT(3)        coordinates of intersection
c     IERR           error code (see below)
c     TANGENT        flag set when the two circles on x-y plane are "tangent 
c                    within cuts" or, for a positive crossing, when the
c                    two extrapolated tracks are "parallel within cuts"
c                    (this last check is used in "constrained fits").
c
c     Error codes:
c     ============
c     IERR = 0       found crossing (check TANGENT for "parallelism")
c     IERR = 1       circles on x-y don't intersecate (check TANGENT for
c                    "tangent within cuts")
c     IERR = 2       OK intersection in x-y, but z separation above cuts
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c      

c
c=======================================================================
c
C
      REAL PROXIM     ! routine from CERNLIB (MI)
C
      LOGICAL EXTCRC,INTCRC,tangent
      INTEGER LSTRG1,LSTRG2,INRMST,REG,REGION,NDX
      INTEGER IL,IG
      REAL    RRMIN,RR,TRMIV
      REAL    DCC,RLCOS,ARGMNT,A_HALF
      REAL    DLTZ,SGNIL,SGNIG,DLTCPL,DLTCMN,ANGNW
      REAL    VS(3,2),TS(3,2),VH(3),RHO(2), XINT(3)
      REAL    ANGSTR(2),XCTR(2,2),CTGTHE(2),U(2),ANG(2),ZPL(2),ZMN(2)
      REAL    SGNQB(2),ANGCTR(2),TURNPL(2),TURNMN(2)
C
CMI
      INTEGER LITER, IERR, LTK, LERRS, ilist(2), jlist(2)
      INTEGER nreg, Offset
      REAL    ZSEP, XINTO(3), VA(3), VB(3), XINTDIS, AZIMUT(2)
      REAL    ZSEPPL, ZSEPMN, PARAL, AVCOTHE
CMI
C========================================================================
C
c Initialization of parameters (note that extrapolation sign, coded into
c ILIST, is not relevant for this routine). VWRBLK is the block dimension
c inside VWRK bank
c
      IERR = 0
      Offset = VWRBLK * (Nreg - 1)   ! pointer to region of extrapolation
      Jlist(1) = abs(Ilist(1))
      Jlist(2) = abs(Ilist(2))
c
      DO NDX=1,2

         if ( ilist(ndx)*iswmback .gt. 0 ) then
            VS(1,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWXFH)
            VS(2,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWYFH)
            VS(3,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWZFH)
            TS(1,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTXFH)
            TS(2,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTYFH)
            TS(3,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTZFH)
        else
            VS(1,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWXLH)
            VS(2,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWYLH)
            VS(3,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWZLH)
            TS(1,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTXLH)
            TS(2,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTYLH)
            TS(3,NDX) = RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWTZLH)
        endif
c
        CALL MGFLD(VS(1,NDX),VH)
        IF (ABS(VH(3)) .LE. 1.0E-4) THEN
          IERR = 7
          RETURN
        ELSE
C
C  KLOE convention: RHO is >0 for a positive particle, turning CLOCKWISE.
          RHO(NDX) = 1./
     + (CONVERS*VH(3)*RW(Indvwrk+vwrnco*(Jlist(ndx)-1)+Offset+VWCUFH))
          SGNQB(NDX) = SIGN(1.0,RHO(NDX))
C
C  This is the angle from the center of curvature to the starting point
          ANGSTR(NDX)=
     +     ATAN2(SGNQB(NDX)*TS(1,NDX), -SGNQB(NDX)*TS(2,NDX))
C
C  These are the coordinates of the center of curvature
          TRMIV = 1./SQRT(TS(1,NDX)**2+TS(2,NDX)**2)
          XCTR(1,NDX) = VS(1,NDX) + RHO(NDX)*TS(2,NDX)*TRMIV
          XCTR(2,NDX) = VS(2,NDX) - RHO(NDX)*TS(1,NDX)*TRMIV
C
C  This is the cotangent of theta (or the tangent of lambda, the dip angle)
          CTGTHE(NDX) = TS(3,NDX)/SQRT(1.0-TS(3,NDX)*TS(3,NDX))
          RHO(NDX) = ABS(RHO(NDX))
        ENDIF
      ENDDO
C ----------------->>            ASSURE THAT RHO(IG) .GT. RHO(IL)
      IF (RHO(1) .LT. RHO(2)) THEN
        IL=1
        IG=2
      ELSE
        IL=2
        IG=1
      ENDIF
C
C  U is the vector joining the centers of the two circles in the tr. plane
      U(1) = XCTR(1,IG)-XCTR(1,IL)
      U(2) = XCTR(2,IG)-XCTR(2,IL)
      DCC  = SQRT(U(1)**2+U(2)**2)
C
C ----------------->>              TEST FOR ALMOST TANGENT CIRCLES
C
      EXTCRC = DCC .GT. (RHO(1)+RHO(2))
      INTCRC = DCC .LT. (RHO(IG)-RHO(IL))
C
      IF (EXTCRC .OR. INTCRC) THEN
C
C  The two circles have *NO* intersections. Use the point of closest 
C  approach to both helices. 
C  Finally, if the circles are "tangent within cuts", flag TANGENT = .true.
CMI In this case set error flag
        IERR = 1
CMI
        ANGCTR(IL) = ATAN2(U(2),U(1))
        ANGCTR(IG) = ATAN2(-U(2),-U(1))
        IF (INTCRC) ANGCTR(IL) = ANGCTR(IG)
C
        TURNPL(IL) = PROXIM(ANGCTR(IL)-ANGSTR(IL),0.)
        ZPL(IL) = VS(3,IL) - SGNQB(IL)*TURNPL(IL)*RHO(IL)*CTGTHE(IL)
C
        TURNPL(IG) = PROXIM(ANGCTR(IG)-ANGSTR(IG),0.)
        ZPL(IG) = VS(3,IG) - SGNQB(IG)*TURNPL(IG)*RHO(IG)*CTGTHE(IG) 
C
        DLTZ = ABS(ZPL(IG)-ZPL(IL))
        IF (INTCRC) THEN
          A_HALF = (RHO(IG)-RHO(IL)-DCC)/2.
        ELSE
          A_HALF = (DCC-RHO(IG)-RHO(IL))/2.
        ENDIF
        XINT(1) = XCTR(1,IL) + (RHO(IL)+A_HALF)*COS(ANGCTR(IL))
        XINT(2) = XCTR(2,IL) + (RHO(IL)+A_HALF)*SIN(ANGCTR(IL))
        XINT(3) = 0.5*(ZPL(IG)+ZPL(IL))
        ZSEP = abs(ZPL(IG)-ZPL(IL))
C      
        IF (INTCRC) THEN
          TANGENT = RHO(IG)-DCC-RHO(IL) .LT. AMAX1(ABSTOLER,TOLER*DCC)
        ELSE
          TANGENT = DCC-RHO(1)-RHO(2) .LT. 
     +              AMAX1(ABSTOLER,TOLER*(RHO(1)+RHO(2)))
        ENDIF
      ELSE
C
C  The two circles have exactly two intersections
        TANGENT = .FALSE.
C
C  This is the distance from the center of circle IL to the chord
C  between the two intersections.
        RLCOS  = ((DCC**2-RHO(IG)**2)+RHO(IL)**2)/(2.*DCC)
        ARGMNT = RLCOS/RHO(IL)
        IF (ABS(ARGMNT) .GT. 1.) THEN
          ARGMNT = SIGN(1.,ARGMNT)
        ENDIF
C
C  This is a half of the chord angle, defined positive
        ANG(IL) = ACOS(ARGMNT)
C
C  Same for circle IG....
        ARGMNT = (DCC-RLCOS)/RHO(IG)
        IF (ABS(ARGMNT) .GT. 1.) THEN
          ARGMNT = SIGN(1.,ARGMNT)
        ENDIF
        ANG(IG) = ACOS(ARGMNT)
C
C  This is the angle of center IG seen from IL, correctly in (-PI,PI)
        ANGCTR(IL) = ATAN2(U(2),U(1))
        SGNIL = SIGN(1.0,ANGCTR(IL))
C
C  And here is the angle of center IL seen from IG, also in (-PI,PI)
        ANGCTR(IG) = ATAN2(-U(2),-U(1))
        SGNIG = SIGN(1.0,ANGCTR(IG))
C
C  These 4 TURNs are the ang.distances from the 2 starting points up to the
C  intersections (2 for each track). Signs are geometric: clockwise --> < 0
        TURNPL(IL) = PROXIM(ANGCTR(IL)+SGNIL*ANG(IL)-ANGSTR(IL),0.)
C
C  The 4 - signs below take into account the KLOE convention above
        ZPL(IL) = VS(3,IL) - SGNQB(IL)*TURNPL(IL)*RHO(IL)*CTGTHE(IL)
C
        TURNPL(IG) = PROXIM(ANGCTR(IG)+SGNIG*ANG(IG)-ANGSTR(IG),0.)
        ZPL(IG) = VS(3,IG) - SGNQB(IG)*TURNPL(IG)*RHO(IG)*CTGTHE(IG)
C
        TURNMN(IL) = PROXIM(ANGCTR(IL)-SGNIL*ANG(IL)-ANGSTR(IL),0.)
        ZMN(IL) = VS(3,IL) - SGNQB(IL)*TURNMN(IL)*RHO(IL)*CTGTHE(IL)
C
        TURNMN(IG) = PROXIM(ANGCTR(IG)-SGNIG*ANG(IG)-ANGSTR(IG),0.)
        ZMN(IG) = VS(3,IG) - SGNQB(IG)*TURNMN(IG)*RHO(IG)*CTGTHE(IG)
C
C The choice of the good intersection is based on the Z-separation 
c between the two helices. If both separations are small, check angular
c distance
c
        ZSEPMN = abs(ZMN(IG)-ZMN(IL))
        DLTCMN = TURNMN(IL)**2+TURNMN(IG)**2
        ZSEPPL = abs(ZPL(IG)-ZPL(IL))
        DLTCPL = TURNPL(IL)**2+TURNPL(IG)**2

        if ( AMAX1(ZSEPPL,ZSEPMN) .lt. 2. ) then
           if ( DLTCPL .lt. DLTCMN ) goto 112
        else
           if ( ZSEPPL .lt. ZSEPMN ) goto 112
        endif

        ZSEP = ZSEPMN
        ANGNW   = ANGCTR(IL) - SGNIL*ANG(IL)
        XINT(3) = 0.5*(ZMN(IG)+ZMN(IL))
c Azimuthal angle at intersection point. 
        AZIMUT(IG) = ATAN2(TS(2,IG),TS(1,IG)) + TURNMN(IG)
        AZIMUT(IL) = ATAN2(TS(2,IL),TS(1,IL)) + TURNMN(IL)

        goto 113
 112    continue
           ZSEP = ZSEPPL
           ANGNW   = ANGCTR(IL) + SGNIL*ANG(IL)
           XINT(3) = 0.5*(ZPL(IG)+ZPL(IL))
           AZIMUT(IG) = ATAN2(TS(2,IG),TS(1,IG)) + TURNPL(IG)
           AZIMUT(IL) = ATAN2(TS(2,IL),TS(1,IL)) + TURNPL(IL)
 113       continue

cmi Here check for parallelism (used later in minimization procedure)
        PARAL = abs( PI - abs(AZIMUT(IG)-AZIMUT(IL)) )
        if ( PARAL .lt. PARALCUT ) TANGENT = .true.
cmi

        XINT(1) = XCTR(1,IL) + RHO(IL)*COS(ANGNW)
        XINT(2) = XCTR(2,IL) + RHO(IL)*SIN(ANGNW)
      ENDIF
C
CMI Check wether z_separation is small enough. If not flag it out. 
CMI
      AVCOTHE = amax1(abs(CTGTHE(IL)),abs(CTGTHE(IG)))
      If (ZSEP.gt.ZSEPMAX*(1+AVCOTHE)) then
         IERR = 2
         goto 999
      Endif
CMI
cmi
cmi now an iterative procedure starts that tends to improve the
cmi initial conditions. The vectors VA and VB, joining XINT with the 
cmi points closest to XINT, belonging to the two tracks, are built.
cmi The vector sum (VA+VB)/2 is evaluated and XINT is moved by this
cmi amount. The iteration ends either after a certain number of attempts
cmi (NITER) or when the new position is far from the old one less than
cmi CUTINTER cm.
cmi
cmi initialize counter
c      LITER = 0
c
c      do while (LITER .le. NITERCRSS)
c         LITER = LITER + 1
c
cmi keep track of old interaction point
c         XINTO(1) = XINT(1)
c         XINTO(2) = XINT(2)
c         XINTO(3) = XINT(3)
c
cmi get vector VA
c         LTK = ILIST(1)
c         call VXSWIM(XINTO, LTK, TRKBNK(1,4,LTK), LERRS)
c         if (LERRS .ne. 0) goto 999        ! bad track swim
c         VA(1) = XINTO(1) - TRKBNK(2,4,LTK)
c         VA(2) = XINTO(2) - TRKBNK(3,4,LTK)
c         VA(3) = XINTO(3) - TRKBNK(4,4,LTK)
c
cmi get vector VB
c         LTK = ILIST(2)
c         call VXSWIM(XINTO, LTK, TRKBNK(1,4,LTK), LERRS)
c         if (LERRS .ne. 0) goto 999        ! bad track swim
c         VB(1) = XINTO(1) - TRKBNK(2,4,LTK)
c         VB(2) = XINTO(2) - TRKBNK(3,4,LTK)
c         VB(3) = XINTO(3) - TRKBNK(4,4,LTK)
c
ccmi get new interaction point
c         XINT(1) = XINTO(1) + (VA(1)+VB(1))/2.
c         XINT(2) = XINTO(2) + (VA(2)+VB(2))/2.
c         XINT(3) = XINTO(3) + (VA(3)+VB(3))/2.
c
ccmi check distance with old interaction point
c         XINTDIS = ( XINT(1) - XINTO(1) )**2 +
c     +             ( XINT(2) - XINTO(2) )**2 +
c     +             ( XINT(3) - XINTO(3) )**2 
c        XINTDIS = sqrt(XINTDIS)
c
c         if (XINTDIS .lt. CUTINTER) goto 999
c
c      enddo
ccmi
c
 999  continue
      RETURN
      END

c=============================================================
      integer function VTXSWM(iii,Ireg,XR)
c=============================================================
c
c This routine finds the coordinates of the point XP, belonging to
c track iii, CLOSEST IN SPACE to a given point XR (for example a 
c candidate vertex).
c The point is found via an iterative procedure.
c - If Ireg=1-4 the track is extrapolated moving backward starting
c   from the corresponding "First Hit" (1=FH,2=DC,3=BI,4=BU - see
c   VTXFIN.INC). The difference between using one of these "First 
c   hits" is the energy loss due to DC and BP boundaries.
c - If Ireg=6 the track is extrapolated from the last point, in the DC
c   chain of hits, moving outward.
c - If Ireg=0 then the routine starts from the FH and it tries to find
c   the direction of extrapolation by rotating using Phi and Phi+-2Pi,
c   chosing the "best one" [FOR THE MOMENT THIS IS NOT WORKING].
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      25-9-1997
c     ==============
c
c     Input:
c     ======
c     iii                 Track number
c     Ireg                Region of extrapolation (see VTXFIN.INC)
c     XR(3)               Coordinates of external point
c
c     Output:
c     =======
c     the following variables are filled inside bank VWRK:
c
c     RW(INDVWRK+...+VWXVi), VWYVi, VWZVi, VWTXVi, VWTYVi, VWTZVi, 
c                            VWCUVi, VWTLVi
c
c     (position, tangent, Q/Pt and Track Length from vertex to FH or LH)
c
c     where i=L , if Ireg=NLH (Vertex at Last point) , or i=X otherwise.
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c      
c Global declarations
c
      INTEGER NITER                   ! number of iterations IN VTXSWM
      PARAMETER (NITER=10)
      REAL    EPSILON                 ! End of iteration procedure
      PARAMETER (EPSILON=0.1)         
      REAL    ALPHATOL
      PARAMETER (ALPHATOL=0.3)        ! Tolerance on "wrong extrapolation"
c
c Local declarations
c
      INTEGER Ireg, iii, I1, i2, IWDATA
      REAL xfh(3), vh(3)
      REAL XP(3), XR(3), X0, Y0, Z0, TX0, TY0, TZ0, Bfield, Alphatot
      REAL rho, Q, costhe, sinthe, cotthe, sinphi, cosphi, Xc, Yc
      REAL Rnorm, sinalpha, cosalpha, alpha, PRdist, Rcur, prdistold
      REAL PX(NITER),PY(NITER),PZ(NITER),TPX(NITER),TPY(NITER),TPZ(NITER)
      CHARACTER*80 message
c
c================================================================

c --- Get initial conditions according to IREG parameter
c
      XP(1) = 0.
      XP(2) = 0.
      XP(3) = 0.
      VTXSWM = -1   ! set initial status to failure
      IWDATA = INDVWRK+VWRNCO*(iii-1) ! data pointer for track iii in VWRK

c check IREG with VWREG parameter in VWRK bank
      if ( IREG.ne.NLH .and. IREG.gt.IW(IWDATA+VWREG) ) then
         message = 'Track cannot be extrapolated in this region'
	 call ERLOGR ('VTXSWM',ERWARN,0,0,message)
         return
      endif

      If (IREG.eq.NFH .OR. IREG.EQ.0) then

         X0 = RW(IWdata+VWXFH)
         Y0 = RW(IWdata+VWYFH)
         Z0 = RW(IWdata+VWZFH)
         TX0 = RW(IWdata+VWTXFH)
         TY0 = RW(IWdata+VWTYFH)
         TZ0 = RW(IWdata+VWTZFH)
c get B field at First Hit
         xfh(1) = X0
         xfh(2) = Y0
         xfh(3) = Z0
         call MGFLD(xfh,Vh)
         Bfield = Vh(3) 
         rho = CONVERS*Bfield*RW(IWdata+VWCUFH)
         if ( abs(rho).lt.0.0001 ) then
            message = 'Error in swimming track'
            call ERLOGR ('VTXSWM',ERWARN,0,0,message)
            return            
         endif
         Q = SIGN(1.,rho)
         rho = 1./rho

      elseif (IREG.eq.NVC) then

         X0 = RW(IWdata+VWXDC)
         Y0 = RW(IWdata+VWYDC)
         Z0 = RW(IWdata+VWZDC)
         TX0 = RW(IWdata+VWTXDC)
         TY0 = RW(IWdata+VWTYDC)
         TZ0 = RW(IWdata+VWTZDC)
c get B field at First Hit
         xfh(1) = X0
         xfh(2) = Y0
         xfh(3) = Z0
         call MGFLD(xfh,Vh)
         Bfield = Vh(3) 
         rho = CONVERS*Bfield*RW(IWdata+VWCUDC)
         if ( abs(rho).lt.0.0001 ) then
            message = 'Error in swimming track'
            call ERLOGR ('VTXSWM',ERWARN,0,0,message)
            return            
         endif
         Q = SIGN(1.,rho)
         rho = 1./rho

      elseif (IREG.eq.NBI) then

         X0 = RW(IWdata+VWXBI)
         Y0 = RW(IWdata+VWYBI)
         Z0 = RW(IWdata+VWZBI)
         TX0 = RW(IWdata+VWTXBI)
         TY0 = RW(IWdata+VWTYBI)
         TZ0 = RW(IWdata+VWTZBI)
c get B field at First Hit
         xfh(1) = X0
         xfh(2) = Y0
         xfh(3) = Z0
         call MGFLD(xfh,Vh)
         Bfield = Vh(3) 
         rho = CONVERS*Bfield*RW(IWdata+VWCUBI)
         if ( abs(rho).lt.0.0001 ) then
            message = 'Error in swimming track'
            call ERLOGR ('VTXSWM',ERWARN,0,0,message)
            return            
         endif
         Q = SIGN(1.,rho)
         rho = 1./rho

      elseif (IREG.eq.NBU) then

         X0 = RW(IWdata+VWXBU)
         Y0 = RW(IWdata+VWYBU)
         Z0 = RW(IWdata+VWZBU)
         TX0 = RW(IWdata+VWTXBU)
         TY0 = RW(IWdata+VWTYBU)
         TZ0 = RW(IWdata+VWTZBU)
c get B field at First Hit
         xfh(1) = X0
         xfh(2) = Y0
         xfh(3) = Z0
         call MGFLD(xfh,Vh)
         Bfield = Vh(3) 
         rho = CONVERS*Bfield*RW(IWdata+VWCUBU)
         if ( abs(rho).lt.0.0001 ) then
            message = 'Error in swimming track'
            call ERLOGR ('VTXSWM',ERWARN,0,0,message)
            return            
         endif
         Q = SIGN(1.,rho)
         rho = 1./rho

      elseif (IREG.eq.NLH) then

         X0 = RW(IWdata+VWXLH)
         Y0 = RW(IWdata+VWYLH)
         Z0 = RW(IWdata+VWZLH)
         TX0 = RW(IWdata+VWTXLH)
         TY0 = RW(IWdata+VWTYLH)
         TZ0 = RW(IWdata+VWTZLH)
c get B field at First Hit
         xfh(1) = X0
         xfh(2) = Y0
         xfh(3) = Z0
         call MGFLD(xfh,Vh)
         Bfield = Vh(3) 
         rho = CONVERS*Bfield*RW(IWdata+VWCULH)
         if ( abs(rho).lt.0.0001 ) then
            message = 'Error in swimming track'
            call ERLOGR ('VTXSWM',ERWARN,0,0,message)
            return            
         endif
         Q = SIGN(1.,rho)
         rho = 1./rho

      else

         message = 'Unknown detector region'
	 call ERLOGR ('VTXSWM',ERWARN,0,0,message)
         return

      endif

c --- Get helix parameters (center, radius and cot(theta))

      costhe = TZ0
      sinthe = sqrt(1-costhe**2)
      cotthe = costhe/sinthe
      cosphi = TX0/sinthe
      sinphi = TY0/sinthe
      Xc     = X0 + rho*sinphi
      Yc     = Y0 - rho*cosphi

c --- Get starting point of iterative procedure

c Starting point P1 of iterative procedure is on the line C-R. Find
c rotation angle "alpha" from 0 to P1. 
c While doing a backward extrapolation, the sign of Alpha is positive
c (counterclockwise) for positive tracks and negative for negative
c tracks. The situation is the opposite for forward extrapolations (from
c the last point moving outward).
c HOWEVER this approach must have a CONTROLLED TOLERANCE. In fact, the
c candidate vertex may be put in the "wrong position with respect to X0";
c in this situation "alpha" has the wrong sign.

c 1 - get SIN of rotation angle using vector product:

      rnorm = ( (X0-Xc)**2 + (Y0-Yc)**2 ) *
     +        ( (Xr(1)-Xc)**2 + (Xr(2)-Yc)**2 )
      rnorm = sqrt(rnorm)
      sinalpha = (X0-Xc)*(Xr(2)-Yc) - (Y0-Yc)*(Xr(1)-Xc)
      sinalpha = sinalpha / rnorm
      If (abs(sinalpha) .ge. 1.0) sinalpha = SIGN(0.9999,sinalpha)

c 2 - check sign according to direction of extrapolation and track charge
c     (the passage from sinalpha to cosalpha is made in order to correctly
c     define the angle alpha in the interval [-pi;pi])

      If ( Ireg.eq.NLH ) then ! sign of alpha opposite to charge

         if ( sinalpha*Q .lt. 0 ) then      ! normal situation
            cosalpha = sqrt(1. - sinalpha**2)
            alpha = -Q * ACOS(cosalpha)     ! defined in [-pi:pi]
         else                               ! wrong situation; check tolerance
            cosalpha = sqrt(1. - sinalpha**2)
            alpha = Q * ACOS(cosalpha)
            if (abs(alpha).gt.alphatol) return
         endif

      else                  ! alpha same sign as charge

         if ( sinalpha*Q .gt. 0 ) then      ! normal situation
            cosalpha = sqrt(1 - sinalpha**2)
            alpha = Q * ACOS(cosalpha)
         else                               ! wrong situation; check tolerance
            cosalpha = sqrt(1 - sinalpha**2)
            alpha = -Q * ACOS(cosalpha)
            if (abs(alpha).gt.alphatol) return
         endif

      endif

c 3 - get tangent and coordinates at P1, start of iteration, through a
c rotation of "alpha" 

      TPX(1) = ( cosphi*cos(Alpha) - sinphi*sin(alpha) ) * sinthe
      TPY(1) = ( sinphi*cos(Alpha) + cosphi*sin(alpha) ) * sinthe
      TPZ(1) = costhe
      PX(1)  = Xc - rho*TPY(1)/sinthe
      PY(1)  = Yc + rho*TPX(1)/sinthe
      PZ(1)  = Z0 - rho*alpha*cotthe

c keep track of rotation angle
      alphatot = alpha

c----------------------------------------------------------------------------
c
c Now start iterative procedure
c
      PRdistold = 9999.

      Do i1 = 2, NITER

         i2 = i1

c get distance P(i-1) - R', R' being the projection of R on the 3-d tangent
c to the helix; this distance is signed.

         PRdist = (PX(i1-1)-Xr(1))*TPX(i1-1)+(PY(i1-1)-Xr(2))*TPY(i1-1)
     +          + (PZ(i1-1)-Xr(3))*TPZ(i1-1)

c check if distance increased in this iteration; if yes exit

         if ( abs(PRdist) .gt. abs(PRdistold) ) then
            i2 = i1-1
            goto 999
         endif

c check if distance is below cut

         if (abs(PRdist) .lt. epsilon ) goto 999

c If not find new point and iterate. New point is found moving by an
c arc of length PRdist along the curve. Note that PRdist is a signed 
c quantity (and RHO, too).

         alpha  = PRdist / rho

         TPX(i1) = TPX(i1-1)*cos(Alpha) - TPY(i1-1)*sin(alpha)
         TPY(i1) = TPY(i1-1)*cos(Alpha) + TPX(i1-1)*sin(alpha)
         TPZ(i1) = TPZ(i1-1)
         PX(i1)  = Xc - rho*TPY(i1)/sinthe
         PY(i1)  = Yc + rho*TPX(i1)/sinthe
         PZ(i1)  = PZ(i1-1) - rho*alpha*cotthe

         PRdistold = PRdist

c keep track of rotation angle
      alphatot = alphatot + alpha

      enddo

c------------------------------------------------------------------------

 999  continue

c output results

      Rcur = 1./(convers*Bfield*Rho)
      If (Ireg .ne. NLH) then
         RW(IWdata+VWXVX)  =  PX(I2-1)
         RW(IWdata+VWYVX)  =  PY(I2-1) 
         RW(IWdata+VWZVX)  =  PZ(I2-1)
         RW(IWdata+VWTXVX) = TPX(I2-1)
         RW(IWdata+VWTYVX) = TPY(I2-1)
         RW(IWdata+VWTZVX) = TPZ(I2-1)         
         RW(IWdata+VWCUVX) = Rcur
         RW(IWdata+VWTLVX) = abs(alphatot*rho)
      else
         RW(IWdata+VWXVL)  =  PX(I2-1)
         RW(IWdata+VWYVL)  =  PY(I2-1) 
         RW(IWdata+VWZVL)  =  PZ(I2-1)
         RW(IWdata+VWTXVL) = TPX(I2-1)
         RW(IWdata+VWTYVL) = TPY(I2-1)
         RW(IWdata+VWTZVL) = TPZ(I2-1)         
         RW(IWdata+VWCUVL) = Rcur
         RW(IWdata+VWTLVL) = abs(alphatot*rho)
      ENDIF

      VTXSWM = YESUCC

      return
      end

c=======================================================================
      SUBROUTINE VTXMIN(Nflag,Ntrfit,ILIST,XVX,CSQ,IFIT,XCN,CONSTR)
c=======================================================================
c
c Routine perfoming the minimization of the distance tracks - candidate
c vertex. 
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      26-9-1997
c     ==============
c
c     Input:
c     ======
c           Nflag         Section of program in which cand. vertex was found
c           Ntrfit        Number of tracks to be fitted
c           Ilist(Ntrfit) Track numbers
c           XVX(3)        Coordinates of candidate vertex
c           Constr        Logical value; if true then do a constrained  fit
c           XCN(3)        Coordinates of the constraint
c
c     Output:
c     =======
c           XVX(3)        Coordinates of fitted vertex
c           CSQ           CHI2 value of this fit
c           Ifit          flag (values in VTXFIN)
c                         = FITGOLD -> "successfull" fit
c                         = FITSILVER -> "acceptable" fit
c                         = FITBAD -> fit converged but CHI2 too high
c                         = FITNOCONV -> fit didn't converge
c                         = FITNEGCHI2 -> negative CHI2
c                         = FITMAXITER -> too many iterations
c                         = FITTRKEXTR -> error in track extrapolation (VTXSWM)
c                         = FITOUTDC -> cand vertex outside DC boundaries
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'				
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c      
c External declarations
c
      INTEGER Istat, VTXSWM, IWDATA
c
c Local declarations
c     
      INTEGER i1, i2, iii, Niter, ilist(10), ibadtk, Ntrfit, IWfitflg(5)
      INTEGER Ireg, Iireg, Idum(3), nerror, Tolerate, Ifit, Nflag
      REAL    Xcn(3), miverr(3), midv(3), vershift, vershprev
      REAL    mixgb(3), vh(3), rho, theta, Parallel
      REAL    rpca(3), trpca(3), cotheta
      REAL    midx, midy, midt, midz, Xvx(3), txynorm, cosa, sina
      REAL    sig2t, sig2z, sigtz, denom, vart, varz, covar, csq
      REAL    Trkcsq(5), den, mitx, mity
      REAL    mixgb1, mixgb2, mixgb3, mixga11, mixga12, mixga13
      REAL    mixga22, mixga23, mixga33, xga(3,3)
      CHARACTER*80 message
      LOGICAL Constr, converg, accept, verterr
      REAL    Rdc, Rbp, rvertex, con1, con2, con3
      EQUIVALENCE (TIRGVX(1),Rdc),(TIRGVX(2),Rbp)
c
c common passed to VTXCAN from VTXMIN for creating candidate bank DVCS
c
      INTEGER Jfit, Nflg, Jlist(2), Flagfl(2)
      REAL    Vx, Vy, Vz, mixga(3,3), Vchi2, VTrkcsq(2)

      COMMON /DVCS_COM/ Jfit, Nflg, Jlist, Flagfl,
     +                  Vx, Vy, Vz, mixga, Vchi2, VTrkcsq
c
c
c=======================================================================
c
c initialize variables
c
      if ( Ntrfit .gt. 10 ) then
         message = 'More than 10 tracks connected to a vertex'
         call ERLOGR ('VTXMIN',ERWARN,0,0,message)
         return
      endif
c
      verterr = .false. ! set to true if vertex outside detector boundaries
      NITER = 0                 ! iteration nummber
      vershprev = 999999.       ! vertex shift (decrease at each iteration)
      Tolerate = 0              ! we tolerate one "increase" in vertex shift
      Parallel = 1.             ! if "parallesim" flag is up (CONSTR=.true.)
      If (constr) Parallel=2.   ! then loose convergence criteria.
c
c-----------------------------------------------------------------------------
c Find region of candidate vertex. 
c Note that this region needs not to be the same for all tracks. 
c For example, if the vertex is in the DC region, than one 
c track may have the First Hit connected to it (Ireg=NFH),
c while the other may have the Last Hit (Ireg=NLH).
c
      rvertex = sqrt( xvx(1)**2 + xvx(2)**2 )
      if ( rvertex .lt. Rbp ) then
         Ireg = NBI
      elseif  ( rvertex .lt. Rdc ) then
         Ireg = NVC
      elseif  ( rvertex .lt. Rcal*1.05 ) then ! 50f tolerance
         Ireg = NFH             ! Assume First Hit (eventually change later)
      else
         message = 'Candidate vertex outside calorimeter boundaries'
         call ERLOGR ('VTXMIN',ERWARN,0,0,message)
         verterr = .true. ! raise a flag that will be checked later
      endif

c   Find pointers used later to store fit results, but first check if
c this is a BACKWORD or FORWARD extrapolation; in this last case the
c vertex is associated to the track Last Hit => change IWFITFLG and FLAGFL.

      do 414 i1 = 1, Ntrfit

         iii = abs( ilist(i1) )
         IWdata = INDVWRK+VWRNCO*(iii-1) ! data pointer for track iii in VWRK
         IWfitflg(i1) = IWdata + VWFLF ! pointer to fit flag (assume 1st point)
         Flagfl(i1) = Flagfh    ! flag First Hit
         If ( Ilist(i1)*ISWMFORW .gt. 0. .or. verterr ) then
            IWfitflg(i1) = IWdata + VWFLL ! change to last point
            Flagfl(i1) = Flaglh ! flag First Hit
         endif

 414  continue

c check VERTERR flag (IWFITFLG pointers are needed, so this check is
c performed after loop 414)
      If ( verterr ) goto 305
c
c Start of iterative process
c
 888  continue
      NITER = NITER + 1

c check number of iterations
      if ( NITER .gt. Nitfitmax ) goto 303
c
c ===========================================================
c loop on tracks and build derivative matrix and error vector
c ===========================================================
c
c 
c zero CHI2, derivative matrix and error vector
c
      CSQ = 0.
      do i1=1,3
         mixgb(i1) = 0.
         do i2=1,3
            mixga(i1,i2) = 0.
         enddo
      enddo

c get point of closest approach to candidate vertex (VPCA)

      do 415 i1 = 1, Ntrfit

         Iireg = Ireg           ! use Iireg that can be different from Ireg
         If ( Ilist(i1)*ISWMFORW .gt. 0 ) Iireg = NLH

         iii = abs( ilist(i1) )
         IWdata = INDVWRK+VWRNCO*(iii-1) ! data pointer for track iii in VWRK

         istat = VTXSWM(iii,Iireg,XVX)
         if ( ISTAT .ne. YESUCC ) then
c
c If swimming routine returns error check wether the candidate vertex is 
c close to the boarder between two regions. If yes try again swimming
c with a different Iireg value
c
            if ( iireg.eq.nbi .and. rvertex.lt.0.8*rbp ) then
               goto 304         ! not at boarder
            elseif ( iireg.eq.nvc .and. rvertex.lt..8*rdc) then
               goto 304         ! not at boarder
            elseif ( iireg.eq.nfh .or. iireg.eq.nlh ) then
               goto304
            else
               iireg = iireg-1            ! try swimming with external region
               istat = VTXSWM(iii,Iireg,XVX)
               if ( ISTAT .ne. YESUCC ) goto 304 !No hope; flag error and ret
            endif
         endif
c
         If ( Ilist(i1)*ISWMBACK .gt. 0. ) then
            rpca(1)  = RW(IWdata+VWXVX)
            rpca(2)  = RW(IWdata+VWYVX)
            rpca(3)  = RW(IWdata+VWZVX)
            trpca(1) = RW(IWdata+VWTXVX)
            trpca(2) = RW(IWdata+VWTYVX)
            trpca(3) = RW(IWdata+VWTZVX)
            call mgfld(RW(IWdata+VWXVX),vh)
            rho = 1./(convers * vh(3) * 
     +                abs(RW(IWdata+VWCUVX)) )
         else
            rpca(1)  = RW(IWdata+VWXVL)
            rpca(2)  = RW(IWdata+VWYVL)
            rpca(3)  = RW(IWdata+VWZVL)
            trpca(1) = RW(IWdata+VWTXVL)
            trpca(2) = RW(IWdata+VWTYVL)
            trpca(3) = RW(IWdata+VWTZVL)
            call mgfld(RW(IWdata+VWXVL),vh)
            rho = 1./(convers * vh(3) * 
     +                abs(RW(IWdata+VWCUVL)) )
         endif

c if at first iteration, than evaluate error matrix at VPCA
         IF ( NITER .EQ. 1 ) call vtxerr(iii, Iireg, rpca, trpca)
         sig2t = RW(IWdata+VWERRV+0) 
         sigtz = RW(IWdata+VWERRV+1)
         sig2z = RW(IWdata+VWERRV+5)

c this is the vector from PCA to VX
         midx = XVX(1) - rpca(1)
         midy = XVX(2) - rpca(2)
         midz = XVX(3) - rpca(3)

c this is the distance PCA-VX on transverse plane
         txynorm = 1/sqrt(trpca(1)**2+trpca(2)**2)
         midt = txynorm * (midx*trpca(2) - midy*trpca(1))

c alpha is the "rotation angle" along the helix at PCA; cosa=cos(alpha); sina...
         mitx = trpca(1)
         mity = trpca(2)
         cosa =   mity * txynorm ! cos(alpha) =  sin(phi)
         sina = - mitx * txynorm ! sin(alpha) = -cos(phi)
         cotheta = trpca(3) / sqrt( trpca(1)**2 + trpca(2)**2 )

c correct cot(theta) by vertex distance from helix (normally theta ~
c cot(theta), since midt<<rho)
         theta = cotheta * rho/(rho-midt)

c before evaluating the matrix, calculate the total and the diagonal CHI2
         DENOM = 1 - sigtz**2/(sig2t*sig2z)
         VART  = midt**2/sig2t
         VARZ  = midz**2/sig2z
         COVAR = - 2 * abs(midt) * abs(midz) * sigtz / sig2t / sig2z 
 
c CSQ = global diagonal CHI2  (the sqrt will be taken after the loop)
c Trkcsq = CHI2 of single track (including correlations)
         CSQ = CSQ + VART + VARZ
         Trkcsq(i1) = ( VART + COVAR + VARZ ) / DENOM
         IF (Trkcsq(i1) .LT. 0.0) Trkcsq(i1) = 100000000.
         Trkcsq(i1) = sqrt(Trkcsq(i1))

c now evaluate matrix
         DEN = sig2t*sig2z - sigtz**2
c 
         mixgb1 = - cosa*sig2z*midt + theta*sina*sig2t*midz +
     &         ( cosa*midz - theta*sina*midt ) * sigtz
         mixgb2 = - sina*sig2z*midt + theta*cosa*sig2t*midz +
     &         ( sina*midz - theta*cosa*midt ) * sigtz
         mixgb3 = - sig2t*midz + sigtz*midt
         mixgb(1) = mixgb(1) + mixgb1/DEN
         mixgb(2) = mixgb(2) + mixgb2/DEN
         mixgb(3) = mixgb(3) + mixgb3/DEN
*
         mixga11 = cosa**2*sig2z + theta**2*sina**2*sig2t +
     &          2*theta*sina*cosa*sigtz
         mixga12 = sina*cosa*(theta**2*sig2t+sig2z) +
     &          theta*sigtz
         mixga13 = - theta*sina*sig2t - cosa*sigtz
         mixga22 = sina**2*sig2z + theta**2*cosa**2*sig2t +
     &          2*theta*sina*cosa*sigtz
         mixga23 = - theta*cosa*sig2t - sina*sigtz
         mixga33 = sig2t
         mixga(1,1) = mixga(1,1) + mixga11/DEN
         mixga(1,2) = mixga(1,2) + mixga12/DEN
         mixga(1,3) = mixga(1,3) + mixga13/DEN
         mixga(2,2) = mixga(2,2) + mixga22/DEN
         mixga(2,3) = mixga(2,3) + mixga23/DEN
         mixga(3,3) = mixga(3,3) + mixga33/DEN
   
 415  enddo

c Fix global CHI2 (sum in quadrature of all diagonal CHI2)
      CSQ = sqrt(CSQ)

c Check CHI2 cut on single track; flag worst track (if above limit)
      do i1= 1, ntrfit
         Ibadtk = 0             ! no BAD tracks
         if ( Trkcsq(i1) .gt. Cutrkcsq ) Ibadtk = iii 
      enddo

c now apply the constraint (if asked) => fake track with coordinates 
c (con1,con2,con3), wher con1,2,3 are defined below

      if ( .not.CONSTR ) goto 416

      con1 = XVX(1) - XCN(1)
      con2 = XVX(2) - XCN(2)
      con3 = XVX(3) - XCN(3)
      midt = sqrt(con1**2+con2**2)
      midz = abs(con3)

      if ( midt.lt.0.00001 ) then
         cosa = 1.
         sina = 0.
         theta = 0.
      else
         cosa = COS( ATAN2(con2,con1) )
         sina = SIN( ATAN2(con2,con1) )
         theta =  con3 / sqrt(midt**2+midz**2)
         if ( (abs(theta)-1).lt..0001 ) theta = SIGN(0.999,theta)
         theta = ACOS( theta )
         theta = 1. / TAN(theta)
      endif

      sig2t = sig2tcon
      sig2z = sig2zcon
      sigtz = 0.

c now update matrix with constraint conditions
         DEN = sig2t*sig2z - sigtz**2
c 
         mixgb1 = - cosa*sig2z*midt + theta*sina*sig2t*midz +
     &         ( cosa*midz - theta*sina*midt ) * sigtz
         mixgb2 = - sina*sig2z*midt + theta*cosa*sig2t*midz +
     &         ( sina*midz - theta*cosa*midt ) * sigtz
         mixgb3 = - sig2t*midz + sigtz*midt
         mixgb(1) = mixgb(1) + mixgb1/DEN
         mixgb(2) = mixgb(2) + mixgb2/DEN
         mixgb(3) = mixgb(3) + mixgb3/DEN
*
         mixga11 = cosa**2*sig2z + theta**2*sina**2*sig2t +
     &          2*theta*sina*cosa*sigtz
         mixga12 = sina*cosa*(theta**2*sig2t+sig2z) +
     &          theta*sigtz
         mixga13 = - theta*sina*sig2t - cosa*sigtz
         mixga22 = sina**2*sig2z + theta**2*cosa**2*sig2t +
     &          2*theta*sina*cosa*sigtz
         mixga23 = - theta*cosa*sig2t - sina*sigtz
         mixga33 = sig2t
c
c before modifying the matrix, store it. The final covariance matrix
c is the inverse of this matrix BEFORE being modified by the constraint.
c
         do i1=1,3
            do i2=i1,3
               xga(i1,i2) = mixga(i1,i2)
            enddo
         enddo
         mixga(1,1) = mixga(1,1) + mixga11/DEN
         mixga(1,2) = mixga(1,2) + mixga12/DEN
         mixga(1,3) = mixga(1,3) + mixga13/DEN
         mixga(2,2) = mixga(2,2) + mixga22/DEN
         mixga(2,3) = mixga(2,3) + mixga23/DEN
         mixga(3,3) = mixga(3,3) + mixga33/DEN

 416  continue

      miXGA(2,1)=miXGA(1,2)
      miXGA(3,1)=miXGA(1,3)
      miXGA(3,2)=miXGA(2,3)
c
c----------------------------------------------------------------------------
c
c Use derivatives to evaluate new vertex position
c
c 1 - keep track of error vector 
c
      do i1 = 1,3
         miverr(i1)=mixgb(i1)
      enddo
c
c 2 - solve linearized system
c
      call reqinv(3,mixga,3,idum,nerror,1,mixgb)
c
c 3 - get displacement
c
      do i1=1,3
         midv(i1)=mixgb(i1)
      enddo
c
c 4 - get "vertex shift" (= how large was this step, in the iterative
c     process, normalized with the inverse error vector)
      vershift = 0.
      do i1=1,3
         vershift = vershift + miverr(i1)*midv(i1)
      enddo
c
c 5 - flag error if normalized vertex dshift is negative
      if ( vershift .lt. 0. ) goto 302
c
c 6 - Allows for an increment in vertex shift from previous step to this one,
c     (TOLERATE), but only once.
c
      if ( vershift .gt. vershprev ) then
         Tolerate = Tolerate + 1
         if ( Tolerate .gt. 1 ) goto 301
      endif
c
      vershprev = vershift
c
c 7 - update vertex position
c
      XVX(1) = XVX(1) + midv(1)
      XVX(2) = XVX(2) + midv(2)
      XVX(3) = XVX(3) + midv(3)
c
c 8 - Check for fit convergence (normalized vector shift smaller than a 
c     given cut). The "Parallel" factor looses the fit convergence
c     requirements for quasi-parallel tracks.
c
      if ( vershift .lt. minshift*parallel ) then
         converg = .true.
c
c If constraint flag was raised, restore the old XGA matrix, invert it
c and pass it to the VTXCAN routine IF POSITIVELY DEFINED.
c
         if (constr) then
            xga(2,1) = xga(1,2)
            xga(3,1) = xga(1,3)
            xga(3,2) = xga(2,3)
            call rinv(3,xga,3,idum,nerror)
            if (xga(1,1).gt.0.and.xga(2,2).gt.0
     &          .and.xga(3,3).gt.0) then
               do i1=1,3
                  do i2=1,3
                     mixga(i1,i2) = xga(i1,i2)
                  enddo
               enddo
            endif
         endif
c
         goto 300
      endif
c
c 9 - Iterate
c                 
      goto 888

c==================================================================
c
c end of iterative procedure; fill FIT code (see comment above for
c meaning of "parallel" parameter).
c
 300  if ( Ibadtk .eq. 0 ) then
         IFIT = FITGOLD
      elseif ( CSQ .lt. CHI2limit*parallel ) then
         IFIT = FITSILVER
      else
         IFIT = FITBAD
      endif
      goto 999
c
 301  IFIT = FITNOCONV
      goto 999
c
 302  IFIT = FITNEGCHI2
      goto 999
c
 303  IFIT = FITMAXITER
      goto 999
c
 304  IFIT = FITTRKEXTR
      goto 999
c
 305  IFIT = FITOUTDC
      goto 999
c

 999  continue
      
c fill track codes
      do i1 = 1, ntrfit
         IW( IWfitflg(i1) ) = IFIT
      enddo

c If fit was succesfull than prepare the common block for VTXCAN and
c call the routine to store this candidate vertex. 
c Note that DVCS bank is created only for 2 tracks vertices. Vertices
c with more tracks are built in VTXMERG and written directly into
c DVFS bank. 

      Accept = Ntrfit.eq.2 .and. 
     +         ( IFIT.eq.FITGOLD .or. IFIT.eq.FITSILVER )
      If ( Accept ) then

c fill common block with infos to be put into the candidate bank
         Nflg = Nflag           ! internal flag
         Jfit = Ifit            ! quality flag
cmi
cmi just for debugging
cmi
         if (constr) jfit = -Jfit
cmi
         Vchi2 = CSQ            ! (sqrt of) CHI squared
         Nvxfit = Nvxfit + 1    ! vertex index
         Vx = XVX(1)            !
         Vy = XVX(2)            ! Vertex position
         Vz = XVX(3)            !
         do i1 = 1, 2
            Jlist(i1) = abs(Ilist(i1)) ! track number
            Vtrkcsq(i1) = Trkcsq(i1)   ! trk contribution to CHI2
         enddo

c call the routine that creates DVCS bank (Candidate bank)
         call VTXCAN

      endif
c
      return
      end

c=======================================================================
           SUBROUTINE VTXERR(iii, Ireg, rpca, trpca)
c=======================================================================
c
c Routine perfoming the extrapolation to point RPCA(3), in region Ireg,
c of error matrix.
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      30-9-1997
c     ==============
c
c     Input:
c     ======
c           iii           track number
c           Ireg          region of extrapolation
c           rpca(3)       coordinates of extrapolation point
c           trpca(3)       tangent at extrapolation point
c
c     Output:
c     =======
c           RW(...+VWERRV) vector (15 elements) filled up
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$Include 'K$inc:Bcs.inc'
$$include 'ybos$library:errcod.inc'
$$include 'k$inc:jobsta.inc'			
$$include 'k$inc:erlevl.inc'                    ! error logger
$$INCLUDE 'K$ITRK:CTIDRI.INC'
$$INCLUDE 'K$ITRK:CCONST.INC'
$$INCLUDE 'K$ITRK:VWRK.INC'
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c
c Local declarations
c     
      INTEGER iii, Ireg, Iregcon, IWDATA, IWDATAN
      REAL rpca(3), trpca(3), sinthe, Vh(3), tBP, tDC, sDC, sBP
      REAL cosOMEGA, tEFF, sEFF, SIG2phi, SIG2cot, SIG2z
      REAL Ptot, Etot, Bfield, SIG2kur
      CHARACTER*80 message

c Parameters in common block (VTXERR - VTXTRANS)
      REAL                rxi, ryi, rzi, txi, tyi, exi, eyi,
     +                    rxf, ryf, rzf, txf, tyf, exf, eyf,
     +                    Rho, Kur,
     +                    V11i, V12i, V13i, V14i, V15i,
     +                    V22i, V23i, V24i, V25i, V33i,
     +                    V34i, V35i, V44i, V45i, V55i,
     +                    V11f, V12f, V13f, V14f, V15f,
     +                    V22f, V23f, V24f, V25f, V33f,
     +                    V34f, V35f, V44f, V45f, V55f
      COMMON / TRANSCOM / rxi, ryi, rzi, txi, tyi, exi, eyi,
     +                    rxf, ryf, rzf, txf, tyf, exf, eyf,
     +                    Rho, Kur,
     +                    V11i, V12i, V13i, V14i, V15i,
     +                    V22i, V23i, V24i, V25i, V33i,
     +                    V34i, V35i, V44i, V45i, V55i,
     +                    V11f, V12f, V13f, V14f, V15f,
     +                    V22f, V23f, V24f, V25f, V33f,
     +                    V34f, V35f, V44f, V45f, V55f
c
c Thickness, in gr/cm**2, of the materials that make up the walls
c
      REAL XAldc, XBebp
      EQUIVALENCE (TIRGVX( 6),XAldc),(TIRGVX(11),XBebp)
c
c Radiation length, in gr/cm**2, of the materials that make up the walls
c
      REAL RlAl, RlBe
      EQUIVALENCE (TIDEVX(3,2), RlAl), (TIDEVX(3,7), RlBe)
c
c Density, in gr/cm**3, of the materials
c
      Real RhoCf, RhoBe
      PARAMETER (RhoCf=1.57,RhoBe=1.848)
c
c=======================================================================
c
c Initialize parameters
c
      tDC = XAldc/RlAl          ! thickness of DC wall in Rad. Len. units
      sDC = XAldc/RhoCf         ! thickness of DC wall in cm
      tBP = XBebp/RlBe          ! thickness of BP wall in Rad. Len. units
      sBP = XBebp/RhoBe         ! thickness of BP wall in cm
      IREGCON = 1               ! control word
      IWDATA = INDVWRK+VWRNCO*(iii-1) ! data pointer for track iii in VWRK
c
c Covariant matrix at First point
c
      V11i = RW( IWDATA + VWERRF +  0 )
      V12i = RW( IWDATA + VWERRF +  1 )
      V13i = RW( IWDATA + VWERRF +  2 )
      V14i = RW( IWDATA + VWERRF +  3 )
      V15i = RW( IWDATA + VWERRF +  4 )
      V22i = RW( IWDATA + VWERRF +  5 )
      V23i = RW( IWDATA + VWERRF +  6 )
      V24i = RW( IWDATA + VWERRF +  7 )
      V25i = RW( IWDATA + VWERRF +  8 )
      V33i = RW( IWDATA + VWERRF +  9 )
      V34i = RW( IWDATA + VWERRF + 10 )
      V35i = RW( IWDATA + VWERRF + 11 )
      V44i = RW( IWDATA + VWERRF + 12 )
      V45i = RW( IWDATA + VWERRF + 13 )
      V55i = RW( IWDATA + VWERRF + 14 )

c get B field at First Hit

      call MGFLD(RW(IWDATA+VWXFH),Vh)
      Bfield = Vh(3) 

c === Now start extrapolation of covariant matrix === 
c Two comments on conventions used
c 1 - In all of the following :
c Txi, Tyi      = tangent unit vector on trasverse plane at initial point
c Exi, Eyi      = versor defined as E = T X z  (z being the B-field direction)
c Rxi, Ryi, Rzi = Position of initial point of extrapolation
c Txf, Tyf, Exf, Eyf, Rxf, ... = as before for final point
c Rho, Kur = rafius of curvature and curvature (defined as Q/Pt) 
c 
c 2 - To get from VWRK bank the informations relative to First Point, DC,
c or BP, I use the fact that each subregion is described by VWRBLK entries
c in VWRK bank. IREGCON is the control word
c that keep tracks of what subregion we are in.

c     
c ====> 1 - Forward extrapolation 
c
      If (Ireg .eq. NLH) then

c values of versors and position at initial point

            IWDATAN = IWDATA + (IREGCON-1) * VWRBLK !elements per block in VWRK
            sinthe = sqrt(1.-RW(IWDATAN+VWTZFH)**2)
            Txi = RW( IWDATAN + VWTXFH ) / sinthe
            Tyi = RW( IWDATAN + VWTYFH ) / sinthe
            Exi = -Tyi
            Eyi =  Txi
            Kur = RW( IWDATAN + VWCUFH )
            Rho = 1/(Convers * Bfield * Kur)
            rxi = RW( IWDATAN + VWXFH )
            ryi = RW( IWDATAN + VWYFH )
            rzi = RW( IWDATAN + VWZFH )

c values of versors and position at final point
            
            Txf = trpca(1) / sinthe
            Tyf = trpca(2) / sinthe
            Exf = -Tyf
            Eyf =  Txf
            rxf = rpca(1)
            ryf = rpca(2)
            rzf = rpca(3)
c
c call transforming routine
c
         call VTXTRANS(ISWMFORW)
c
c ====> 2 - If here than backward extrapolation.
c Loop on IREGCON control word (stop loop if IREGCON>IREG)
c
      else

         do while (IREGCON-IREG .le. 0)

c values of versors and position at initial point

            IWDATAN = IWDATA + (IREGCON-1) * VWRBLK !elements per block in VWRK
            sinthe = sqrt(1.-RW(IWDATAN+VWTZFH)**2)
            Txi = RW( IWDATAN + VWTXFH ) / sinthe
            Tyi = RW( IWDATAN + VWTYFH ) / sinthe
            Exi = -Tyi
            Eyi =  Txi
            Kur = RW( IWDATAN + VWCUFH )
            Rho = 1/(Convers * Bfield * Kur)
            rxi = RW( IWDATAN + VWXFH )
            ryi = RW( IWDATAN + VWYFH )
            rzi = RW( IWDATAN + VWZFH )

c values of versors and position at final point

            IREGCON = IREGCON + 1

            if (IREGCON .gt. IREG ) then ! end of extrapolation

               Txf = trpca(1) / sinthe
               Tyf = trpca(2) / sinthe
               Exf = -Tyf
               Eyf =  Txf
               rxf = rpca(1)
               ryf = rpca(2)
               rzf = rpca(3)

               call VTXTRANS(Iswmback)
               
               goto 999
            
            else
               
               IWDATAN = IWDATA + (IREGCON-1) * VWRBLK !elements per block in VWRK
               sinthe = sqrt(1.-RW(IWDATAN+VWTZFH)**2)
               Txf = RW( IWDATAN + VWTXFH ) / sinthe
               Tyf = RW( IWDATAN + VWTYFH ) / sinthe
               Exf = -Tyf
               Eyf =  Txf
               rxf = RW( IWDATAN + VWXFH )
               ryf = RW( IWDATAN + VWYFH )
               rzf = RW( IWDATAN + VWZFH )
               
               call VTXTRANS(Iswmback)

c --> Here we are crossing a surface!!!               
c So add Multiple Scattering effect in pion mass hypothesis. 

c get total momentum and energy

               Ptot = 1./abs(Kur)/sinthe
               Etot = sqrt(PION_MASS**2 + Ptot**2)

c get angle OMEGA, between momentum versor and surface, and eff. thickness

               cosOMEGA = sinthe*(rxf*txf+ryf*tyf)/sqrt(rxf**2+ryf**2)
               if (IREGCON .eq. NVC) then
                  tEFF = tDC / abs(cosOMEGA) ! eff.thickness in rad.len.
                  sEFF = sDC / abs(cosOMEGA) ! eff.thickness in cm.
               elseif (IREGCON.eq.NBI .or. IREGCON.eq.NBU ) then
                  tEFF = tBP / abs(cosOMEGA)
                  sEFF = sBP / abs(cosOMEGA)
               else
                  message = 'Unknown extrapolation region'
                  call ERLOGR ('VTXERR',ERWARN,0,0,message)
                  return
               endif

c get SIG2phi as [ 0.0136GeV/(Beta*p) * sqrt(tEFF) ]**2

               SIG2phi = (0.0136 * Etot)/Ptot**2 * sqrt(tEFF)
               SIG2phi = SIG2phi*SIG2phi

c derive SIG2kur, SIG2z and SIG2cottheta

               SIG2z   = SIG2phi * sEFF**2 / 3.
               SIG2cot = SIG2phi / sinthe**4
               SIG2kur = SIG2phi * Kur**2 * (1-sinthe**2) / sinthe**2

c update diagonal elements of covariant matrix

               V22f = V22f + SIG2z
               V33f = V33f + SIG2kur
               V44f = V44f + SIG2cot
               V55f = V55f + SIG2phi

c --> End of MULTIPLE SCATTERING

c update error matrix for next iteration

               V11i = V11f
               V12i = V12f
               V13i = V13f
               V14i = V14f
               V15i = V15f
               V22i = V22f
               V23i = V23f
               V24i = V24f
               V25i = V25f
               V33i = V33f
               V34i = V34f
               V35i = V35f
               V44i = V44f
               V45i = V45f
               V55i = V55f

            endif
            
         enddo                  ! end of DO WHILE loop
c
c if here than error (from final extrapolation should jump to 999)
c
         message = 'Error in error matrix extrapolation'
         call ERLOGR ('VTXERR',ERWARN,0,0,message)
         return
c
      endif                     ! end of extrapolation

 999  continue
c
c Covariant Matrix at Candidate Vertex
c
      RW( IWDATA + VWERRV +  0 ) = V11f
      RW( IWDATA + VWERRV +  1 ) = V12f
      RW( IWDATA + VWERRV +  2 ) = V13f
      RW( IWDATA + VWERRV +  3 ) = V14f
      RW( IWDATA + VWERRV +  4 ) = V15f
      RW( IWDATA + VWERRV +  5 ) = V22f
      RW( IWDATA + VWERRV +  6 ) = V23f
      RW( IWDATA + VWERRV +  7 ) = V24f
      RW( IWDATA + VWERRV +  8 ) = V25f
      RW( IWDATA + VWERRV +  9 ) = V33f
      RW( IWDATA + VWERRV + 10 ) = V34f
      RW( IWDATA + VWERRV + 11 ) = V35f
      RW( IWDATA + VWERRV + 12 ) = V44f
      RW( IWDATA + VWERRV + 13 ) = V45f
      RW( IWDATA + VWERRV + 14 ) = V55f

      return
      end

c=======================================================================
           SUBROUTINE VTXTRANS(Iswim)
c=======================================================================
c
c Routine that perform the matrix transformation
c
c     Author:             Marco Incagli
c     =======
c
c     Creation date:      11-11-1997
c     ==============
c
c     Input:
c     ======
c           Iswim         Swim direction (see VTXFIN include file)
c           V11i,..,V55i  Initial covariant matrix (15 elements)
c           TRANSCOM      Common file with initial and final point
c
c     Output:
c     =======
c           V11f,..,V55f  Final covariant matrix (15 elements)
c
c=======================================================================
c
c include files
c
$$IMPLICIT NONE
$$INCLUDE 'K$ITRK:VTXFIN.INC'
c
c Local declarations
c     
      INTEGER Iswim
      REAL V21i, V31i, V32i, V41i, V42i, V43i
      REAL V51i, V52i, V53i, V54i, rif, Alf
      REAL D11, D13, D15, D22, D23, D24, D33, D44, D53, D55

c Parameters in common block (VTXERR - VTXTRANS)
      REAL                rxi, ryi, rzi, txi, tyi, exi, eyi,
     +                    rxf, ryf, rzf, txf, tyf, exf, eyf,
     +                    Rho, Kur,
     +                    V11i, V12i, V13i, V14i, V15i,
     +                    V22i, V23i, V24i, V25i, V33i,
     +                    V34i, V35i, V44i, V45i, V55i,
     +                    V11f, V12f, V13f, V14f, V15f,
     +                    V22f, V23f, V24f, V25f, V33f,
     +                    V34f, V35f, V44f, V45f, V55f
      COMMON / TRANSCOM / rxi, ryi, rzi, txi, tyi, exi, eyi,
     +                    rxf, ryf, rzf, txf, tyf, exf, eyf,
     +                    Rho, Kur,
     +                    V11i, V12i, V13i, V14i, V15i,
     +                    V22i, V23i, V24i, V25i, V33i,
     +                    V34i, V35i, V44i, V45i, V55i,
     +                    V11f, V12f, V13f, V14f, V15f,
     +                    V22f, V23f, V24f, V25f, V33f,
     +                    V34f, V35f, V44f, V45f, V55f
c
c=======================================================================
c
c simmetrization of input matrix
c
      V21i = V12i
      V31i = V13i
      V32i = V23i
      V41i = V14i
      V42i = V24i
      V43i = V34i
      V51i = V15i
      V52i = V25i
      V53i = V35i
      V54i = V45i
c
c get rotation angle (same sign as Rho for FORWARD extrapolation,
c opposite sign for BACKWARD extrapolation)
c rif = distance initial-final point
c
         rif = sqrt( (rxi-rxf)**2 + (ryi-ryf)**2 )
         Alf = 0.5*rif/rho
         If ( abs(Alf).ge.1. ) alf = SIGN(1.,alf)
         Alf = Iswim * 2 * ASIN( Alf )
c
c evaluate derivatives matrix (all other terms are 0)
c
         D11 = Txi*txf + Tyi*Tyf
         D13 = ((rxi-rxf)*Exf + (ryi-ryf)*Eyf) / Kur
         D15 = (rxf-rxi)*Txf + (ryf-ryi)*Tyf
         D22 = 1.
         D23 = (rzi-rzf) / Kur
         D24 = Rho*Alf
         D33 = 1.
         D44 = 1.
         D53 = - Alf / Kur
         D55 = 1.
c
c Final covariant matrix
c
         V11f = (D11*V11i+D13*V31i+D15*V51i)*D11 +
     +          (D11*V13i+D13*V33i+D15*V53i)*D13 +
     +          (D11*V15i+D13*V35i+D15*V55i)*D15

         V12f = (D11*V12i+D13*V32i+D15*V52i)*D22 +
     +          (D11*V13i+D13*V33i+D15*V53i)*D23 +
     +          (D11*V14i+D13*V34i+D15*V54i)*D24

         V13f = (D11*V13i+D13*V33i+D15*V53i)*D33

         V14f = (D11*V14i+D13*V34i+D15*V54i)*D44

         V15f = (D11*V13i+D13*V33i+D15*V53i)*D53 +
     +          (D11*V15i+D13*V35i+D15*V55i)*D55

         V22f = (D22*V22i+D23*V32i+D24*V42i)*D22 +
     +          (D22*V23i+D23*V33i+D24*V43i)*D23 +
     +          (D22*V24i+D23*V34i+D24*V44i)*D24

         V23f = (D22*V23i+D23*V33i+D24*V43i)*D33


         V24f = (D22*V24i+D23*V34i+D24*V44i)*D44

         V25f = (D22*V23i+D23*V33i+D24*V43i)*D53 +
     +          (D22*V25i+D23*V35i+D24*V45i)*D55

         V33f = D33*V33i*D33
         
         V34f = D33*V34i*D44

         V35f = D33*V33i*D53 + D33*V35i*D55

         V44f = D44*V44i*D44
         
         V45f = D44*V43i*D53 + D44*V45i*D55

         V55f = (D53*V33i+D55*V53i)*D53 + 
     +          (D53*V35i+D55*V55i)*D55


         return
         end

[KLOE] [Offline Doc] [TRK Files]
Generated with Light on Thu Apr 8 13:00:16 MET DST 1999 .
Mail comments and suggestions.