LCOV - code coverage report
Current view: top level - MUON/MUONrec - AliMUONTrack.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 226 600 37.7 %
Date: 2016-06-14 17:26:59 Functions: 17 35 48.6 %

          Line data    Source code
       1             : /**************************************************************************
       2             :  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
       3             :  *                                                                        *
       4             :  * Author: The ALICE Off-line Project.                                    *
       5             :  * Contributors are mentioned in the code where appropriate.              *
       6             :  *                                                                        *
       7             :  * Permission to use, copy, modify and distribute this software and its   *
       8             :  * documentation strictly for non-commercial purposes is hereby granted   *
       9             :  * without fee, provided that the above copyright notice appears in all   *
      10             :  * copies and that both the copyright notice and this permission notice   *
      11             :  * appear in the supporting documentation. The authors make no claims     *
      12             :  * about the suitability of this software for any purpose. It is          *
      13             :  * provided "as is" without express or implied warranty.                  *
      14             :  **************************************************************************/
      15             : 
      16             : /* $Id$ */
      17             : 
      18             : //-----------------------------------------------------------------------------
      19             : // Class AliMUONTrack
      20             : //-------------------
      21             : // Reconstructed track in ALICE dimuon spectrometer
      22             : //-----------------------------------------------------------------------------
      23             : 
      24             : #include "AliMUONTrack.h"
      25             : 
      26             : #include "AliMUONReconstructor.h"
      27             : #include "AliMUONVCluster.h"
      28             : #include "AliMUONVClusterStore.h"
      29             : #include "AliMUONObjectPair.h"
      30             : #include "AliMUONTrackExtrap.h"
      31             : #include "AliMUONConstants.h"
      32             : #include "AliMUONTrackParam.h"
      33             : 
      34             : #include "AliLog.h"
      35             : 
      36             : #include <TMath.h>
      37             : 
      38             : #include <Riostream.h>
      39             : 
      40             : using std::setw;
      41             : using std::endl;
      42             : using std::cout;
      43             : using std::streamsize;
      44             : using std::setprecision;
      45             : /// \cond CLASSIMP
      46          18 : ClassImp(AliMUONTrack) // Class implementation in ROOT context
      47             : /// \endcond
      48             : 
      49             : 
      50             : const Double_t AliMUONTrack::fgkMaxChi2 = 1.e10; ///< maximum chi2 above which the track can be considered as abnormal
      51             : 
      52             : 
      53             : //__________________________________________________________________________
      54             : AliMUONTrack::AliMUONTrack()
      55           2 :   : TObject(),
      56           2 :     fTrackParamAtCluster(0x0),
      57           2 :     fFitWithVertex(kFALSE),
      58           2 :     fVertexErrXY2(),
      59           2 :     fFitWithMCS(kFALSE),
      60           2 :     fClusterWeightsNonBending(0x0),
      61           2 :     fClusterWeightsBending(0x0),
      62           2 :     fGlobalChi2(-1.),
      63           2 :     fImproved(kFALSE),
      64           2 :     fMatchTrigger(-1),
      65           2 :     fChi2MatchTrigger(0.),
      66           2 :     fTrackID(-1),
      67           2 :     fTrackParamAtVertex(0x0),
      68           2 :     fHitsPatternInTrigCh(0),
      69           2 :     fHitsPatternInTrigChTrk(0),
      70           2 :     fLocalTrigger(0),
      71           2 :     fConnected(kFALSE)
      72          10 : {
      73             :   /// Default constructor
      74           2 :   fVertexErrXY2[0] = 0.;
      75           2 :   fVertexErrXY2[1] = 0.;
      76           4 : }
      77             : 
      78             :   //__________________________________________________________________________
      79             : AliMUONTrack::AliMUONTrack(AliMUONObjectPair *segment, Double_t bendingVertexDispersion)
      80          34 :   : TObject(),
      81         102 :     fTrackParamAtCluster(new TObjArray(20)),
      82          34 :     fFitWithVertex(kFALSE),
      83          34 :     fVertexErrXY2(),
      84          34 :     fFitWithMCS(kFALSE),
      85          34 :     fClusterWeightsNonBending(0x0),
      86          34 :     fClusterWeightsBending(0x0),
      87          34 :     fGlobalChi2(0.),
      88          34 :     fImproved(kFALSE),
      89          34 :     fMatchTrigger(-1),
      90          34 :     fChi2MatchTrigger(0.),
      91          34 :     fTrackID(-1),
      92          34 :     fTrackParamAtVertex(0x0),
      93          34 :     fHitsPatternInTrigCh(0),
      94          34 :     fHitsPatternInTrigChTrk(0),
      95          34 :     fLocalTrigger(0),
      96          34 :     fConnected(kFALSE)
      97         170 : {
      98             :   /// Constructor from two clusters
      99             :   
     100          34 :   fTrackParamAtCluster->SetOwner(kTRUE);
     101             :   
     102          34 :   fVertexErrXY2[0] = 0.;
     103          34 :   fVertexErrXY2[1] = 0.;
     104             :   
     105             :   // Pointers to clusters from the segment
     106          34 :   AliMUONVCluster* firstCluster = (AliMUONVCluster*) segment->First();
     107          34 :   AliMUONVCluster* lastCluster = (AliMUONVCluster*) segment->Second();
     108             :   
     109             :   // Compute track parameters
     110          34 :   Double_t z1 = firstCluster->GetZ();
     111          34 :   Double_t z2 = lastCluster->GetZ();
     112          34 :   Double_t dZ = z1 - z2;
     113             :   // Non bending plane
     114          34 :   Double_t nonBendingCoor1 = firstCluster->GetX();
     115          34 :   Double_t nonBendingCoor2 = lastCluster->GetX();
     116          34 :   Double_t nonBendingSlope = (nonBendingCoor1 - nonBendingCoor2) / dZ;
     117             :   // Bending plane
     118          34 :   Double_t bendingCoor1 = firstCluster->GetY();
     119          34 :   Double_t bendingCoor2 = lastCluster->GetY();
     120          34 :   Double_t bendingSlope = (bendingCoor1 - bendingCoor2) / dZ;
     121             :   // Inverse bending momentum
     122          34 :   Double_t bendingImpact = bendingCoor1 - z1 * bendingSlope;
     123          68 :   Double_t inverseBendingMomentum = 1. / AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(bendingImpact);
     124             :   
     125             :   // Set track parameters at first cluster
     126          34 :   AliMUONTrackParam trackParamAtFirstCluster;
     127          34 :   trackParamAtFirstCluster.SetZ(z1);
     128          34 :   trackParamAtFirstCluster.SetNonBendingCoor(nonBendingCoor1);
     129          34 :   trackParamAtFirstCluster.SetNonBendingSlope(nonBendingSlope);
     130          34 :   trackParamAtFirstCluster.SetBendingCoor(bendingCoor1);
     131          34 :   trackParamAtFirstCluster.SetBendingSlope(bendingSlope);
     132          34 :   trackParamAtFirstCluster.SetInverseBendingMomentum(inverseBendingMomentum);
     133             :   
     134             :   // Set track parameters at last cluster
     135          34 :   AliMUONTrackParam trackParamAtLastCluster;
     136          34 :   trackParamAtLastCluster.SetZ(z2);
     137          34 :   trackParamAtLastCluster.SetNonBendingCoor(nonBendingCoor2);
     138          34 :   trackParamAtLastCluster.SetNonBendingSlope(nonBendingSlope);
     139          34 :   trackParamAtLastCluster.SetBendingCoor(bendingCoor2);
     140          34 :   trackParamAtLastCluster.SetBendingSlope(bendingSlope);
     141          34 :   trackParamAtLastCluster.SetInverseBendingMomentum(inverseBendingMomentum);
     142             :   
     143             :   // Compute and set track parameters covariances at first cluster
     144          34 :   TMatrixD paramCov(5,5);
     145          34 :   paramCov.Zero();
     146             :   // Non bending plane
     147         102 :   paramCov(0,0) = firstCluster->GetErrX2();
     148         102 :   paramCov(0,1) = firstCluster->GetErrX2() / dZ;
     149         102 :   paramCov(1,0) = paramCov(0,1);
     150         136 :   paramCov(1,1) = ( firstCluster->GetErrX2() + lastCluster->GetErrX2() ) / dZ / dZ;
     151             :   // Bending plane
     152         102 :   paramCov(2,2) = firstCluster->GetErrY2();
     153         102 :   paramCov(2,3) = firstCluster->GetErrY2() / dZ;
     154         102 :   paramCov(3,2) = paramCov(2,3);
     155         136 :   paramCov(3,3) = ( firstCluster->GetErrY2() + lastCluster->GetErrY2() ) / dZ / dZ;
     156             :   // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
     157          34 :   if (AliMUONTrackExtrap::IsFieldON()) {
     158         136 :     paramCov(4,4) = ( ( bendingVertexDispersion*bendingVertexDispersion +
     159         136 :                        (z1 * z1 * lastCluster->GetErrY2() + z2 * z2 * firstCluster->GetErrY2()) / dZ / dZ) /
     160          34 :                      bendingImpact / bendingImpact + 0.1 * 0.1) * inverseBendingMomentum * inverseBendingMomentum ;
     161         102 :     paramCov(2,4) = - z2 * firstCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
     162         102 :     paramCov(4,2) = paramCov(2,4);
     163         136 :     paramCov(3,4) = - (z1 * lastCluster->GetErrY2() + z2 * firstCluster->GetErrY2()) * inverseBendingMomentum / bendingImpact / dZ / dZ;
     164         102 :     paramCov(4,3) = paramCov(3,4);
     165          34 :   } else paramCov(4,4) = inverseBendingMomentum*inverseBendingMomentum;
     166          34 :   trackParamAtFirstCluster.SetCovariances(paramCov);
     167             :   
     168             :   // Compute and set track parameters covariances at last cluster
     169             :   // Non bending plane
     170         102 :   paramCov(0,0) = lastCluster->GetErrX2();
     171         102 :   paramCov(0,1) = - lastCluster->GetErrX2() / dZ;
     172         102 :   paramCov(1,0) = paramCov(0,1);
     173             :   // Bending plane
     174         102 :   paramCov(2,2) = lastCluster->GetErrY2();
     175         102 :   paramCov(2,3) = - lastCluster->GetErrY2() / dZ;
     176         102 :   paramCov(3,2) = paramCov(2,3);
     177             :   // Inverse bending momentum (vertex resolution + bending slope resolution + 10% error on dipole parameters+field)
     178          34 :   if (AliMUONTrackExtrap::IsFieldON()) {
     179         102 :     paramCov(2,4) = z1 * lastCluster->GetErrY2() * inverseBendingMomentum / bendingImpact / dZ;
     180         102 :     paramCov(4,2) = paramCov(2,4);
     181          34 :   }
     182          34 :   trackParamAtLastCluster.SetCovariances(paramCov);
     183             :   
     184             :   // Add track parameters at clusters
     185          34 :   AddTrackParamAtCluster(trackParamAtFirstCluster,*firstCluster);
     186          34 :   AddTrackParamAtCluster(trackParamAtLastCluster,*lastCluster);
     187             :   
     188          68 : }
     189             : 
     190             : //__________________________________________________________________________
     191             : AliMUONTrack::AliMUONTrack(const AliMUONTrack& track)
     192         112 :   : TObject(track),
     193         112 :     fTrackParamAtCluster(0x0),
     194         112 :     fFitWithVertex(track.fFitWithVertex),
     195         112 :     fVertexErrXY2(),
     196         112 :     fFitWithMCS(track.fFitWithMCS),
     197         112 :     fClusterWeightsNonBending(0x0),
     198         112 :     fClusterWeightsBending(0x0),
     199         112 :     fGlobalChi2(track.fGlobalChi2),
     200         112 :     fImproved(track.fImproved),
     201         112 :     fMatchTrigger(track.fMatchTrigger),
     202         112 :     fChi2MatchTrigger(track.fChi2MatchTrigger),
     203         112 :     fTrackID(track.fTrackID),
     204         112 :     fTrackParamAtVertex(0x0),
     205         112 :     fHitsPatternInTrigCh(track.fHitsPatternInTrigCh),
     206         112 :     fHitsPatternInTrigChTrk(track.fHitsPatternInTrigChTrk),
     207         112 :     fLocalTrigger(track.fLocalTrigger),
     208         112 :     fConnected(track.fConnected)
     209         560 : {
     210             :   ///copy constructor
     211             :   
     212             :   // necessary to make a copy of the objects and not only the pointers in TObjArray.
     213         112 :   if (track.fTrackParamAtCluster) {
     214         448 :     fTrackParamAtCluster = new TObjArray(track.fTrackParamAtCluster->GetSize());
     215         112 :     fTrackParamAtCluster->SetOwner(kTRUE);
     216        2106 :     for (Int_t i = 0; i < track.GetNClusters(); i++)
     217        1770 :       fTrackParamAtCluster->AddLast(new AliMUONTrackParam(*static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(i))));
     218         112 :   }
     219             :   
     220             :   // copy vertex resolution square used during the tracking procedure
     221         112 :   fVertexErrXY2[0] = track.fVertexErrXY2[0];
     222         112 :   fVertexErrXY2[1] = track.fVertexErrXY2[1];
     223             :   
     224             :   // copy cluster weights matrices if any
     225         112 :   if (track.fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
     226         112 :   if (track.fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
     227             :   
     228             :   // copy track parameters at vertex if any
     229         112 :   if (track.fTrackParamAtVertex) fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
     230             :   
     231         224 : }
     232             : 
     233             :   //__________________________________________________________________________
     234             : AliMUONTrack & AliMUONTrack::operator=(const AliMUONTrack& track)
     235             : {
     236             :   /// Asignment operator
     237             :   // check assignement to self
     238           0 :   if (this == &track)
     239           0 :     return *this;
     240             : 
     241             :   // base class assignement
     242           0 :   TObject::operator=(track);
     243             :   
     244             :   // clear memory
     245           0 :   Clear();
     246             :   
     247             :   // necessary to make a copy of the objects and not only the pointers in TObjArray
     248           0 :   if (track.fTrackParamAtCluster) {
     249           0 :     fTrackParamAtCluster = new TObjArray(track.fTrackParamAtCluster->GetSize());
     250           0 :     fTrackParamAtCluster->SetOwner(kTRUE);
     251           0 :     for (Int_t i = 0; i < track.GetNClusters(); i++)
     252           0 :       fTrackParamAtCluster->AddLast(new AliMUONTrackParam(*static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(i))));
     253           0 :   }
     254             :   
     255             :   // copy cluster weights matrix if any
     256           0 :   if (track.fClusterWeightsNonBending) {
     257           0 :     if (fClusterWeightsNonBending) {
     258           0 :       fClusterWeightsNonBending->ResizeTo(*(track.fClusterWeightsNonBending));
     259           0 :       *fClusterWeightsNonBending = *(track.fClusterWeightsNonBending);
     260           0 :     } else fClusterWeightsNonBending = new TMatrixD(*(track.fClusterWeightsNonBending));
     261             :   }
     262             :   
     263             :   // copy cluster weights matrix if any
     264           0 :   if (track.fClusterWeightsBending) {
     265           0 :     if (fClusterWeightsBending) {
     266           0 :       fClusterWeightsBending->ResizeTo(*(track.fClusterWeightsBending));
     267           0 :       *fClusterWeightsBending = *(track.fClusterWeightsBending);
     268           0 :     } else fClusterWeightsBending = new TMatrixD(*(track.fClusterWeightsBending));
     269             :   }
     270             :   
     271             :   // copy track parameters at vertex if any
     272           0 :   if (track.fTrackParamAtVertex) {
     273           0 :     if (fTrackParamAtVertex) *fTrackParamAtVertex = *(track.fTrackParamAtVertex);
     274           0 :     else fTrackParamAtVertex = new AliMUONTrackParam(*(track.fTrackParamAtVertex));
     275             :   }
     276             :   
     277           0 :   fFitWithVertex      =  track.fFitWithVertex;
     278           0 :   fVertexErrXY2[0]    =  track.fVertexErrXY2[0];
     279           0 :   fVertexErrXY2[1]    =  track.fVertexErrXY2[1];
     280           0 :   fFitWithMCS         =  track.fFitWithMCS;
     281           0 :   fGlobalChi2         =  track.fGlobalChi2;
     282           0 :   fImproved           =  track.fImproved;
     283           0 :   fMatchTrigger       =  track.fMatchTrigger;
     284           0 :   fChi2MatchTrigger   =  track.fChi2MatchTrigger;
     285           0 :   fTrackID            =  track.fTrackID; 
     286           0 :   fHitsPatternInTrigCh = track.fHitsPatternInTrigCh;
     287           0 :   fHitsPatternInTrigChTrk = track.fHitsPatternInTrigChTrk;
     288           0 :   fLocalTrigger        = track.fLocalTrigger;
     289           0 :   fConnected          =  track.fConnected;
     290             : 
     291           0 :   return *this;
     292           0 : }
     293             : 
     294             :   //__________________________________________________________________________
     295             : AliMUONTrack::~AliMUONTrack()
     296         740 : {
     297             :   /// Destructor
     298         242 :   delete fTrackParamAtCluster;
     299         124 :   delete fClusterWeightsNonBending;
     300         124 :   delete fClusterWeightsBending;
     301         124 :   delete fTrackParamAtVertex;
     302         370 : }
     303             : 
     304             :   //__________________________________________________________________________
     305             : void AliMUONTrack::Clear(Option_t* /*opt*/)
     306             : {
     307             :   /// Clear arrays
     308         112 :   delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
     309          56 :   delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
     310          56 :   delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
     311          56 :   delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
     312          28 : }
     313             : 
     314             :   //__________________________________________________________________________
     315             : void AliMUONTrack::Reset()
     316             : {
     317             :   /// Reset to default values
     318           0 :   SetUniqueID(0);
     319           0 :   fFitWithVertex = kFALSE;
     320           0 :   fVertexErrXY2[0] = 0.;
     321           0 :   fVertexErrXY2[1] = 0.;
     322           0 :   fFitWithMCS = kFALSE;
     323           0 :   fGlobalChi2 = -1.;
     324           0 :   fImproved = kFALSE;
     325           0 :   fMatchTrigger = -1;
     326           0 :   fChi2MatchTrigger = 0.;
     327           0 :   fTrackID = -1;
     328           0 :   fHitsPatternInTrigCh = 0;
     329           0 :   fHitsPatternInTrigChTrk = 0;
     330           0 :   fLocalTrigger = 0;
     331           0 :   fConnected = kFALSE;
     332           0 :   delete fTrackParamAtCluster; fTrackParamAtCluster = 0x0;
     333           0 :   delete fClusterWeightsNonBending; fClusterWeightsNonBending = 0x0;
     334           0 :   delete fClusterWeightsBending; fClusterWeightsBending = 0x0;
     335           0 :   delete fTrackParamAtVertex; fTrackParamAtVertex = 0x0;
     336           0 : }
     337             : 
     338             :   //__________________________________________________________________________
     339             : TObjArray* AliMUONTrack::GetTrackParamAtCluster() const
     340             : {
     341             :   /// return array of track parameters at cluster (create it if needed)
     342        2836 :   if (!fTrackParamAtCluster) {
     343           0 :     fTrackParamAtCluster = new TObjArray(20);
     344           0 :     fTrackParamAtCluster->SetOwner(kTRUE);
     345           0 :   }
     346        1418 :   return fTrackParamAtCluster;
     347           0 : }
     348             : 
     349             :   //__________________________________________________________________________
     350             : void AliMUONTrack::AddTrackParamAtCluster(const AliMUONTrackParam &trackParam, AliMUONVCluster &cluster, Bool_t copy)
     351             : {
     352             :   /// Copy given track parameters into a new TrackParamAtCluster
     353             :   /// Link parameters with the associated cluster
     354             :   /// If copy=kTRUE: the cluster is copied then passed the trackParam which become its owner 
     355             :   ///     otherwise: make sure to do not delete the cluster until it is used by the track
     356             :   
     357             :   // check chamber ID of the associated cluster
     358         524 :   if (cluster.GetChamberId() < 0 || cluster.GetChamberId() > AliMUONConstants::NTrackingCh()) {
     359           0 :     AliError(Form("Chamber ID of the associated cluster is not valid (ChamberId=%d)",cluster.GetChamberId()));
     360           0 :     return;
     361             :   }
     362             :   
     363             :   // check whether track parameters are given at the correct cluster z position
     364         262 :   if (TMath::Abs(cluster.GetZ() - trackParam.GetZ())>1.e-5) {   // AU
     365           0 :     AliError("track parameters are given at a different z position than the one of the associated cluster");
     366           0 :     return;
     367             :   }
     368             :   
     369             :   // add parameters to the array of track parameters
     370         262 :   if (!fTrackParamAtCluster) {
     371           0 :     fTrackParamAtCluster = new TObjArray(20);
     372           0 :     fTrackParamAtCluster->SetOwner(kTRUE);
     373           0 :   }
     374         262 :   AliMUONTrackParam* trackParamAtCluster = new AliMUONTrackParam(trackParam);
     375         262 :   fTrackParamAtCluster->AddLast(trackParamAtCluster);
     376             :   
     377             :   // link parameters with the associated cluster or its copy
     378         262 :   if (copy) {
     379           0 :     AliMUONVCluster *clusterCopy = static_cast<AliMUONVCluster*>(cluster.Clone());
     380           0 :     trackParamAtCluster->SetClusterPtr(clusterCopy, kTRUE);
     381         262 :   } else trackParamAtCluster->SetClusterPtr(&cluster);
     382             :   
     383             :   // sort the array of track parameters
     384         262 :   fTrackParamAtCluster->Sort();
     385         524 : }
     386             : 
     387             :   //__________________________________________________________________________
     388             : void AliMUONTrack::RemoveTrackParamAtCluster(AliMUONTrackParam *trackParam)
     389             : {
     390             :   /// Remove trackParam from the array of TrackParamAtCluster and delete it since the array is owner
     391             :   
     392           0 :   if (fTrackParamAtCluster) {
     393             :     
     394           0 :     AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->Remove(trackParam));
     395             :     
     396           0 :     if (trackParamAtCluster) {
     397             :       
     398             :       // clean memory
     399           0 :       delete trackParamAtCluster;
     400             :       
     401             :       // remove hole
     402           0 :       fTrackParamAtCluster->Compress();
     403             :       
     404           0 :     } else AliWarning("object to remove does not exist in array fTrackParamAtCluster");
     405             :     
     406           0 :   } else AliWarning("array fTrackParamAtCluster does not exist");
     407             :   
     408           0 : }
     409             : 
     410             :   //__________________________________________________________________________
     411             : Bool_t AliMUONTrack::UpdateTrackParamAtCluster()
     412             : {
     413             :   /// Update track parameters at each attached cluster
     414             :   /// Return kFALSE in case of failure (i.e. extrapolation problem)
     415             :   
     416           0 :   Int_t nClusters = GetNClusters();
     417           0 :   if (nClusters == 0) {
     418           0 :     AliWarning("no cluster attached to the track");
     419           0 :     return kFALSE;
     420             :   }
     421             :   
     422             :   Bool_t extrapStatus = kTRUE;
     423           0 :   AliMUONTrackParam* startingTrackParam = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(0));
     424             :   
     425           0 :   for (Int_t i = 1; i < nClusters; i++) {
     426           0 :     AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(i));
     427             :     
     428             :     // reset track parameters and their covariances
     429           0 :     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
     430           0 :     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
     431             :     
     432             :     // extrapolation to the given z
     433           0 :     if (!AliMUONTrackExtrap::ExtrapToZ(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ())) extrapStatus = kFALSE;
     434             :     
     435             :     // prepare next step
     436             :     startingTrackParam = trackParamAtCluster;
     437             :   }
     438             : 
     439             :   // set global chi2 to max value in case of problem during track extrapolation
     440           0 :   if (!extrapStatus) SetGlobalChi2(2.*MaxChi2());
     441             :   return extrapStatus;
     442             :   
     443           0 : }
     444             : 
     445             :   //__________________________________________________________________________
     446             : Bool_t AliMUONTrack::UpdateCovTrackParamAtCluster()
     447             : {
     448             :   /// Update track parameters and their covariances at each attached cluster
     449             :   /// Include effects of multiple scattering in chambers
     450             :   /// Return kFALSE in case of failure (i.e. extrapolation problem)
     451             :   
     452           0 :   Int_t nClusters = GetNClusters();
     453           0 :   if (nClusters == 0) {
     454           0 :     AliWarning("no cluster attached to the track");
     455           0 :     return kFALSE;
     456             :   }
     457             :   
     458             :   Bool_t extrapStatus = kTRUE;
     459           0 :   AliMUONTrackParam* startingTrackParam = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(0));
     460           0 :   Int_t expectedChamber = startingTrackParam->GetClusterPtr()->GetChamberId() + 1;
     461             :   Int_t currentChamber;
     462             :   
     463           0 :   for (Int_t i = 1; i < nClusters; i++) {
     464           0 :     AliMUONTrackParam* trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(i));
     465             :     
     466             :     // reset track parameters and their covariances
     467           0 :     trackParamAtCluster->SetParameters(startingTrackParam->GetParameters());
     468           0 :     trackParamAtCluster->SetZ(startingTrackParam->GetZ());
     469           0 :     trackParamAtCluster->SetCovariances(startingTrackParam->GetCovariances());
     470             :     
     471             :     // add MCS effect
     472           0 :     AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(expectedChamber-1),-1.);
     473             :     
     474             :     // add MCS in missing chambers if any
     475           0 :     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
     476           0 :     while (currentChamber > expectedChamber) {
     477             :       // extrapolation to the missing chamber
     478           0 :       if (!AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, AliMUONConstants::DefaultChamberZ(expectedChamber))) extrapStatus = kFALSE;
     479             :       // add MCS effect
     480           0 :       AliMUONTrackExtrap::AddMCSEffect(trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(expectedChamber),-1.);
     481           0 :       expectedChamber++;
     482             :     }
     483             :     
     484             :     // extrapolation to the z of the current cluster
     485           0 :     if (!AliMUONTrackExtrap::ExtrapToZCov(trackParamAtCluster, trackParamAtCluster->GetClusterPtr()->GetZ())) extrapStatus = kFALSE;
     486             :     
     487             :     // prepare next step
     488           0 :     expectedChamber = currentChamber + 1;
     489             :     startingTrackParam = trackParamAtCluster;
     490             :   }
     491             :   
     492             :   // set global chi2 to max value in case of problem during track extrapolation
     493           0 :   if (!extrapStatus) SetGlobalChi2(2.*MaxChi2());
     494             :   return extrapStatus;
     495             :   
     496           0 : }
     497             : 
     498             :   //__________________________________________________________________________
     499             : Bool_t AliMUONTrack::IsValid(UInt_t requestedStationMask, Bool_t request2ChInSameSt45)
     500             : {
     501             :   /// check the validity of the current track:
     502             :   /// at least one cluster per requested station
     503             :   /// and at least 2 chambers in stations 4 & 5 that contain cluster(s)
     504             :   /// + if request2ChInSameSt45 = kTRUE: 2 chambers hit in the same station (4 or 5)
     505             :   
     506           0 :   Int_t nClusters = GetNClusters();
     507             :   AliMUONTrackParam *trackParam;
     508             :   Int_t currentCh, currentSt, previousCh = -1, nChHitInSt4 = 0, nChHitInSt5 = 0;
     509             :   UInt_t presentStationMask(0);
     510             :   
     511             :   // first loop over clusters
     512           0 :   for (Int_t i = 0; i < nClusters; i++) {
     513           0 :     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
     514             :     
     515           0 :     currentCh = trackParam->GetClusterPtr()->GetChamberId();
     516           0 :     currentSt = currentCh/2;
     517             :     
     518             :     // build present station mask
     519           0 :     presentStationMask |= ( 1 << currentSt );
     520             :     
     521             :     // count the number of chambers hit in station 4 that contain cluster(s)
     522           0 :     if (currentSt == 3 && currentCh != previousCh) {
     523           0 :       nChHitInSt4++;
     524             :       previousCh = currentCh;
     525           0 :     }
     526             :     
     527             :     // count the number of chambers hit in station 5 that contain cluster(s)
     528           0 :     if (currentSt == 4 && currentCh != previousCh) {
     529           0 :       nChHitInSt5++;
     530             :       previousCh = currentCh;
     531           0 :     }
     532             :     
     533             :   }
     534             :   
     535             :   // at least one cluster per requested station
     536           0 :   if ((requestedStationMask & presentStationMask) != requestedStationMask) return kFALSE;
     537             :   
     538             :   // 2 chambers hit in the same station (4 or 5)
     539           0 :   if (request2ChInSameSt45) return (nChHitInSt4 == 2 || nChHitInSt5 == 2);
     540             :   // or 2 chambers hit in station 4 & 5 together
     541           0 :   else return (nChHitInSt4+nChHitInSt5 >= 2);
     542             :   
     543           0 : }
     544             : 
     545             :   //__________________________________________________________________________
     546             : void AliMUONTrack::TagRemovableClusters(UInt_t requestedStationMask) {
     547             :   /// Identify clusters that can be removed from the track,
     548             :   /// with the only requirements to have at least 1 cluster per requested station
     549             :   /// and at least 2 chambers over 4 in stations 4 & 5 that contain cluster(s)
     550             :   
     551          36 :   Int_t nClusters = GetNClusters();
     552             :   AliMUONTrackParam *trackParam, *nextTrackParam;
     553             :   Int_t currentCh, nextCh, currentSt, nextSt, previousCh = -1, nChHitInSt45 = 0;
     554             :   
     555             :   // first loop over clusters
     556         396 :   for (Int_t i = 0; i < nClusters; i++) {
     557         180 :     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
     558             :     
     559         180 :     currentCh = trackParam->GetClusterPtr()->GetChamberId();
     560         180 :     currentSt = currentCh/2;
     561             :     
     562             :     // reset flags to kFALSE for all clusters in required station
     563         360 :     if ((1 << currentSt) & requestedStationMask) trackParam->SetRemovable(kFALSE);
     564           0 :     else trackParam->SetRemovable(kTRUE);
     565             :     
     566             :     // count the number of chambers in station 4 & 5 that contain cluster(s)
     567         254 :     if (currentCh > 5 && currentCh != previousCh) {
     568          72 :       nChHitInSt45++;
     569             :       previousCh = currentCh;
     570          72 :     }
     571             :     
     572             :   }
     573             :   
     574             :   // second loop over clusters
     575         216 :   for (Int_t i = 0; i < nClusters; i++) {
     576          90 :     trackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i);
     577             :     
     578          90 :     currentCh = trackParam->GetClusterPtr()->GetChamberId();
     579          90 :     currentSt = currentCh/2;
     580             :     
     581             :     // make sure they are more than 2 clusters in 2 different chambers of stations 4 & 5
     582             :     // but 2 clusters in he same chamber will still be flagged as removable
     583          90 :     if (nChHitInSt45 < 3 && currentSt > 2) {
     584             :       
     585           0 :       if (i == nClusters-1) {
     586             :         
     587           0 :         trackParam->SetRemovable(kFALSE);
     588             :       
     589           0 :       } else {
     590             :         
     591           0 :         nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(i+1);
     592           0 :         nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
     593             :         
     594             :         // set clusters in the same chamber as being removable
     595           0 :         if (nextCh == currentCh) {
     596           0 :           trackParam->SetRemovable(kTRUE);
     597           0 :           nextTrackParam->SetRemovable(kTRUE);
     598             :           i++; // skip cluster already checked
     599           0 :         } else {
     600           0 :           trackParam->SetRemovable(kFALSE);
     601             :         }
     602             :         
     603             :       }
     604             :       
     605             :     } else {
     606             :       
     607             :       // skip clusters already flag as removable
     608          90 :       if (trackParam->IsRemovable()) continue;
     609             :       
     610             :       // loop over next track parameters
     611        1084 :       for (Int_t j = i+1; j < nClusters; j++) {
     612         452 :         nextTrackParam = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(j);
     613             :         
     614         452 :         nextCh = nextTrackParam->GetClusterPtr()->GetChamberId();
     615         452 :         nextSt = nextCh/2;
     616             :         
     617             :         // set clusters in the same station as being removable
     618         452 :         if (nextSt == currentSt) {
     619          90 :           trackParam->SetRemovable(kTRUE);
     620          90 :           nextTrackParam->SetRemovable(kTRUE);
     621          90 :           i++; // skip cluster already checked
     622          90 :         }
     623             :         
     624             :       }
     625             :       
     626             :     }
     627             :       
     628             :   }
     629             :     
     630          18 : }
     631             : 
     632             :   //__________________________________________________________________________
     633             : Bool_t AliMUONTrack::ComputeLocalChi2(Bool_t accountForMCS)
     634             : {
     635             :   /// Compute each cluster contribution to the chi2 of the track
     636             :   /// accounting for multiple scattering or not according to the flag
     637             :   /// - Also recompute the weight matrices of the attached clusters if accountForMCS=kTRUE
     638             :   /// - Assume that track parameters at each cluster are corrects
     639             :   /// - Return kFALSE if computation failed
     640           0 :   AliDebug(1,"Enter ComputeLocalChi2");
     641             :   
     642           0 :   if (!fTrackParamAtCluster) {
     643           0 :     AliWarning("no cluster attached to this track");
     644           0 :     return kFALSE;
     645             :   }
     646             :   
     647           0 :   if (accountForMCS) { // Compute local chi2 taking into account multiple scattering effects
     648             :       
     649             :     // Compute MCS covariance matrix only once
     650           0 :     Int_t nClusters = GetNClusters();
     651           0 :     TMatrixD mcsCovariances(nClusters,nClusters);
     652           0 :     ComputeMCSCovariances(mcsCovariances);
     653             :     
     654             :     // Make sure cluster weights are consistent with following calculations
     655           0 :     if (!ComputeClusterWeights(&mcsCovariances)) {
     656           0 :       AliWarning("cannot take into account the multiple scattering effects");
     657           0 :       return ComputeLocalChi2(kFALSE);
     658             :     }
     659             :     
     660             :     // Compute chi2 of the track
     661           0 :     Double_t globalChi2 = ComputeGlobalChi2(kTRUE);
     662           0 :     if (globalChi2 < 0.) return kFALSE;
     663             :     
     664             :     // Loop over removable clusters and compute their local chi2
     665             :     AliMUONTrackParam* trackParamAtCluster;
     666             :     AliMUONTrackParam* trackParamAtCluster1;
     667             :     AliMUONVCluster *cluster, *discardedCluster;
     668             :     Int_t iCluster1, iCluster2, iCurrentCluster1, iCurrentCluster2;
     669           0 :     TMatrixD clusterWeightsNB(nClusters-1,nClusters-1);
     670           0 :     TMatrixD clusterWeightsB(nClusters-1,nClusters-1);
     671           0 :     Double_t *dX = new Double_t[nClusters-1];
     672           0 :     Double_t *dY = new Double_t[nClusters-1];
     673             :     Double_t globalChi2b;
     674           0 :     for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) { 
     675           0 :       trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(iCluster));
     676             :       
     677           0 :       discardedCluster = trackParamAtCluster->GetClusterPtr();
     678             :       
     679             :       // Recompute cluster weights without the current cluster
     680           0 :       if (!ComputeClusterWeights(clusterWeightsNB, clusterWeightsB, &mcsCovariances, discardedCluster)) {
     681           0 :         AliWarning("cannot take into account the multiple scattering effects");
     682           0 :         delete [] dX;
     683           0 :         delete [] dY;
     684           0 :         return ComputeLocalChi2(kFALSE);
     685             :       }
     686             :       
     687             :       // Compute track chi2 without the current cluster
     688             :       globalChi2b = 0.;
     689             :       iCurrentCluster1 = 0;
     690           0 :       for (iCluster1 = 0; iCluster1 < nClusters ; iCluster1++) { 
     691           0 :         trackParamAtCluster1 = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
     692           0 :         cluster = trackParamAtCluster1->GetClusterPtr();
     693             :         
     694           0 :         if (cluster == discardedCluster) continue;
     695             :         
     696             :         // Compute and save residuals
     697           0 :         dX[iCurrentCluster1] = cluster->GetX() - trackParamAtCluster1->GetNonBendingCoor();
     698           0 :         dY[iCurrentCluster1] = cluster->GetY() - trackParamAtCluster1->GetBendingCoor();
     699             :         
     700             :         iCurrentCluster2 = 0;
     701           0 :         for (iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
     702           0 :           cluster = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
     703             :           
     704           0 :           if (cluster == discardedCluster) continue;
     705             :           
     706             :           // Add contribution from covariances
     707           0 :           globalChi2b += (clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) +
     708           0 :                           clusterWeightsNB(iCurrentCluster2, iCurrentCluster1)) * dX[iCurrentCluster1] * dX[iCurrentCluster2] +
     709           0 :                          (clusterWeightsB(iCurrentCluster1, iCurrentCluster2) +
     710           0 :                           clusterWeightsB(iCurrentCluster2, iCurrentCluster1)) * dY[iCurrentCluster1] * dY[iCurrentCluster2];
     711             :           
     712           0 :           iCurrentCluster2++;
     713           0 :         }
     714             :         
     715             :         // Add contribution from variances
     716           0 :         globalChi2b += clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) * dX[iCurrentCluster1] * dX[iCurrentCluster1] +
     717           0 :                        clusterWeightsB(iCurrentCluster1, iCurrentCluster1) * dY[iCurrentCluster1] * dY[iCurrentCluster1];
     718             :         
     719           0 :         iCurrentCluster1++;
     720           0 :       }
     721             : 
     722             :       // Set local chi2
     723           0 :       trackParamAtCluster->SetLocalChi2(globalChi2 - globalChi2b);
     724             :     }
     725             :     
     726           0 :     delete [] dX;
     727           0 :     delete [] dY;
     728             :     
     729           0 :   } else { // without multiple scattering effects
     730             :     
     731           0 :     Int_t nClusters = GetNClusters();
     732             :     AliMUONTrackParam* trackParamAtCluster;
     733             :     AliMUONVCluster *discardedCluster;
     734             :     Double_t dX, dY;
     735           0 :     for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) { 
     736           0 :       trackParamAtCluster = static_cast<AliMUONTrackParam*>(fTrackParamAtCluster->UncheckedAt(iCluster));
     737             :       
     738           0 :       discardedCluster = trackParamAtCluster->GetClusterPtr();
     739             :       
     740             :       // Compute residuals
     741           0 :       dX = discardedCluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
     742           0 :       dY = discardedCluster->GetY() - trackParamAtCluster->GetBendingCoor();
     743             :       
     744             :       // Set local chi2
     745           0 :       trackParamAtCluster->SetLocalChi2(dX * dX / discardedCluster->GetErrX2() + dY * dY / discardedCluster->GetErrY2());
     746             :     }
     747             :   
     748             :   }
     749             :   
     750           0 :   return kTRUE;
     751             :   
     752           0 : }
     753             : 
     754             :   //__________________________________________________________________________
     755             : Double_t AliMUONTrack::ComputeGlobalChi2(Bool_t accountForMCS)
     756             : {
     757             :   /// Compute the chi2 of the track accounting for multiple scattering or not according to the flag
     758             :   /// - Assume that track parameters at each cluster are corrects
     759             :   /// - Assume the cluster weights matrices are corrects
     760             :   /// - Return a value of chi2 higher than the maximum allowed if computation failed
     761           0 :   AliDebug(1,"Enter ComputeGlobalChi2");
     762             :   
     763           0 :   if (!fTrackParamAtCluster) {
     764           0 :     AliWarning("no cluster attached to this track");
     765           0 :     return 2.*MaxChi2();
     766             :   }
     767             :   
     768             :   Double_t chi2 = 0.;
     769             :   
     770           0 :   if (accountForMCS) {
     771             :     
     772             :     // Check the weight matrices. If weight matrices are not available compute chi2 without MCS
     773           0 :     if (!fClusterWeightsNonBending || !fClusterWeightsBending) {
     774           0 :       AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
     775           0 :       return ComputeGlobalChi2(kFALSE);
     776             :     }
     777           0 :     Int_t nClusters = GetNClusters();
     778           0 :     if (fClusterWeightsNonBending->GetNrows() != nClusters || fClusterWeightsBending->GetNcols() != nClusters) {
     779           0 :       AliWarning("cluster weights including multiple scattering effects are not available\n\t\t --> compute chi2 WITHOUT multiple scattering");
     780           0 :       return ComputeGlobalChi2(kFALSE);
     781             :     }
     782             :     
     783             :     // Compute chi2
     784             :     AliMUONVCluster *cluster;
     785           0 :     Double_t *dX = new Double_t[nClusters];
     786           0 :     Double_t *dY = new Double_t[nClusters];
     787             :     AliMUONTrackParam* trackParamAtCluster;
     788           0 :     for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
     789           0 :       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1);
     790           0 :       cluster = trackParamAtCluster->GetClusterPtr();
     791           0 :       dX[iCluster1] = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
     792           0 :       dY[iCluster1] = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
     793           0 :       for (Int_t iCluster2 = 0; iCluster2 < iCluster1; iCluster2++) {
     794           0 :         chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster2) + (*fClusterWeightsNonBending)(iCluster2, iCluster1)) * dX[iCluster1] * dX[iCluster2] +
     795           0 :                 ((*fClusterWeightsBending)(iCluster1, iCluster2) + (*fClusterWeightsBending)(iCluster2, iCluster1)) * dY[iCluster1] * dY[iCluster2];
     796             :       }
     797           0 :       chi2 += ((*fClusterWeightsNonBending)(iCluster1, iCluster1) * dX[iCluster1] * dX[iCluster1]) +
     798           0 :               ((*fClusterWeightsBending)(iCluster1, iCluster1) * dY[iCluster1] * dY[iCluster1]);
     799             :     }
     800           0 :     delete [] dX;
     801           0 :     delete [] dY;
     802             :     
     803           0 :   } else {
     804             :     
     805             :     AliMUONVCluster *cluster;
     806             :     Double_t dX, dY;
     807             :     AliMUONTrackParam* trackParamAtCluster;
     808           0 :     Int_t nClusters = GetNClusters();
     809           0 :     for (Int_t iCluster = 0; iCluster < nClusters ; iCluster++) { 
     810           0 :       trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
     811           0 :       cluster = trackParamAtCluster->GetClusterPtr();
     812           0 :       dX = cluster->GetX() - trackParamAtCluster->GetNonBendingCoor();
     813           0 :       dY = cluster->GetY() - trackParamAtCluster->GetBendingCoor();
     814           0 :       chi2 += dX * dX / cluster->GetErrX2() + dY * dY / cluster->GetErrY2();
     815             :     }
     816             :     
     817             :   }
     818             :   
     819           0 :   return chi2;
     820             :   
     821           0 : }
     822             : 
     823             :   //__________________________________________________________________________
     824             : Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD* mcsCovariances)
     825             : {
     826             :   /// Compute the weight matrices of the attached clusters, in non bending and bending direction,
     827             :   /// accounting for multiple scattering correlations and cluster resolution
     828             :   /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
     829             :   /// - Assume that track parameters at each cluster are corrects
     830             :   /// - Return kFALSE if computation failed
     831           0 :   AliDebug(1,"Enter ComputeClusterWeights1");
     832             :   
     833           0 :   if (!fTrackParamAtCluster) {
     834           0 :     AliWarning("no cluster attached to this track");
     835           0 :     return kFALSE;
     836             :   }
     837             :   
     838             :   // Alocate memory
     839           0 :   Int_t nClusters = GetNClusters();
     840           0 :   if (!fClusterWeightsNonBending) fClusterWeightsNonBending = new TMatrixD(nClusters,nClusters);
     841           0 :   if (!fClusterWeightsBending) fClusterWeightsBending = new TMatrixD(nClusters,nClusters);
     842             :   
     843             :   // Compute weights matrices
     844           0 :   if (!ComputeClusterWeights(*fClusterWeightsNonBending, *fClusterWeightsBending, mcsCovariances)) return kFALSE;
     845             :   
     846           0 :   return kTRUE;
     847             :   
     848           0 : }
     849             : 
     850             :   //__________________________________________________________________________
     851             : Bool_t AliMUONTrack::ComputeClusterWeights(TMatrixD& clusterWeightsNB, TMatrixD& clusterWeightsB,
     852             :                                            TMatrixD* mcsCovariances, const AliMUONVCluster* discardedCluster) const
     853             : {
     854             :   /// Compute the weight matrices, in non bending and bending direction,
     855             :   /// of the other attached clusters assuming the discarded one does not exist
     856             :   /// accounting for multiple scattering correlations and cluster resolution
     857             :   /// - Use the provided MCS covariance matrix if any (otherwise build it temporarily)
     858             :   /// - Return kFALSE if computation failed
     859           0 :   AliDebug(1,"Enter ComputeClusterWeights2");
     860             :   
     861             :   // Check MCS covariance matrix and recompute it if need
     862           0 :   Int_t nClusters = GetNClusters();
     863             :   Bool_t deleteMCSCov = kFALSE;
     864           0 :   if (!mcsCovariances) {
     865           0 :     mcsCovariances = new TMatrixD(nClusters,nClusters);
     866             :     deleteMCSCov = kTRUE;
     867           0 :     ComputeMCSCovariances(*mcsCovariances);
     868           0 :   }
     869             :   
     870             :   // Resize the weights matrices; alocate memory
     871           0 :   if (discardedCluster) {
     872           0 :     clusterWeightsNB.ResizeTo(nClusters-1,nClusters-1);
     873           0 :     clusterWeightsB.ResizeTo(nClusters-1,nClusters-1);
     874           0 :   } else {
     875           0 :     clusterWeightsNB.ResizeTo(nClusters,nClusters);
     876           0 :     clusterWeightsB.ResizeTo(nClusters,nClusters);
     877             :   }
     878             :   
     879             :   // Define variables
     880             :   AliMUONVCluster *cluster1, *cluster2;
     881             :   Int_t iCurrentCluster1, iCurrentCluster2;
     882             :   
     883             :   // Compute the covariance matrices
     884             :   iCurrentCluster1 = 0;
     885           0 :   for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
     886           0 :     cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
     887             :     
     888           0 :     if (cluster1 == discardedCluster) continue;
     889             :     
     890             :     // Loop over next clusters
     891             :     iCurrentCluster2 = iCurrentCluster1;
     892           0 :     for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
     893           0 :       cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
     894             :       
     895           0 :       if (cluster2 == discardedCluster) continue;
     896             :       
     897             :       // Fill with MCS covariances
     898           0 :       clusterWeightsNB(iCurrentCluster1, iCurrentCluster2) = (*mcsCovariances)(iCluster1,iCluster2);
     899             :       
     900             :       // Equal contribution from multiple scattering in non bending and bending directions
     901           0 :       clusterWeightsB(iCurrentCluster1, iCurrentCluster2) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
     902             :       
     903             :       // Add contribution from cluster resolution to diagonal element and symmetrize the matrix
     904           0 :       if (iCurrentCluster1 == iCurrentCluster2) {
     905             :         
     906             :         // In non bending plane
     907           0 :         clusterWeightsNB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrX2();
     908             :         // In bending plane
     909           0 :         clusterWeightsB(iCurrentCluster1, iCurrentCluster1) += cluster1->GetErrY2();
     910             :         
     911           0 :       } else {
     912             :         
     913             :         // In non bending plane
     914           0 :         clusterWeightsNB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsNB(iCurrentCluster1, iCurrentCluster2);
     915             :         // In bending plane
     916           0 :         clusterWeightsB(iCurrentCluster2, iCurrentCluster1) = clusterWeightsB(iCurrentCluster1, iCurrentCluster2);
     917             :         
     918             :       }
     919             :       
     920           0 :       iCurrentCluster2++;
     921           0 :     }
     922             :     
     923           0 :     iCurrentCluster1++;
     924           0 :   }
     925             :     
     926             :   // Inversion of covariance matrices to get the weights
     927           0 :   if (clusterWeightsNB.Determinant() != 0 && clusterWeightsB.Determinant() != 0) {
     928           0 :     clusterWeightsNB.Invert();
     929           0 :     clusterWeightsB.Invert();
     930             :   } else {
     931           0 :     AliWarning(" Determinant = 0");
     932           0 :     clusterWeightsNB.ResizeTo(0,0);
     933           0 :     clusterWeightsB.ResizeTo(0,0);
     934           0 :     if(deleteMCSCov) delete mcsCovariances;
     935           0 :     return kFALSE;
     936             :   }
     937             :   
     938           0 :   if(deleteMCSCov) delete mcsCovariances;
     939             :   
     940           0 :   return kTRUE;
     941             :   
     942           0 : }
     943             : 
     944             :   //__________________________________________________________________________
     945             : void AliMUONTrack::ComputeMCSCovariances(TMatrixD& mcsCovariances) const
     946             : {
     947             :   /// Compute the multiple scattering covariance matrix
     948             :   /// (assume that track parameters at each cluster are corrects)
     949           0 :   AliDebug(1,"Enter ComputeMCSCovariances");
     950             :   
     951             :   // Reset the size of the covariance matrix if needed
     952           0 :   Int_t nClusters = GetNClusters();
     953           0 :   if (mcsCovariances.GetNrows() != nClusters) mcsCovariances.ResizeTo(nClusters,nClusters);
     954             :   
     955             :   // Define variables
     956           0 :   Int_t nChambers = AliMUONConstants::NTrackingCh();
     957             :   AliMUONTrackParam* trackParamAtCluster;
     958           0 :   AliMUONTrackParam extrapTrackParam;
     959             :   Int_t currentChamber = 0, expectedChamber = 0, size = 0;
     960           0 :   Double_t *mcsAngle2 = new Double_t[2*nChambers];
     961           0 :   Double_t *zMCS = new Double_t[2*nChambers];
     962           0 :   Int_t *indices = new Int_t[2*nClusters];
     963             :   
     964             :   // Compute multiple scattering dispersion angle at each chamber
     965             :   // and save the z position where it is calculated
     966           0 :   for (Int_t iCluster = 0; iCluster < nClusters; iCluster++) {
     967           0 :     trackParamAtCluster = (AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster);
     968             :     
     969             :     // look for missing chambers if any
     970           0 :     currentChamber = trackParamAtCluster->GetClusterPtr()->GetChamberId();
     971           0 :     while (currentChamber > expectedChamber) {
     972             :       
     973             :       // Save the z position where MCS dispersion is calculated
     974           0 :       zMCS[size] = AliMUONConstants::DefaultChamberZ(expectedChamber);
     975             :       
     976             :       // Do not take into account MCS in chambers prior the first cluster
     977           0 :       if (iCluster > 0) {
     978             :         
     979             :         // Get track parameters at missing chamber z
     980           0 :         extrapTrackParam = *trackParamAtCluster;
     981           0 :         AliMUONTrackExtrap::ExtrapToZ(&extrapTrackParam, zMCS[size]);
     982             :         
     983             :         // Save multiple scattering dispersion angle in missing chamber
     984           0 :         mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(extrapTrackParam,AliMUONConstants::ChamberThicknessInX0(expectedChamber),1.);
     985             :         
     986           0 :       } else mcsAngle2[size] = 0.;
     987             :       
     988           0 :       expectedChamber++;
     989           0 :       size++;
     990             :     }
     991             :     
     992             :     // Save z position where MCS dispersion is calculated
     993           0 :     zMCS[size] = trackParamAtCluster->GetZ();
     994             :     
     995             :     // Save multiple scattering dispersion angle in current chamber
     996           0 :     mcsAngle2[size] = AliMUONTrackExtrap::GetMCSAngle2(*trackParamAtCluster,AliMUONConstants::ChamberThicknessInX0(currentChamber),1.);
     997             :     
     998             :     // Save indice in zMCS array corresponding to the current cluster
     999           0 :     indices[iCluster] = size;
    1000             :     
    1001           0 :     expectedChamber = currentChamber + 1;
    1002           0 :     size++;
    1003             :   }
    1004             :   
    1005             :   // complete array of z if last cluster is on the last but one chamber
    1006           0 :   if (currentChamber != nChambers-1) zMCS[size++] = AliMUONConstants::DefaultChamberZ(nChambers-1);
    1007             :   
    1008             :   // Compute the covariance matrix
    1009           0 :   for (Int_t iCluster1 = 0; iCluster1 < nClusters; iCluster1++) { 
    1010             :     
    1011           0 :     for (Int_t iCluster2 = iCluster1; iCluster2 < nClusters; iCluster2++) {
    1012             :       
    1013             :       // Initialization to 0 (diagonal plus upper triangular part)
    1014           0 :       mcsCovariances(iCluster1,iCluster2) = 0.;
    1015             :       
    1016             :       // Compute contribution from multiple scattering in upstream chambers
    1017           0 :       for (Int_t k = 0; k < indices[iCluster1]; k++) {       
    1018           0 :         mcsCovariances(iCluster1,iCluster2) += (zMCS[indices[iCluster1]] - zMCS[k]) * (zMCS[indices[iCluster2]] - zMCS[k]) * mcsAngle2[k];
    1019             :       }
    1020             :       
    1021             :       // Symetrize the matrix
    1022           0 :       mcsCovariances(iCluster2,iCluster1) = mcsCovariances(iCluster1,iCluster2);
    1023             :     }
    1024             :     
    1025             :   }
    1026             :     
    1027           0 :   delete [] mcsAngle2;
    1028           0 :   delete [] zMCS;
    1029           0 :   delete [] indices;
    1030             :   
    1031           0 : }
    1032             : 
    1033             :   //__________________________________________________________________________
    1034             : Int_t AliMUONTrack::ClustersInCommon(AliMUONTrack* track, Int_t stMin, Int_t stMax) const
    1035             : {
    1036             :   /// Returns the number of clusters in common in stations [stMin, stMax]
    1037             :   /// between the current track ("this") and the track pointed to by "track".
    1038             :   
    1039         296 :   if (!track || !track->fTrackParamAtCluster || !this->fTrackParamAtCluster) return 0;
    1040             :   
    1041          74 :   Int_t chMin = 2 * stMin;
    1042          74 :   Int_t chMax = 2 * stMax + 1;
    1043             :   Int_t clustersInCommon = 0;
    1044             :   
    1045             :   // Loop over clusters of first track
    1046          74 :   Int_t nCl1 = this->GetNClusters();
    1047        1136 :   for(Int_t iCl1 = 0; iCl1 < nCl1; iCl1++) {
    1048         494 :     AliMUONVCluster* cl1 = ((AliMUONTrackParam*) this->fTrackParamAtCluster->UncheckedAt(iCl1))->GetClusterPtr();
    1049             :     
    1050         494 :     Int_t chCl1 = cl1->GetChamberId();
    1051        1072 :     if (chCl1 < chMin || chCl1 > chMax) continue;
    1052             :     
    1053             :     // Loop over clusters of second track
    1054         310 :     Int_t nCl2 = track->GetNClusters();
    1055        4332 :     for(Int_t iCl2 = 0; iCl2 < nCl2; iCl2++) {
    1056        1872 :       AliMUONVCluster* cl2 = ((AliMUONTrackParam*) track->fTrackParamAtCluster->UncheckedAt(iCl2))->GetClusterPtr();
    1057             :       
    1058        1872 :       Int_t chCl2 = cl2->GetChamberId();
    1059        4000 :       if (chCl2 < chMin || chCl2 > chMax) continue;
    1060             :       
    1061             :       // Increment "clustersInCommon" if both clusters have the same ID
    1062        1252 :       if (cl1->GetUniqueID() == cl2->GetUniqueID()) {
    1063         114 :         clustersInCommon++;
    1064         114 :         break;
    1065             :       }
    1066             :       
    1067        1138 :     }
    1068             :     
    1069         310 :   }
    1070             :   
    1071             :   return clustersInCommon;
    1072          74 : }
    1073             : 
    1074             :   //__________________________________________________________________________
    1075             : Int_t AliMUONTrack::GetNDF() const
    1076             : {
    1077             :   /// return the number of degrees of freedom
    1078             :   
    1079           0 :   Int_t ndf = 2 * GetNClusters() - 5;
    1080           0 :   return (ndf > 0) ? ndf : 0;
    1081             : }
    1082             : 
    1083             :   //__________________________________________________________________________
    1084             : Double_t AliMUONTrack::GetNormalizedChi2() const
    1085             : {
    1086             :   /// return the chi2 value divided by the number of degrees of freedom (or FLT_MAX if ndf <= 0)
    1087             :   
    1088           0 :   Double_t ndf = (Double_t) GetNDF();
    1089           0 :   return (ndf > 0.) ? fGlobalChi2 / ndf : 2.*MaxChi2();
    1090             : }
    1091             : 
    1092             :   //__________________________________________________________________________
    1093             : Int_t AliMUONTrack::FindCompatibleClusters(const AliMUONTrack &track, Double_t sigmaCut, Bool_t compatibleCluster[10]) const
    1094             : {
    1095             :   /// Try to match clusters from this track with clusters from the given track within the provided sigma cut:
    1096             :   /// - Fill the array compatibleCluster[iCh] with kTRUE if a compatible cluster has been found in chamber iCh.
    1097             :   /// - Return the number of clusters of "this" track matched with one cluster of the given track.
    1098             :   AliMUONVCluster *cluster1, *cluster2;
    1099             :   Double_t chi2, dX, dY;
    1100           0 :   Double_t chi2Max = sigmaCut * sigmaCut;
    1101             :   
    1102             :   // initialization
    1103             :   Int_t nMatchClusters = 0;
    1104           0 :   for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) compatibleCluster[ch] = kFALSE;
    1105             : 
    1106           0 :   if (!track.fTrackParamAtCluster || !this->fTrackParamAtCluster) return nMatchClusters;
    1107             :   
    1108             :   // Loop over clusters of first track
    1109           0 :   Int_t nCl1 = this->GetNClusters();
    1110           0 :   for(Int_t iCl1 = 0; iCl1 < nCl1; iCl1++) {
    1111           0 :     cluster1 = static_cast<AliMUONTrackParam*>(this->fTrackParamAtCluster->UncheckedAt(iCl1))->GetClusterPtr();
    1112             :     
    1113             :     // Loop over clusters of second track
    1114           0 :     Int_t nCl2 = track.GetNClusters();
    1115           0 :     for(Int_t iCl2 = 0; iCl2 < nCl2; iCl2++) {
    1116           0 :       cluster2 = static_cast<AliMUONTrackParam*>(track.fTrackParamAtCluster->UncheckedAt(iCl2))->GetClusterPtr();
    1117             :       
    1118             :       // check DE Id
    1119           0 :       if (cluster1->GetDetElemId() != cluster2->GetDetElemId()) continue;
    1120             :       
    1121             :       // check local chi2
    1122           0 :       dX = cluster1->GetX() - cluster2->GetX();
    1123           0 :       dY = cluster1->GetY() - cluster2->GetY();
    1124           0 :       chi2 = dX * dX / (cluster1->GetErrX2() + cluster2->GetErrX2()) + dY * dY / (cluster1->GetErrY2() + cluster2->GetErrY2());
    1125           0 :       if (chi2 > 2. * chi2Max) continue; // 2 because 2 quantities in chi2
    1126             :       
    1127           0 :       compatibleCluster[cluster1->GetChamberId()] = kTRUE;
    1128           0 :       nMatchClusters++;
    1129           0 :       break;
    1130             :     }
    1131             :     
    1132             :   }
    1133             :   
    1134             :   return nMatchClusters;
    1135           0 : }
    1136             : 
    1137             : //__________________________________________________________________________
    1138             : Bool_t AliMUONTrack::Match(AliMUONTrack &track, Double_t sigmaCut, Int_t &nMatchClusters) const
    1139             : {
    1140             :   /// Try to match this track with the given track. Matching conditions:
    1141             :   /// - more than 50% of clusters from this track matched with clusters from the given track
    1142             :   /// - at least 1 cluster matched before and 1 cluster matched after the dipole
    1143             :   
    1144           0 :   Bool_t compTrack[10];
    1145           0 :   nMatchClusters = FindCompatibleClusters(track, sigmaCut, compTrack);
    1146             :   
    1147           0 :   if ((compTrack[0] || compTrack[1] || compTrack[2] || compTrack[3]) && // at least 1 cluster matched in st 1 & 2
    1148           0 :       (compTrack[6] || compTrack[7] || compTrack[8] || compTrack[9]) && // at least 1 cluster matched in st 4 & 5
    1149           0 :       2 * nMatchClusters > GetNClusters()) return kTRUE;                // more than 50% of clusters matched
    1150           0 :   else return kFALSE;
    1151             :   
    1152           0 : }
    1153             : 
    1154             : //__________________________________________________________________________
    1155             : void AliMUONTrack::SetTrackParamAtVertex(const AliMUONTrackParam* trackParam)
    1156             : {
    1157             :   /// set track parameters at vertex
    1158           0 :   if (trackParam == 0x0) return;
    1159           0 :   if (fTrackParamAtVertex) *fTrackParamAtVertex = *trackParam;
    1160           0 :   else fTrackParamAtVertex = new AliMUONTrackParam(*trackParam);
    1161           0 : }
    1162             : 
    1163             : //__________________________________________________________________________
    1164             : void AliMUONTrack::RecursiveDump() const
    1165             : {
    1166             :   /// Recursive dump of AliMUONTrack, i.e. with dump of trackParamAtCluster and attached clusters
    1167             :   AliMUONTrackParam *trackParamAtCluster;
    1168             :   AliMUONVCluster *cluster;
    1169           0 :   cout << "Recursive dump of Track: " << this << endl;
    1170             :   // Track
    1171           0 :   this->Dump();
    1172           0 :   for (Int_t iCluster = 0; iCluster < GetNClusters(); iCluster++) {
    1173           0 :     trackParamAtCluster = (AliMUONTrackParam*) ((*fTrackParamAtCluster)[iCluster]);
    1174             :     // trackParamAtCluster
    1175           0 :     cout << "trackParamAtCluster: " << trackParamAtCluster << " (index: " << iCluster << ")" << endl;
    1176           0 :     trackParamAtCluster->Dump();
    1177           0 :     cluster = trackParamAtCluster->GetClusterPtr();
    1178             :     // cluster
    1179           0 :     cout << "cluster: " << cluster << endl;
    1180           0 :     cluster->Print();
    1181             :   }
    1182             :   return;
    1183           0 : }
    1184             :   
    1185             : //_____________________________________________-
    1186             : void AliMUONTrack::Print(Option_t*) const
    1187             : {
    1188             :   /// Printing Track information 
    1189             : 
    1190           0 :   streamsize curW = cout.width();
    1191           0 :   streamsize curPrecision = cout.precision();
    1192           0 :   cout << "<AliMUONTrack> No.Clusters=" << setw(2)   << GetNClusters() << 
    1193           0 :       ", Match2Trig=" << setw(1) << GetMatchTrigger()  << 
    1194           0 :       ", LoTrgNum=" << setw(3) << LoCircuit()  << 
    1195           0 :     ", Chi2-tracking-trigger=" << setw(8) << setprecision(5) <<  GetChi2MatchTrigger();
    1196           0 :   cout << Form(" HitTriggerPattern trig %x  track %x",fHitsPatternInTrigCh, fHitsPatternInTrigChTrk);
    1197           0 :   cout << Form(" MClabel=%d",fTrackID) << endl;
    1198           0 :   if (fTrackParamAtCluster) fTrackParamAtCluster->First()->Print("FULL");
    1199           0 :   cout.width(curW);
    1200           0 :   cout.precision(curPrecision);
    1201           0 : }
    1202             : 
    1203             : //__________________________________________________________________________
    1204             : void AliMUONTrack::SetLocalTrigger(Int_t loCirc, Int_t loStripX, Int_t loStripY, Int_t loDev, Int_t loLpt, Int_t loHpt, UChar_t respWithoutChamber)
    1205             : {
    1206             :   /// pack the local trigger information and store
    1207             : 
    1208          28 :   if (loCirc < 0) return;
    1209             : 
    1210          14 :   fLocalTrigger = 0;
    1211             :   fLocalTrigger += loCirc;
    1212          14 :   fLocalTrigger += loStripX << 8;
    1213          14 :   fLocalTrigger += loStripY << 13;
    1214          14 :   fLocalTrigger += loDev    << 17;
    1215          14 :   fLocalTrigger += loLpt    << 22;
    1216          14 :   fLocalTrigger += loHpt    << 24;
    1217          14 :   fLocalTrigger += respWithoutChamber << 26;
    1218             : 
    1219          28 : }
    1220             : 
    1221             : //__________________________________________________________________________
    1222             : void AliMUONTrack::FindMCLabel()
    1223             : {
    1224             :   /// Determine the MC label from the label of the attached clusters and fill fMCLabel data member:
    1225             :   /// More than 50% of clusters, including 1 before and 1 after the dipole, must share the same label
    1226             :   
    1227          32 :   Int_t nClusters = GetNClusters();
    1228          16 :   Int_t halfCluster = nClusters/2;
    1229             :   
    1230             :   // reset MC label
    1231          16 :   fTrackID = -1;
    1232             :   
    1233             :   // loop over first clusters (if nClusters left < (nClusters-halfCluster) the conditions cannot be fulfilled)
    1234          96 :   for (Int_t iCluster1 = 0; iCluster1 < nClusters-halfCluster; iCluster1++) {
    1235          48 :     AliMUONVCluster* cluster1 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster1))->GetClusterPtr();
    1236             :     
    1237             :     // if the first cluster is not on station 1 or 2 the conditions cannot be fulfilled
    1238          56 :     if (cluster1->GetChamberId() > 3) return;
    1239             :     
    1240          40 :     Int_t label1 = cluster1->GetMCLabel();
    1241          72 :     if (label1 < 0) continue;
    1242             :     
    1243             :     Int_t nIdenticalLabel = 1;
    1244             :     
    1245             :     // Loop over next clusters
    1246          96 :     for (Int_t iCluster2 = iCluster1+1; iCluster2 < nClusters; iCluster2++) {
    1247          48 :       AliMUONVCluster* cluster2 = ((AliMUONTrackParam*) fTrackParamAtCluster->UncheckedAt(iCluster2))->GetClusterPtr();
    1248             :       
    1249          48 :       if (cluster2->GetMCLabel() != label1) continue;
    1250             :       
    1251          48 :       nIdenticalLabel++;
    1252             :       
    1253             :       // stop as soon as conditions are fulfilled
    1254          64 :       if (nIdenticalLabel > halfCluster && cluster2->GetChamberId() > 5) {
    1255           8 :         fTrackID = label1;
    1256           8 :         return;
    1257             :       }
    1258             :       
    1259          40 :     }
    1260             :     
    1261           0 :   }
    1262             :   
    1263          16 : }
    1264             : 

Generated by: LCOV version 1.11